首页 > 编程 > JavaScript > 正文

原生JS+Canvas实现五子棋游戏实例

2019-11-19 16:18:37
字体:
来源:转载
供稿:网友

一、功能模块

先看下现在做完的效果:

线上体验:https://wj704.github.io/five_game.html

主要功能模块为:

1.人机对战功能
2.悔棋功能
3.撤销悔棋功能

二、代码详解

2.1 人机对战功能实现

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

    //绘画棋盘    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();      }    }

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

       //赢法数组      var wins = [];      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++){          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++;        }      }

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

  for(var i = 0; i < count; i++){        myWin[i] = 0;        _myWin[i] = 0;        computerWin[i] = 0;        _compWin[i] = 0;   }

然后就是人开始下棋:

 

  // 我,下棋  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);    _nowi = i;    _nowj = j;    if(chressBord[i][j] == 0){      oneStep(i,j,me);      chressBord[i][j] = 1; //我,已占位置          for(var k = 0; k < count; k++){ // 将可能赢的情况都加1        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( new RegExp( "(//s|^)unable(//s|$)" )," " );       }

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

    //画棋子    var oneStep = function(i,j,me){      // debugger;      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();    }

接着看计算机怎么下棋,具体看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(chressBord[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] += 220;                }else if(computerWin[k] == 2){                  computerScore[i][j] += 420;                }else if(computerWin[k] == 3){                  computerScore[i][j] += 2100;                }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;                }            }          }        }      }      _compi = u;      _compj = v;      oneStep(u,v,false);      chressBord[u][v] = 2; //计算机占据位置      for(var k = 0; k < count; 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.onclick = function(e){        if(!backAble) { return;}        over = false;        me = true;        // 我,悔棋        chressBord[_nowi][_nowj] = 0; //我,已占位置 还原        minusStep(_nowi, _nowj); //销毁棋子                         for(var k = 0; k < count; k++){ // 将可能赢的情况都减1          if(wins[_nowi][_nowj][k]){            myWin[k]--;            computerWin[k] = _compWin[k];//这个位置对方可能赢          }        }        // 计算机相应的悔棋        chressBord[_compi][_compj] = 0; //计算机,已占位置 还原        minusStep(_compi, _compj); //销毁棋子                         for(var k = 0; k < count; k++){ // 将可能赢的情况都减1          if(wins[_compi][_compj][k]){            computerWin[k]--;            myWin[k] = _myWin[i];//这个位置对方可能赢          }        }        resultTxt.innerHTML = '--益智五子棋--';        returnAble = true;        backAble = false;         // 撤销悔棋功能可用        returnbtn.className = returnbtn.className.replace( new RegExp( "(//s|^)unable(//s|$)" )," " );       }

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

     //销毁棋子     var minusStep = 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.onclick = function(e){      if(!returnAble) { return; }      // 我,撤销悔棋      chressBord[_nowi][_nowj] = 1; //我,已占位置       oneStep(_nowi,_nowj,me);                     for(var k = 0; k < count; 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(var k = 0; k < count; 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。

最后代码放到github上了,地址:https://github.com/wj704/wj704.github.io/blob/master/five_game.html

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表