Canvas制作五子棋人机大战
Posted 代码君肿了么
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Canvas制作五子棋人机大战相关的知识,希望对你有一定的参考价值。
点击文末‘阅读原文’,预览效果!
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>人机大战之五子棋</title>
</head>
<body>
<style>
*{margin: 0;padding:0}
.chess_game{margin: 16px auto;
width: 1200px;
}
canvas:nth-child(1){margin: 0 auto;
display: block;
float: left;
top: 20px;
cursor: pointer;
border-radius: 5px;
box-shadow: 3px 3px 5px gray;
}
canvas:nth-child(2){position: relative;left: 0px;top: -600px;cursor: pointer;}
</style>
<div class="chess_game">
<canvas id="chess" width="1200px" height="600px"></canvas>
<canvas id="animate" width="1200px" height="600px"></canvas>
</div>
<script>
var chess=document.getElementById("chess");
var c=chess.getContext("2d"); //获取上下文
var animate=document.getElementById("animate");
var a=animate.getContext("2d"); //获取上下文
var backimage=new Image(); //创建背景
// backimage.src="../images/board.jpg";
backimage.src="img/wuziqi.jpg";
backimage.onload=function(){ //加载背景
c.drawImage(backimage,0,0,1200,600); //绘制背景
drawChessBoard(); //绘制棋盘
drawTaiJi(c,200,300,150,"#000000",Math.PI); //绘制太极
drawTaiJi(c,1000,300,150,"#ffffff",0);
drawChessPiece(c,200,225,false); //绘制太极棋眼
drawChessPiece(c,1000,375,true);
c.font="bolder 50px 宋体";
c.fillText("Player",950,540);
c.fillStyle="#ffffff";
c.fillText("AlphaDog",50,540);
reset();
}
var chessBoard=[]; //将落子坐标化,创建棋盘二维数组;
var me=true; //设定第一步为me落棋,即黑子
var over=false;
var flash=false;
var x, y,t=500; //定义画布坐标,animation时间;
function reset(){ //重置棋盘;
for (var i= 0;i<15;i+=1){
chessBoard[i]=[];
for (var j=0;j<15;j+=1){
chessBoard[i][j]=0; //遍历数组,值初始化为0;
}
}
a.clearRect(0,0,1200,600);
me=true; //设定第一步为me落棋,即黑子
over=false;
}
var wins=[]; //创建赢法三维数组;
for (var i= 0;i<15;i+=1){
wins[i]=[];
for (var j=0;j<15;j+=1){
wins[i][j]=[];
}
}
var count = 0;
for (var i= 0;i<15;i+=1){ //遍历横向赢法数组
for (var j=0;j<11;j+=1){
for (var k=0;k<5;k+=1){
wins[i][j+k][count]=true;
}
count++;
}
}
for (var i= 0;i<15;i+=1){ //遍历纵向赢法数组
for (var j=0;j<11;j+=1){
for (var k=0;k<5;k+=1){
wins[j+k][i][count]=true;
}
count++;
}
}
for (var i= 0;i<11;i+=1){ //遍历反斜向赢法数组
for (var j=0;j<11;j+=1){
for (var k=0;k<5;k+=1){
wins[i+k][j+k][count]=true;
}
count++;
}
}
for (var i= 4;i<15;i+=1){ //遍历斜向赢法数组
for (var j=0;j<11;j+=1){
for (var k=0;k<5;k+=1){
wins[i-k][j+k][count]=true;
}
count++;
}
}
var myWin=[];
var computerWin=[];
for(var i=0;i<count;i++){ //初始化数组;
myWin[i]=0;
computerWin[i]=0
}
function drawChessBoard() { //定义绘制棋盘函数
c.strokeStyle="#454545";
c.lineWidth=1;
for(var i=0;i<15;i+=1){
c.moveTo(320+i*40,20);
c.lineTo(320+i*40,580);
c.stroke();
c.moveTo(320,20+i*40);
c.lineTo(880,20+i*40);
c.stroke();
}
}
function oneStep(i,j,me){ //定义落子函数;
c.beginPath();
c.arc(320+i*40,20+j*40,15,0,Math.PI*2);
c.closePath();
var gradient= c.createRadialGradient(320+i*40,20+j*40,10,320+i*40+2,20+j*40-2,0);//创建圆形渐变,两个圆之间为渐变区域;
if(me){ //绘制黑棋;
gradient.addColorStop(0,"#0a0a0a"); // gradient.addColorStop(0.3,"blue"); 可以在渐变区域渐变多种颜色;
gradient.addColorStop(1,"#636363");
}
else{ //绘制白棋;
gradient.addColorStop(0,"#e1e1e1");
gradient.addColorStop(1,"#f1f1f1");
}
c.fillStyle=gradient;
setTimeout(function(){ //延迟落子,时间为动画时间;
c.fill();flash=false;
},500);
}
animate.onclick=function(e){ //定义棋盘点击落子事件
if(over){
return;
}
if(!me){
return;
}
if(flash){
return
}
var x = e.offsetX; //用offset方法获取屏幕点与canvas元素原点的相对坐标;
var y = e.offsetY;
var i=Math.floor(x/40-7.5); //向下取整;完整算法为:(x-边距+棋格宽度/2)/40,此处边距等于320,棋格40;
var j=Math.floor(y/40);
if(chessBoard[i][j]==0) { //判断当前位置是否有棋子,无则执行落棋
var m=i*40+320; //计算计算落子的坐标
var n=j*40+20;
animation(m,n,me); //执行落子动画;
flash=true;
oneStep(i,j,me); //落子;
chessBoard[i][j]=1; //设定黑子位置为1;
for(var k=0;k<count;k++){
if(wins[i][j][k]){
myWin[k]++;
computerWin[k]=6;
if(myWin[k]==5){
c.font="bolder 50px 宋体";
c.fillStyle="#000000";
c.fillText("You Win!",950,100);
over=true;
}
}
}
if(!over){
me = !me; //将me取反为false,对方落子;
setTimeout(computerAI,500); //延迟电脑落子500毫秒;
}
}
}
function computerAI(){ //定义计算机智能落子函数;
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+=1){
for (var j=0;j<15;j+=1){
if(chessBoard[i][j]==0){
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]+=210;
}else if(computerWin[k]==2){
computerScore[i][j]+=420;
}else if(computerWin[k]==3){
computerScore[i][j]+=2400;
}else if(computerWin[k]==4){
computerScore[i][j]+=20000;
}
}
}
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;
}
}
}
}
}
var m=u*40+320; //计算计算落子的坐标
var n=v*40+20;
animation(m,n,me); //执行落子动画;
flash=true;
oneStep(u,v,me); //在分数最高的位置落子;
chessBoard[u][v]=2; //设定白子位置为2;
for(var k=0;k<count;k++){
if(wins[u][v][k]){
computerWin[k]++;
myWin[k]=6;
if(computerWin[k]==5){
c.font="bolder 50px 宋体";
c.fillStyle="#ffffff";
c.fillText("αDog Win!",30,100);
over=true;
}
}
}
if(!over){
me=!me;
}
}
</script>
<script>
function drawTaiJi(context,x,y,r,color,deg){ //定义绘制太极图函数,参数为上下文id,x/y坐标,半径,颜色,角度;
context.save(); //保存状态
context.translate(x,y); //设置画布旋转的中心点
context.rotate(deg);
context.translate(-x,-y); //
context.shadowColor="rgba(10,10,10,0.5)"; //阴影颜色
context.shadowOffsetX=context.shadowOffsetY=5; //阴影方向
context.shadowBlur=5; //高斯值
context.fillStyle=color;
context.beginPath();
context.arc(x,y,r,Math.PI*1.5,Math.PI*0.5);
context.arc(x,y+r/2,r/2,Math.PI*0.5,Math.PI*1.5);
context.arc(x,y-r/2,r/2,Math.PI*0.5,Math.PI*1.5,true); //默认顺时针,值为false;逆时针为true;
context.lineJoin="round";
context.closePath();
context.fill();
context.shadowColor="rgba(10,10,10,0)"; //初始化阴影颜色
context.restore(); //恢复状态;
}
function drawChessPiece(context,x,y,color){ //绘制棋子函数
context.beginPath();
context.arc(x,y,15,0,2*Math.PI);
context.closePath();
var gradient= c.createRadialGradient(x,y,10,x+2,y-2,0);//创建圆形渐变,两个圆之间为渐变区域;
if(color){ //绘制黑棋;
gradient.addColorStop(0,"#0a0a0a");
gradient.addColorStop(1,"#636363");
}
else{ //绘制白棋;
gradient.addColorStop(0,"#e1e1e1");
gradient.addColorStop(1,"#f1f1f1");
}
context.fillStyle=gradient;
context.fill();
}
function animation(i,j,me){ //棋子落子时的动画函数;
if(me){ //判断哪方落子
var sx=(1000-i)/10; //将两点之间x轴、y轴分别分成10段
var sy=(375-j)/10;
var k=1;
timer();
function timer() {
if (k< 11) {
a.clearRect(0,0,1200,600);
// c.globalAlpha=1; //绘制像素的透明度;
drawChessPiece(a, 1000 - sx*k, 375 - sy*k, true); //绘制十次棋子
k++;
setTimeout(timer, 50);
}
}
}else { //白子落子;
var sx=(200-i)/10;
var sy=(225-j)/10;
var k=1;
timer();
function timer() {
if (k< 11) {
a.clearRect(0,0,1200,600); //清除画布;
drawChessPiece(a, 200 - sx*k, 225 - sy*k, false); //绘制十次棋子
k++;
setTimeout(timer, 50);
}
}
}
}
</script>
</body>
</html>
以上是关于Canvas制作五子棋人机大战的主要内容,如果未能解决你的问题,请参考以下文章