五子棋 两人对战

#头条创作挑战赛#

banner

这是一个关于五子棋实现的系列文,本文是第 1 篇。总共会分成两篇文章:

当然,本文的两人对战,你找不到第二个玩伴的话,那你可以左手和右手玩

功能概览

  1. 棋盘大小自定义
  2. 白棋先下
  3. 不支持悔棋
  4. 提示当前下棋方(黑子 | 白子)
  5. 输赢判断

代码即文档,读者可在体验地址章节进入 码上掘金 大屏跟读代码,相信读者能有所收获。

读者能来个点赞,那就是对笔者的最大肯定 ‍♂️

讲解

我们制定简单的五子棋规则:在五子棋中,双方各执一个颜色的棋子,空盘开局,交替落子且每次只能落子一枚。如果同种颜色的棋子在横向、竖向或者斜线上有连续五个子,则该颜色棋子的一方获胜。

获胜的情况

胜利的情况有如下四种:

  1. 横向情况 - 此时黑子获胜

  1. 竖向情况 - 此时白子获胜

  1. 左斜线情况 - 此时白子获胜

  1. 右斜线情况 - 此时黑子获胜

否则,黑白双方打成平手(即平局)。

项目的难点

1. 将 canvas 上绘制的棋盘和矩阵一一对应

体验下代码你就明白了:

// 监听鼠标点击棋盘的位置
listenDownChessman() {
  this.checkerboardDom.onclick = event => {
    let {
        offsetX: x,
        offsetY: y
    } = event;
    const { width, height } = this.lattice;
    x = Math.round((x - 15) / width);
    y = Math.round((y - 15) / height);
    if(this.checkerboardMatrix[x][y] !== undefined && Object.is(this.checkerboardMatrix[x][y], 0)) {
      this.checkerboardMatrix[x][y] = this.role;
      // 刻画棋子
      this.drawChessman({ x, y }, Object.is(this.role, EnumRoles.BLACK));
      this.role = Object.is(this.role, EnumRoles.BLACK) ? EnumRoles.WHITE : EnumRoles.BLACK;
      // 设置当前执棋
      if(!this.win) { // 游戏中
        this.setCurrentRole();
      } else { // 游戏结束
        Object.is(this.role, EnumRoles.BLACK) ? this.currentRoleDom.setAttribute("class", "chessman win-white") : this.currentRoleDom.setAttribute("class", "chessman win-black")
        this.message = '赢得本场胜利'
        this.setResultMsgHint();
      }
    }
  }
}
复制代码

我们需要获取 canvas 上相对原点(左上角)的偏移值,计算出在矩阵上对应的位置。然后判断该位置是否已经落子,如果没有落子,则进行棋子的绘制。

2. 判断输赢

在上面获胜情况中我们已经了解。下面我们看看代码实现:

/*
* @method gameReferee 游戏裁判
* @param coordinate 坐标 (x, y)
* @paran role 角色
*/
gameReferee(coordinate, role) {
  const { x, y } = coordinate;
  if( x === undefined || y === undefined || role === undefined) return;

  // 连杀的次数
  let countContinuous = 0;
  // x 轴的情况
  const XContinuous = this.checkerboardMatrix.map(x => x[y]);
  // y 轴的情况
  const YContinuous = this.checkerboardMatrix[x];
  const S1Continuous = [];
  const S2Continuous = [];
  this.checkerboardMatrix.forEach((_x,i) => {
      // 左斜线
      const S1Item = _x[y - (x - i)];
      if(S1Item !== undefined){
          S1Continuous.push(S1Item);
      }
      // 右斜线
      const S2Item = _x[y + (x - i)];
      if(S2Item !== undefined) {
          S2Continuous.push(S2Item);
      }
  });
  // 当前落棋点所在的X轴/Y轴/交叉斜轴,只要有能连起来的5个子的角色即有胜者
  [XContinuous, YContinuous, S1Continuous, S2Continuous].forEach(axis => {
      if(axis.some((x, i) => axis[i] !== 0 &&
              axis[i - 2] === axis[i - 1] &&
              axis[i - 1] === axis[i] &&
              axis[i] === axis[i + 1] &&
              axis[i + 1] === axis[i + 2])) {
          countContinuous++
      }
  });

  if(countContinuous) {
    this.win = true;
    this.checkerboardDom.onclick = null; // 游戏结束,不允许点击
  }
}
复制代码

上面代码的注释已经讲解得很清楚了。简单来说,我们就是将二维数组分成四种情况处理,将其形成四个一维数组,再对四个一维数组进行判断,如果它们中有连续 5 个相同的数值,则可判定输赢。

比如,在 15 * 15 的棋盘中,某次落棋后,可得:

XContinuous = [0, 1, 2, 2, 2, 2, 2, 0, 2, 1, 0, 1, 1, 0, 0]
复制代码

0 代表空, 1 代表黑子,2 代表白子

这里 XContinuous 横轴中就有连续五个白子,则白方获胜。

体验地址:五子棋 - 双人模式/人机模式 - JavaScript 实现 - 码上掘金五子棋 - 双人模式/人机模式 - JavaScript 实现 - 码上掘金

赠人玫瑰,手留花香。俺不要玫瑰,只要读者的一个举手之劳的赞~ 逃:)

展开阅读全文

页面更新:2024-05-16

标签:白子   落子   斜线   黑子   棋盘   人机   输赢   棋子   情况   代码

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top