html五子棋悔棋,原生 JS + Canvas 实现五子棋游戏

原标题:原生 JS + Canvas 实现五子棋游戏

||

一、功能模块

先看下现在做完的效果:

33bef78a7608aa5eef639209b56e7122.png

线上体验:

https://wj704.github.io/five_game.html

主要功能模块为:

人机对战功能

悔棋功能

撤销悔棋功能二、代码详解 2.1 人机对战功能实现

从效果图可以看到,棋盘的横竖可以放的位置为15*15,通过canvas画棋盘:

//绘画棋盘

vardrawChessBoard=function(){

for(vari=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();

}

}

知道格子数后,我们先看五子棋有多少种赢法:

//赢法数组

varwins=[];

for(vari=0;i<15;i++){

wins[i]=[];

for(varj=0;j<15;j++){

wins[i][j]=[];

}

}

varcount=0;//赢法总数

//横线赢法

for(vari=0;i<15;i++){

for(varj=0;j<11;j++){

for(vark=0;k<5;k++){

wins[i][j+k][count]=true;

}

count++;

}

}

//竖线赢法

for(vari=0;i<15;i++){

for(varj=0;j<11;j++){

for(vark=0;k<5;k++){

wins[j+k][i][count]=true;

}

count++;

}

}

//正斜线赢法

for(vari=0;i<11;i++){

for(varj=0;j<11;j++){

for(vark=0;k<5;k++){

wins[i+k][j+k][count]=true;

}

count++;

}

}

//反斜线赢法

for(vari=0;i<11;i++){

for(varj=14;j>3;j--){

for(vark=0;k<5;k++){

wins[i+k][j-k][count]=true;

}

count++;

}

}

根据赢法总数定义分别保存计算机和人赢法的数组:

for(vari=0;i

myWin[i]=0;

_myWin[i]=0;

computerWin[i]=0;

_compWin[i]=0;

}

然后就是人开始下棋:

// 我,下棋

chess.οnclick=function(e){

if(over){// 游戏结束

return;

}

if(!me){

return;

}

varx=e.offsetX;

vary=e.offsetY;

vari=Math.floor(x/30);

varj=Math.floor(y/30);

_nowi=i;

_nowj=j;

if(chressBord[i][j]==0){

oneStep(i,j,me);

chressBord[i][j]=1;//我,已占位置

for(vark=0;k

if(wins[i][j][k]){

myWin[k]++;

_compWin[k]=computerWin[k];// 为悔棋做准备

computerWin[k]=6;//这个位置对方不可能赢了

if(myWin[k]==5){

resultTxt.innerHTML='恭喜,你赢了!';

over=true;

}

}

}

if(!over){

me=!me;

computerAI();

}

}

// 悔棋功能可用

backbtn.className=backbtn.className.replace(newRegExp("(s|^)unable(s|$)")," ");

}

oneStep() 方法为落子,要在棋盘上画一个棋子:

//画棋子

varoneStep=function(i,j,me){

// debugger;

context.beginPath();

context.arc(15+i*30,15+j*30,13,0,2*Math.PI);//画圆

context.closePath();

//渐变

vargradient=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();

}

接着看计算机怎么下棋,具体看computerAI()方法:

// 计算机下棋

varcomputerAI=function(){

varmyScore=[];

varcomputerScore=[];

varmax=0;

varu=0,v=0;

for(vari=0;i<15;i++){

myScore[i]=[];

computerScore[i]=[];

for(varj=0;j<15;j++){

myScore[i][j]=0;

computerScore[i][j]=0;

}

}

for(vari=0;i<15;i++){

for(varj=0;j<15;j++){

if(chressBord[i][j]==0){

for(vark=0;k

if(wins[i][j][k]){

if(myWin[k]==1){

myScore[i][j]+=200;

}elseif(myWin[k]==2){

myScore[i][j]+=400;

}elseif(myWin[k]==3){

myScore[i][j]+=2000;

}elseif(myWin[k]==4){

myScore[i][j]+=10000;

}

if(computerWin[k]==1){

computerScore[i][j]+=220;

}elseif(computerWin[k]==2){

computerScore[i][j]+=420;

}elseif(computerWin[k]==3){

computerScore[i][j]+=2100;

}elseif(computerWin[k]==4){

computerScore[i][j]+=20000;

}

}

}

if(myScore[i][j]>max){

max=myScore[i][j];

u=i;

v=j;

}elseif(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;

}elseif(computerScore[i][j]==max){

if(myScore[i][j]>myScore[u][v]){

u=i;

v=j;

}

}

}

}

}

_compi=u;

_compj=v;

oneStep(u,v,false);

chressBord[u][v]=2;//计算机占据位置

for(vark=0;k

if(wins[u][v][k]){

computerWin[k]++;

_myWin[k]=myWin[k];

myWin[k]=6;//这个位置对方不可能赢了

if(computerWin[k]==5){

resultTxt.innerHTML='o(╯□╰)o,计算机赢了,继续加油哦!';

over=true;

}

}

}

if(!over){

me=!me;

}

}

