前言
- 使用技术:
- canvas
- 算法
- 三维数组
- 循环遍历(计算赢法,计算坐标)
棋盘阴影
display: block;
margin: 50px auto;
box-shadow: 5px 5px 5px #b9b9b9, -2px -2px 2px #efefef;
背景渐变
background-image: linear-gradient(to top, #fbc2eb 0%, #a6c1ee 100%);
绘制棋盘
// 获取棋盘元素容器
let chess = document.querySelector('.chess');
// 获取显示胜利的元素
let title = document.querySelector('h3');
// 获取开始游戏按钮
let start = document.querySelector('.start');
// 控制游戏状态
let flag = false;
// 将该元素变成一个可绘制的画板
let context = chess.getContext('2d');
// 设置画笔绘制颜色
context.strokeStyle = '#b9b9b9';
// 定义一个绘制棋盘的函数
function drawChessBoard () {
// 循环遍历生成棋盘
for (let i = 0; i < 15; i++) {
// 设置横线起始点坐标
context.moveTo(15, 15+i*30);
// 设置横线结束点坐标
context.lineTo(435, 15+i*30);
// 连接 2 点
context.stroke();
// 设置竖线起始点坐标
context.moveTo(15+i*30, 15);
// 设置竖线结束点坐标
context.lineTo(15+i*30, 435);
// 连接 2 点
context.stroke();
}
}
赢法数组
- 定义一个赢法数组
- 将每个子的坐标放入数组中,判断五个子的坐标是否和赢法数组相匹配,匹配则赢,不匹配则继续游戏
```javascript
// 定义赢法数组
let wins = [];
// 循环生成赢法数组
for(let i = 0; i < 15; i++) {
wins[i] = []
for(let j = 0; j < 15; j++) {
} }wins[i][j] = []
// 设置赢法编号 let count = 0; // 统计横线赢 for(let i = 0; i < 15; i++) { for(let j = 0; j < 11; j++) { for(let k = 0; k < 5; k++) { wins[j+k][i][count]=true; } count++; } }
// 统计竖线赢 for(let i = 0; i <15; i++) { for(let j = 0; j < 11; j++) { for(let k = 0; k < 5; k++) { wins[i][j+k][count]=true; } count++; } }
// 统计正斜线赢 for(let i = 0; i < 11; i++) { for(let j = 0; j < 11; j++) { for(let k = 0; k < 5; k++) { wins[i+k][j+k][count]=true; } count++; } }
// 统计反斜线赢 for(let i = 0; i < 11; i++) { for(let j = 14; j > 3; j—) { for(let k = 0; k < 5; k++) { wins[i+k][j-k][count]=true; } count++; } }
// 判断棋盘上的每个坐标内是否已经下了棋子 // 定义一个二维数组,标记棋盘上的所有坐标 let chessboard = []; // 循环遍历棋盘所有坐标 for(let i = 0; i < 15; i++) { chessboard[i]=[]; for(let j = 0; j < 15; j++) { chessboard[i][j] = 0; } }
// 下棋 let me = true; // 标记玩家是否可以下棋 let over = false; // 标记游戏是否结束
chess.onclick = function(e) { // 如果游戏结束,不可以下棋 if(over) { return; } // 判断玩家是否可以下棋 if(!me) { return; } // 获取 x 轴坐标 let x = e.offsetX; // 获取 y 轴坐标 let y = y.offsetY;
let i = Math.floor(x/30); let j = Math.floor(y/30);
if(chessboard[i][j] == 0) { // 下一个子 chessboard[i][j] = 1; } }
<a name="mB0pk"></a>
# 落子方法(绘制棋子)
```javascript
function oneStep(i, j, me) {
// 绘制棋子
ctx.beginPath();
ctx.arc(15+i*30, 15+j*30, 13, 0, 2*Math.PI);
ctx.closePath();
// 判断玩家或AI下棋,更改棋子颜色
let color;
if(me){
color = '#000'
}else {
color = '#fff'
}
// 更改画笔颜色并填充
ctx.fillStyle = color;
ctx.fill()
}
下棋
- 判断玩家是否可以下棋
- 游戏是否结束
- 记录玩家赢法分值
记录AI赢法分值
// 定义所需变量
let me = true; // 标记玩家是否可以下棋
let over = false; // 标记游戏是否结束
let myWin = []; // 记录玩家在赢法上的分值
let computerWin = []; // 记录计算机在赢法上的分值
// 初始化玩家赢法分值与AI赢法分值
for(let i = 0; i < count; i++) {
myWin[i] = 0;
computerWin[i] = 0;
}
// 判断是否点击开始游戏
start.onclick = () => {
if(!flag){
flag = !flag;
start.innerHTML = '重新开始';
}else {
window.location.reload()
}
}
// 点击画板落子 chess.onclick = function(e) { // 如果游戏结束,不可以下棋 if(flag) { if(over) { return; } // 判断玩家是否可以下棋 if(!me) { return; } // 获取 x 轴坐标 let x = e.offsetX; // 获取 y 轴坐标 let y = e.offsetY; let i = Math.floor(x/30); let j = Math.floor(y/30); if(chessboard[i][j] == 0) { // 下一个子 oneStep(i, j, me); chessboard[i][j] = 1; for(let k = 0; k < count; k++) { if(wins[i][j][k]) { myWin[k]++; if(myWin[k] == 5) { title.innerHTML = 'player win!' over = true; } } } } if(!over) { me = !me; // 计算机落子 computerAI(); } // AI落子 function computerAI() { // 空白子在用户所占用赢法上的分值 let myScore = []; // 空白子在计算机所占用赢法上的分值 let computerScore = []; for(let i = 0; i < 15; i++) { myScore[i] = []; computerScore[i] = []; for(let j = 0; j < 15; j++) { myScore[i][j] = 0; computerScore[i][j] = 0; } } // 空白子的最大分值 let max = 0; // 最大分值空白子所在的坐标 let x = 0, y = 0; for(let i = 0; i < 15; i++) { for(let j = 0; j < 15; j++) { // 判断是否是空白子 if(chessboard[i][j] == 0) { for(let 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; } // AI分值 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] += 2200; }else if(computerWin[k] == 4) { computerScore[i][j] += 20000; } } } // 判断玩家最大分值的空白子 if(myScore[i][j] > max) { max = myScore[i][j]; x = i; y = j; }else if(myScore[i][j] == max) { if(computerScore[i][j] > max) { max = computerScore[i][j]; x = i; y = j; } } // 判断AI最大分值的空白子 if(computerScore[i][j] > max) { max = computerScore[i][j]; x = i; y = j; }else if(computerScore[i][j] == max){ if(myScore[i][j] > max) { max = myScore[i][j]; x = i; y = j; } } } } } oneStep(x, y, me); chessboard[x][y] = 1; // 判断计算机是否赢 for(let k = 0; k < count; k++) { if(wins[x][y][k]) { computerWin[k] += 1; if(computerWin[k] == 5) { title.innerHTML = 'AI win!' over = true; } } } if(!over) { me = !me; } } // 落子方法 } }
落子方法
function oneStep(i, j, me) { // 绘制棋子 ctx.beginPath(); ctx.arc(15+i*30, 15+j*30, 13, 0, 2*Math.PI); ctx.closePath(); // 判断玩家或AI下棋,更改棋子颜色 let color; if(me){ color = '#000' }else { color = '#fff' } // 更改画笔颜色并填充 ctx.fillStyle = color; ctx.fill() }