Mooc--五子棋(js)小结

1. canvas是块级元素吗??

 

2. css3 box-shadow属性

语法:box-shadow: h-shadow v-shadow blur spread color inset;

注释:box-shadow 向框添加一个或多个阴影。该属性是由逗号分隔的阴影列表,每个阴影由 2-4 个长度值、可选的颜色值以及可选的 inset 关键词来规定。省略长度的值是 0。

 
描述
h-shadow 必需;水平阴影的位置;允许负值。
v-shadow 必需;垂直阴影的位置;允许负值。
blur 可选;模糊距离。
spread 可选;阴影的尺寸。
color 可选;阴影的颜色。
inset 可选;将外部阴影(outset)改为内部阴影。

 

3.

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>五子棋</title>
    <link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<canvas id="chess" width="450px" height="450px"></canvas>
<script type="text/javascript" src="js/sc.js"></script>>
</body>
</html>

CSS

canvas{
    display: block;
    margin: 50px auto;
    box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #B9B9B9;
}

js部分:

1)双人轮流下棋(赢需要人为判断)

//定义二维数组存储棋盘上落子的情况
var chessBoard = [];
var me = true; //代表黑子

for(var i=0; i<15; i++){
	chessBoard[i] = [];
	for(var j=0; j<15; j++){
		chessBoard[i][j] = 0; //代表没有落子,空的
	}
}


var chess = document.getElementById('chess');
var context = chess.getContext('2d');

context.strokeStyle = "#BFBFBF";

var logo = new Image();
logo.src = "images/deer.png";
//图片加载完成后调用drawImage()
logo.onload = function() {
context.drawImage(logo, 0, 0, 450, 450);
drawChessBoard(); //保证棋盘在水印图片的上层
}

/*canvas为450px*450px,棋盘内边距留白15px,每行每列均为15条线,14个方格,每个方格30px*/
var drawChessBoard = function() {
	for(var i=0; i<15; i++){
		// 画横线
		context.moveTo(15 + i*30, 15);
		context.lineTo(15 + i*30, 435);
		context.stroke(); //用于描边
		// 画竖线
		context.moveTo(15, 15 + i*30);
		context.lineTo(435, 15 + i*30);
		context.stroke();
	}
}

//i,j代表棋子在棋盘的索引,而me(Boolean)表示走的是黑棋还是白棋
var oneStep = function(i, j, me) {
	context.beginPath();
	//可以画扇型,圆心,半径,扇型的起止弧度和终止弧度
	context.arc(15 + i*30, 15 + j*30, 13, 0, 2 * Math.PI);
	context.closePath();
	//6个参数
	var gradient = context.createRadialGradient(15 + i*30 + 2, 15 + j*30 - 2, 13, 15 + i*30 + 2, 15 + j*30 - 2, 0); //圆心偏移右上角
	if(me) {
	gradient.addColorStop(0, "#0A0A0A"); //0、1代表百分比
	gradient.addColorStop(1, "#636766")
} else{
	gradient.addColorStop(0, "#D1D1D1");
	gradient.addColorStop(1, "#F9F9F9")
}
	context.fillStyle = gradient;
	context.fill(); //用于填充
}

chess.onclick = function(e) {
	//相对与canvas左上角计算的坐标
	var x = e.offsetX;
	var y = e.offsetY;
	var i = Math.floor(x / 30);
	var j = Math.floor(y / 30); 
	if(chessBoard[i][j] == 0) {
		oneStep(i, j, me)
		if(me) {
			chessBoard[i][j] = 1;
		} else {
			chessBoard[i][j] = 2;
		}
		me = !me;
	}
	
}

2)人机模式