根据相应的权重,计算出计算机应该落子的位置。

2.2 悔棋功能

要提的是,这里暂时只能悔一步棋。悔棋功能主要关键点是:1、销毁刚刚下的棋子;2、将之前不可能赢的状态还原;看下具体的代码:

// 悔棋

backbtn.οnclick=function(e){

if(!backAble){return;}

over=false;

me=true;

// 我,悔棋

chressBord[_nowi][_nowj]=0;//我,已占位置 还原

minusStep(_nowi,_nowj);//销毁棋子

for(vark=0;k

if(wins[_nowi][_nowj][k]){

myWin[k]--;

computerWin[k]=_compWin[k];//这个位置对方可能赢

}

}

// 计算机相应的悔棋

chressBord[_compi][_compj]=0;//计算机,已占位置 还原

minusStep(_compi,_compj);//销毁棋子

for(vark=0;k

if(wins[_compi][_compj][k]){

computerWin[k]--;

myWin[k]=_myWin[i];//这个位置对方可能赢

}

}

resultTxt.innerHTML='--益智五子棋--';

returnAble=true;

backAble=false;

// 撤销悔棋功能可用

returnbtn.className=returnbtn.className.replace(newRegExp("(s|^)unable(s|$)")," ");

}

minusStep()为销毁棋子的方法,我们看下是怎么销毁的。

//销毁棋子

varminusStep=function(i,j){

//擦除该圆

context.clearRect((i)*30,(j)*30,30,30);

// 重画该圆周围的格子

context.beginPath();

context.moveTo(15+i*30,j*30);

context.lineTo(15+i*30,j*30+30);

context.moveTo(i*30,j*30+15);

context.lineTo((i+1)*30,j*30+15);

context.stroke();

}

首先通过clearRect()擦掉该圆,然后再重新画该圆周围的格子,注意相应的位置,这里花了些时间折腾。

2.3 撤销悔棋功能

悔棋过后,再撤销,相当于还原悔棋之前的状态。代码比较简单:

// 撤销悔棋

returnbtn.οnclick=function(e){

if(!returnAble){return;}

// 我,撤销悔棋

chressBord[_nowi][_nowj]=1;//我,已占位置

oneStep(_nowi,_nowj,me);

for(vark=0;k

if(wins[_nowi][_nowj][k]){

myWin[k]++;

_compWin[k]=computerWin[k];

computerWin[k]=6;//这个位置对方不可能赢

}

if(myWin[k]==5){

resultTxt.innerHTML='恭喜,你赢了!';

over=true;

}

}

// 计算机撤销相应的悔棋

chressBord[_compi][_compj]=2;//计算机,已占位置

oneStep(_compi,_compj,false);

for(vark=0;k

if(wins[_compi][_compj][k]){

computerWin[k]++;

_myWin[k]=myWin[k];

myWin[k]=6;//这个位置对方不可能赢

}

if(computerWin[k]==5){

resultTxt.innerHTML='o(╯□╰)o,计算机赢了,继续加油哦!';

over=true;

}

}

returnbtn.className+='unable';

returnAble=false;

backAble=true;

}

至此,比较简单的完成了这三个功能。

三、总结

五子棋游戏的核心关键点是:

1、弄清楚有多少种赢法;

2、怎么判断是否已经赢了;

3、计算机下棋算法。这里巧妙地运用数组存储赢法,判断是否赢了,通过权重比较,计算出计算机该下棋的位置。 过程中用到canvas,之前有学习过,虽然很久没用,查了些资料,复习了怎么画线,画圆,学会了怎么如何清除一个圆等。 然后要注意的是,用原生Js怎么为元素添加、删除class。

作者:eraser123

源自:https://segmentfault.com/a/1190000009826648

声明:文章著作权归作者所有,如有侵权,请联系小编删除。返回搜狐,查看更多

责任编辑:

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值