下面是详细讲解“纯JS实现五子棋游戏兼容各浏览器(附源码)”的完整攻略。
1. 实现概述
该游戏是基于纯JS实现的,实现思路如下:
- 初始化画布,绘制棋盘;
- 监听鼠标点击事件,判断点击位置是否合法;
- 判断当前玩家是否胜利;
- 实现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技术站