window.onload=function(){
var me=true;
var over=false;//表示棋局有没有结束

//定义二维数组存储棋盘上落子的情况
var chessBord=[];
//初始化chessBord数组
for(var i=0; i<15;i++){
chessBord[i]=[];
for(var j=0;j<15;j++){
chessBord[i][j]=0; //代表没有落子,空的
}
}

//赢法数组(三维数组)
var wins=[];
//赢法的统计数组(一维数组)
var myWin=[];
var computerWin=[];
//初始化3维赢法数组
for(var i=0; i<15; i++){
wins[i]=[];
for(var j=0; j<15; j++){
wins[i][j]=[];
}
}

var count=0;//定义赢法种类的索引
//所有横线的赢法
 for(var i=0;i<15;i++){
  for(var j=0;j<11;j++){
      //wins[0][0][0] = true;
      //wins[0][1][0] = true;
      //wins[0][2][0] = true;
      //wins[0][3][0] = true;
      //wins[0][4][0] = true;

      //wins[0][1][1] = true;
      //wins[0][2][1] = true;
      //wins[0][3][1] = true;
      //wins[0][4][1] = true;
      //wins[0][5][1] = true;
  for(var k=0;k<5;k++){
  wins[i][j+k][count]=true;
  }
  count++;
  }
 }
 //所有竖线的赢法
 for(var i=0;i<15;i++){
  for(var j=0;j<11;j++){
  for(var k=0;k<5;k++){
  wins[j+k][i][count]=true;
  }
  count++;
  }
 }
//所有斜线的赢法
 for(var i=0;i<11;i++){
  for(var j=0;j<11;j++){
  for(var k=0;k<5;k++){
  wins[i+k][j+k][count]=true;
  }
  count++;
  }
 }
//所有反斜线的赢法
 for(var i=0;i<11;i++){
  for(var j=14;j>3;j--){
  for(var k=0;k<5;k++){
  wins[i+k][j-k][count]=true;
  }
  count++;
  }
 }

 console.log(count);
//初始化赢法的统计数组
 for(var i=0; i<count; i++){
  myWin[i]=0;
  computerWin[i]=0;
  }
   
/**/
var chess=document.getElementById('chess');
var context=chess.getContext('2d');

context.strokeStyle="#BFBFBF";
var logo=new Image();
logo.src="images/deer.png";
 /**/
  logo.onload=function(){
context.drawImage(logo,0,0,450,450);
      drawChessBoard();
/**/
 
   }
 /**/
  function drawChessBoard (){
    for(var i=0; i<15; i++){
context.moveTo(15+i*30,15);
    context.lineTo(15+i*30,430);
    context.stroke();
    context.moveTo(15,15+i*30);
    context.lineTo(435,15+i*30);
    context.stroke();
    } 
  }  

/**//*定义onesStep函数来绘制棋子*/
 var oneStep=function(i,j,me){
    context.beginPath();
//可以画扇型,圆心,半径,扇型的起止弧度和终止弧度
    context.arc(15+i*30,15+j*30,13,0,2*Math.PI);
    context.closePath();

 var gradient=context.createRadialGradient(15+i*30+2,15+j*30-2,13,15+i*30+2,15+j*30-2,0);
if(me){
gradient.addColorStop(0,"#0A0A0A");
gradient.addColorStop(1,"#636766");
  }
  else{
  gradient.addColorStop(0,"#D1D1D1");
   gradient.addColorStop(1,"#F9F9F9");
  }
context.fillStyle=gradient;
context.fill();//填充
  }  
 
 /**/ 
 chess.onclick=function(e){
   //棋局结束
   if(over){
    return;
   }
   if(!me){
    return;
   }
   var x=e.offsetX;
   var y=e.offsetY;
   var i=Math.floor(x/30);
   var j=Math.floor(y/30);
   if(chessBord[i][j]==0){
      oneStep(i,j,me);
      chessBord[i][j]=1;
       for(var k=0;k<count;k++){
         if(wins[i][j][k]){
          myWin[k]++; //向着胜利前进一步
          computerWin[k]=6; //黑棋落子,白棋在k种赢法下不成立,异常数据,不可能大于5
           if(myWin[k]==5){
            window.alert("你赢了");
            over=true;
           }
         }
       }
       if(!over){
         me=!me;
         computerAI();
       }
    }
  }

  //定义computerAI函数
 var computerAI=function(){
    var myScore=[]; //计算我方得分(二维数组)
    var computerScore=[]; //计算计算机得分(二维数组)
    var max=0; //保存最高分数
    var u=0, v=0; //保存最高分数的点的坐标

    for(var i=0;i<15;i++){
    myScore[i]=[];
    computerScore[i]=[];
    for(var j=0;j<15;j++){
    myScore[i][j]=0;
    computerScore[i][j]=0;
    }
    }

    for(var i=0;i<15;i++){
    for(var j=0; j<15;j++){
    if(chessBord[i][j]==0){
        //如果i,j出现在多种赢法上,会进行累加
    for(var k=0; k<count;k++){
    if(wins[i][j][k]){
    if(myWin[k]==1){
    myScore[i][j]+=200;
    } else if(myWin[k]==2){
    myScore[i][j]+=400;
    } else if(myWin[k]==3){
    myScore[i][j]+=2000;
    } else if(myWin[k]==4){
    myScore[i][j]+=10000;
    }
    if(computerWin[k]==1){
    computerScore[i][j]+=200;
    } else if(computerWin[k]==2){
    computerScore[i][j]+=400;
    } else if(computerWin[k]==3){
    computerScore[i][j]+=2000;
    } else if(computerWin[k]==4){
    computerScore[i][j]+=10000;
    }
    }
    }
    if(myScore[i][j]>max){
    max=myScore[i][j];
    u=i;
    v=j;
    } else if(myScore[i][j]==max){
    if(computerScore[i][j]>computerScore[u][v]){
    u=i;
    v=j;
    }
    }
    if(computerScore[i][j]>max){
    max=computerScore[i][j];
    u=i;
    v=j;
    } else if(computerScore[i][j]==max){
    if(myScore[i][j]>myScore[u][v]){
    u=i;
    v=j;
    }
    }
    }
    }
    }
    oneStep(u,v,false);
    chessBord[u][v]=2;
    //
     for(var k=0;k<count;k++){
         if(wins[u][v][k]){
          computerWin[k]++;
          myWin[k]=6;
           if(computerWin[k]==5){
               setTimeout(function(){
            window.alert("计算机赢了");},0.5);
            over=true;
           }
         }
       }
       if(!over){
         me=!me;
          
       }
  }
}

注:此AI算法侧重于防守;

几个小问题:

1)Chrome浏览器中,在落下第五个棋子(赢),会先弹出‘赢了’的对话框,用setTimeout改进;

 

后续改进:

1)添加悔棋功能 

如果是要悔棋的功能的话可以用一个变量存储上次落子坐标,重新绘制背景以及坐标位置的十字;

2)添加重置功能

3)落子得分的计算

4)重复部分的封装 

  

 

 

 

  

 

posted @ 2018-10-15 00:47  Amy_World  阅读(355)  评论(0编辑  收藏  举报