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)重复部分的封装