纯JS实现五子棋游戏兼容各浏览器(附源码)

yizhihongxing

下面是详细讲解“纯JS实现五子棋游戏兼容各浏览器(附源码)”的完整攻略。

1. 实现概述

该游戏是基于纯JS实现的,实现思路如下:

  1. 初始化画布,绘制棋盘;
  2. 监听鼠标点击事件,判断点击位置是否合法;
  3. 判断当前玩家是否胜利;
  4. 实现AI逻辑,即电脑自动下棋的过程。

2. 实现过程

2.1 初始化画布,绘制棋盘

首先,在HTML中定义一个canvas元素用于绘制游戏界面,然后通过JS获取canvas元素,设置画布大小、线条颜色等样式。接着,绘制棋盘。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>五子棋游戏</title>
  <style>
    canvas {
      border: 1px solid #999;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="600" height="600"></canvas>
  <script>
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var ROW = 15;
    var GAP = canvas.width / (ROW + 1);
    var qizi = {};

    for (var i = 0; i < ROW; i++) {
      ctx.moveTo(GAP, GAP * (i + 1));
      ctx.lineTo(canvas.width - GAP, GAP * (i + 1));
      ctx.stroke();
      ctx.moveTo(GAP * (i + 1), GAP);
      ctx.lineTo(GAP * (i + 1), canvas.width - GAP);
      ctx.stroke();
    }
  </script>
</body>
</html>

2.2 监听鼠标点击事件,判断点击位置是否合法

我们需要监听鼠标点击事件,获取鼠标点击的坐标,并将坐标转换成棋盘交叉点的坐标。由于棋盘是一个二维数组,因此将获取的坐标作为数组的下标,将棋子信息存储在二维数组中。完整代码如下:

canvas.onclick = function(e) {
  var x = e.offsetX;
  var y = e.offsetY;
  var i = Math.round(x / GAP) - 1;
  var j = Math.round(y / GAP) - 1;
  if (qizi[i + '-' + j]) {
    return;
  }
  drawQizi(i, j, true);
  qizi[i + '-' + j] = true;
}

其中,drawQizi函数用于绘制棋子。

2.3 判断当前玩家是否胜利

当玩家下完一步棋时,需要判断当前玩家是否胜利。这里使用一个五位数的二进制数表示棋盘上的落子情况,其中1表示黑子,0表示白子。比如,如果一行连成了五个黑子,则该行的二进制数为11111,即31;而如果该行只连成了四个黑子,则该行的二进制数为11110,即30。判断胜负时,只需要检查当前玩家的落子情况是否满足五子连珠即可。完整代码如下:

// 判断当前玩家是否胜利
function check(pos, color) {
  var table = {};
  for (var i in qizi) {
    if (qizi[i] === color) {
      table[i] = true;
    }
  }
  var sp = pos.split('-');
  var i = sp[0], j = sp[1];
  var num1 = 1, num2 = 1, num3 = 1, num4 = 1;
  var table2 = {};
  table2[i + '-' + j] = true;
  // 横向
  for (var k = 1; table[(+i + k) + '-' + j]; k++) {
    num1++;
    table2[(+i + k) + '-' + j] = true;
  }
  for (var k = 1; table[(+i - k) + '-' + j]; k++) {
    num1++;
    table2[(+i - k) + '-' + j] = true;
  }
  if (num1 >= 5) return true;
  // 竖向
  for (var k = 1; table[i + '-' + (+j + k)]; k++) {
    num2++;
    table2[i + '-' + (+j + k)] = true;
  }
  for (var k = 1; table[i + '-' + (+j - k)]; k++) {
    num2++;
    table2[i + '-' + (+j - k)] = true;
  }
  if (num2 >= 5) return true;
  // 左斜线
  for (var k = 1; table[(+i + k) + '-' + (+j + k)]; k++) {
    num3++;
    table2[(+i + k) + '-' + (+j + k)] = true;
  }
  for (var k = 1; table[(+i - k) + '-' + (+j - k)]; k++) {
    num3++;
    table2[(+i - k) + '-' + (+j - k)] = true;
  }
  if (num3 >= 5) return true;
  // 右斜线
  for (var k = 1; table[(+i - k) + '-' + (+j + k)]; k++) {
    num4++;
    table2[(+i - k) + '-' + (+j + k)] = true;
  }
  for (var k = 1; table[(+i + k) + '-' + (+j - k)]; k++) {
    num4++;
    table2[(+i + k) + '-' + (+j - k)] = true;
  }
  if (num4 >= 5) return true;
  return false;
}

2.4 实现AI逻辑

实现AI逻辑,让电脑自动下棋。思路是根据已有的落子情况,计算每个空位的得分,选择得分最高的点为电脑下一步落子的位置。完整代码如下:

canvas.onclick = function(e) {
  var x = e.offsetX;
  var y = e.offsetY;
  var i = Math.round(x / GAP) - 1;
  var j = Math.round(y / GAP) - 1;
  if (qizi[i + '-' + j]) {
    return;
  }
  drawQizi(i, j, true);
  qizi[i + '-' + j] = true;
  if (check(i + '-' + j, true)) {
    alert('恭喜您,您赢了!');
    canvas.onclick = null;
    return;
  } else {
    paita();
    if (check(ai.x + '-' + ai.y, false)) {
      alert('很遗憾,您输了!');
      canvas.onclick = null;
      return;
    }
  }
}
function paita() {
  var zuobiao = {};
  var max = -Infinity;
  for (var i in qizi) {
    var x = parseInt(i.split('-')[0]);
    var y = parseInt(i.split('-')[1]);
    var hang = {}, lie = {}, x1xie = {}, x2xie = {};
    for (var j in qizi) {
      if (parseInt(j.split('-')[0]) === x) {
        hang[j] = true;
      }
      if (parseInt(j.split('-')[1]) === y) {
        lie[j] = true;
      }
      if (parseInt(j.split('-')[0]) - x === parseInt(j.split('-')[1]) - y) {
        x1xie[j] = true;
      }
      if (parseInt(j.split('-')[0]) - x === y - parseInt(j.split('-')[1])) {
        x2xie[j] = true;
      }
    }
    var hs = check2(hang);
    var ls = check2(lie);
    var s1s = check2(x1xie);
    var s2s = check2(x2xie);
    if (hs > max) {
      max = hs;
      zuobiao = {x: x, y: y};
    }
    if (ls > max) {
      max = ls;
      zuobiao = {x: x, y: y};
    }
    if (s1s > max) {
      max = s1s;
      zuobiao = {x: x, y: y};
    }
    if (s2s > max) {
      max = s2s;
      zuobiao = {x: x, y: y};
    }
  }
  drawQizi(zuobiao.x, zuobiao.y, false);
  qizi[zuobiao.x + '-' + zuobiao.y] = false;
  ai.x = zuobiao.x;
  ai.y = zuobiao.y;
}
function check2(obj) {
  var max = -Infinity, count = 0;
  for (var i = 0; i < ROW; i++) {
    if (obj[i + '-0'] && obj[i + '-1'] && obj[i + '-2'] && obj[i + '-3'] && obj[i + '-4']) {
      count++;
    } else {
      max = count > max ? count : max;
      count = 0;
    }
  }
  max = count > max ? count : max;
  count = 0;
  for (var i = 0; i < ROW; i++) {
    if (obj['0-' + i] && obj['1-' + i] && obj['2-' + i] && obj['3-' + i] && obj['4-' + i]) {
      count++;
    } else {
      max = count > max ? count : max;
      count = 0;
    }
  }
  max = count > max ? count : max;
  count = 0;
  for (var i = 0; i < ROW; i++) {
    if (obj[i + '-' + i]) {
      count++;
    } else {
      max = count > max ? count : max;
      count = 0;
    }
  }
  max = count > max ? count : max;
  count = 0;
  for (var i = 0; i < ROW; i++) {
    if (obj[(ROW - 1 - i) + '-' + i]) {
      count++;
    } else {
      max = count > max ? count : max;
      count = 0;
    }
  }
  max = count > max ? count : max;
  count = 0;
  return max;
}

3. 示例说明

3.1 示例一:实现对战模式

可以通过添加对战模式,让两个玩家进行互动。例如,添加一个按钮用于切换到对战模式,点击后需要提示先后手,并且落子颜色会随着先后手的不同而变化。修改后的完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>五子棋游戏</title>
  <style>
    canvas {
      border: 1px solid #999;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="600" height="600"></canvas>
  <button onclick="modeChange()">切换到对战模式</button>
  <script>
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var ROW = 15;
    var GAP = canvas.width / (ROW + 1);
    var qizi = {};
    var mode = 1;

    for (var i = 0; i < ROW; i++) {
      ctx.moveTo(GAP, GAP * (i + 1));
      ctx.lineTo(canvas.width - GAP, GAP * (i + 1));
      ctx.stroke();
      ctx.moveTo(GAP * (i + 1), GAP);
      ctx.lineTo(GAP * (i + 1), canvas.width - GAP);
      ctx.stroke();
    }

    canvas.onclick = function(e) {
      var x = e.offsetX;
      var y = e.offsetY;
      var i = Math.round(x / GAP) - 1;
      var j = Math.round(y / GAP) - 1;
      if (qizi[i + '-' + j]) {
        return;
      }
      if (mode === 1) {
        drawQizi(i, j, true);
        qizi[i + '-' + j] = true;
        if (check(i + '-' + j, true)) {
          alert('恭喜您,您赢了!');
          canvas.onclick = null;
          return;
        }
        mode = 2;
      } else if (mode === 2) {
        drawQizi(i, j, false);
        qizi[i + '-' + j] = false;
        if (check(i + '-' + j, false)) {
          alert('恭喜电脑赢了!');
          canvas.onclick = null;
          return;
        }
        mode = 1;
      }
    }

    function modeChange() {
      alert('您执黑,电脑执白。');
      mode = 1;
    }
  </script>
</body>
</html>

3.2 示例二:添加音效和动画效果

可以通过添加音效和动画效果,提高游戏的趣味性。例如,添加音效用于提示棋子落下的声音;添加动画效果用于提示玩家哪里可以下棋。修改后的完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>五子棋游戏</title>
  <style>
    canvas {
      border: 1px solid #999;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="600" height="600"></canvas>
  <button onclick="modeChange()">切换到对战模式</button>
  <audio src="https://www.w3school.com.cn/i/horse.ogg" id="music"></audio>
  <script>
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var ROW = 15;
    var GAP = canvas.width / (ROW + 1);
    var qizi = {};
    var mode = 1;
    var music = document.getElementById("music");

    for (var i = 0; i < ROW; i++) {
      ctx.moveTo(GAP, GAP * (i + 1));
      ctx.lineTo(canvas.width - GAP, GAP * (i + 1));
      ctx.stroke();
      ctx.moveTo(GAP * (i + 1), GAP);
      ctx.lineTo(GAP * (i + 1), canvas.width - GAP);
      ctx.stroke();
    }

    canvas.onclick = function(e) {
      var x = e.offsetX;
      var y = e.offsetY;
      var i = Math.round(x / GAP) - 1;
      var j = Math.round(y / GAP) - 1;
      if (qizi[i + '-' + j]) {
        return;
      }
      if (mode === 1) {
        drawQizi(i, j, true);
        qizi[i + '-' + j] = true;
        if (check(i + '-' + j, true)) {
          alert('恭喜您,您赢了!');
          canvas.onclick = null;
          return;
        }
        mode = 2;
      } else if (mode === 2) {
        drawQizi(i, j, false);
        qizi[i + '-' + j] = false;
        if (check(i + '-' + j, false)) {
          alert('恭喜电脑赢了!');
          canvas.onclick = null;
          return;
        }
        mode = 1;
      }
      music.play();
      animate(i, j);
    }

    function modeChange() {
      alert('您执黑,电脑执白。');
      mode = 1;
    }

    function animate(x, y) {
      ctx.save();
      ctx.beginPath();
      ctx.arc((x + 1) * GAP, (y + 1) * GAP, GAP / 3, 0, Math.PI * 2);
      ctx.closePath();
      ctx.fillStyle = "rgba(0, 0, 0, 0.2)";
      ctx.strokeStyle = "rgba(0, 0, 0, 0.6)";
      ctx.fill();
      ctx.stroke();
      ctx.restore();
    }
  </script>
</body>
</html>

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:纯JS实现五子棋游戏兼容各浏览器(附源码) - Python技术站

(0)
上一篇 2023年6月11日
下一篇 2023年6月11日

相关文章

  • js实现弹框效果

    如何通过JavaScript实现弹框效果呢?下面是一些步骤和示例代码来帮助你实现这个功能: 步骤一:创建弹出框的 HTML 代码 首先,要在 HTML 代码中创建弹出框的模板,可以使用 <div> 标签来实现: <div id="myModal" class="modal"> <div c…

    JavaScript 2023年5月27日
    00
  • JavaScript setTimeout和setInterval的用法与区别详解

    JavaScript setTimeout和setInterval的用法与区别详解 setTimeout()和setInterval()是JavaScript中的两个重要函数,它们都用于实现JavaScript中的定时器。通常,我们使用这两个函数来延迟执行一段代码或者重复执行一段代码。但是setTimeout()和setInterval()用法和区别还是有很…

    JavaScript 2023年6月11日
    00
  • 不要小看注释掉的JS 引起的安全问题

    首先,注释掉的 JavaScript 代码是存在安全问题的,因为这些代码可以被黑客利用来进行攻击。因此,我们需要小心处理这些注释掉的代码。下面是一些攻略: 1. 审查代码,删除无用的注释信息 我们应该定期地审查我们的代码,删除无用的注释信息。在代码中注释掉的代码可能是过时的,已被修复或已不再需要。除此之外,注释信息还可能包含敏感信息,比如数据库密码、API …

    JavaScript 2023年6月11日
    00
  • js 转义字符及URI编码详解

    JS 转义字符及 URI 编码详解 在 JavaScript 编程中,我们经常需要对一些字符进行编码或转义,以确保它们能够被正确地处理和显示。同时,对于某些需要作为 URL 参数传递的字符,也需要使用 URI 编码进行处理。本攻略将就这两个问题进行详细的讲解。 转义字符 在 JavaScript 中,我们可以通过使用转义字符来表示一些特定的字符。下表列出了一…

    JavaScript 2023年5月20日
    00
  • JavaScript在IE和Firefox(火狐)的不兼容问题解决方法小结

    为了解决JavaScript在IE和Firefox(火狐)的不兼容问题,我们需要掌握以下知识点: 1. DOM(文档对象模型)的差异 IE和Firefox对DOM标准的解析有所不同,导致同样的JavaScript代码在不同浏览器中执行效果会有所不同。我们可以采用以下方法解决这个问题: (1)使用ID来获取元素 在IE中,我们可以通过document.all[…

    JavaScript 2023年5月18日
    00
  • ASP动态生成的javascript表单验证代码

    下面是ASP动态生成的javascript表单验证代码的完整攻略。 什么是ASP动态生成的javascript表单验证代码? ASP动态生成的javascript表单验证代码是在ASP程序中使用javascript代码来验证用户提交的表单数据,它可以确保用户提交的数据格式符合要求,从而排除了很多不合规的数据,提高了网站的安全性和稳定性。 如何实现ASP动态生…

    JavaScript 2023年6月10日
    00
  • 2021年值得向Python开发者推荐的VS Code扩展插件

    下面是详细讲解“2021年值得向Python开发者推荐的VS Code扩展插件”的完整攻略。 1. 简介 VS Code 是一款免费开源的轻量级编辑器,支持多种编程语言,Python 是其中之一。丰富的扩展插件使得 VS Code 更加强大,可以让开发者更加高效地编写 Python 代码。本攻略将介绍一些值得向 Python 开发者推荐的扩展插件。 2. 推…

    JavaScript 2023年5月28日
    00
  • JS 两个字符串时间的天数差计算

    当我们需要计算两个字符串表示的时间之间相差的天数时,我们需要先将字符串转换为日期对象,比较两个日期对象之间的天数差。 以下是详细的步骤: 步骤一:将字符串转换为日期对象 使用Date()方法将字符串转换为日期对象,语法如下: var date1 = new Date(‘2019-01-01’); var date2 = new Date(‘2019-01-0…

    JavaScript 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部