面试题:使用class类来写工个五子棋
核心功能说明
类的结构:
constructor
:初始化画布、棋盘数据(15×15 网格)、当前玩家等。drawBoard
:绘制棋盘网格线。drawPiece
:根据落子位置绘制黑 / 白棋子。initEvent
:绑定鼠标点击事件,计算落子坐标并判断有效性。checkWin
:从当前落子位置向四个方向检查是否有 “五子连珠”。
实现逻辑:
- 棋盘使用二维数组
board
存储状态(0 为空,1 为黑棋,2 为白棋)。 - 点击画布时,通过坐标计算落子位置,合法则更新数组并绘制棋子。
- 每步落子后检查胜负,若满足条件则弹出提示。
- 棋盘使用二维数组
<!DOCTYPE html>
<html><head><title>五子棋</title><style>canvas {border: 2px solid #333;}</style>
</head><body><canvas id="chessboard" width="500" height="500"></canvas><script>class Gomoku {constructor(canvasId, size = 15) {// 初始化画布和上下文this.canvas = document.getElementById(canvasId);this.ctx = this.canvas.getContext('2d');// 棋盘大小(15×15 格)this.size = size;// 格子尺寸(根据画布大小计算)this.cellSize = this.canvas.width / (this.size - 1);// 棋盘数据:0=空,1=黑棋,2=白棋this.board = Array.from({ length: size }, () => Array(size).fill(0));// 当前回合(1=黑棋先行)this.currentPlayer = 1;// 绑定事件this.initEvent();// 绘制棋盘this.drawBoard();}// 绘制棋盘网格drawBoard() {const { ctx, size, cellSize, canvas } = this;// 清空画布ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制横线和竖线for (let i = 0; i < size; i++) {// 横线ctx.beginPath();ctx.moveTo(0, i * cellSize);ctx.lineTo((size - 1) * cellSize, i * cellSize);ctx.stroke();// 竖线ctx.beginPath();ctx.moveTo(i * cellSize, 0);ctx.lineTo(i * cellSize, (size - 1) * cellSize);ctx.stroke();}}// 绘制棋子drawPiece(row, col) {const { ctx, cellSize, board } = this;const x = col * cellSize;const y = row * cellSize;const radius = cellSize / 2 - 2; // 棋子半径(略小于格子一半)ctx.beginPath();ctx.arc(x, y, radius, 0, Math.PI * 2);ctx.fillStyle = board[row][col] === 1 ? '#000' : '#fff';ctx.fill();ctx.strokeStyle = '#000'; // 棋子边框ctx.stroke();}// 初始化点击事件(落子)initEvent() {this.canvas.addEventListener('click', (e) => {const rect = this.canvas.getBoundingClientRect();// 计算点击位置对应的棋盘坐标(行、列)const col = Math.round((e.clientX - rect.left) / this.cellSize);const row = Math.round((e.clientY - rect.top) / this.cellSize);// 检查是否在棋盘范围内且位置为空if (row >= 0 && row < this.size && col >= 0 && col < this.size && this.board[row][col] === 0) {// 落子this.board[row][col] = this.currentPlayer;this.drawPiece(row, col);// 判断胜负if (this.checkWin(row, col)) {alert(`玩家${this.currentPlayer === 1 ? '黑' : '白'}获胜!`);return;}// 切换玩家this.currentPlayer = this.currentPlayer === 1 ? 2 : 1;}});}// 检查胜负(上下、左右、对角线四个方向)checkWin(row, col) {const { board, currentPlayer, size } = this;const directions = [[0, 1], // 水平方向[1, 0], // 垂直方向[1, 1], // 右下对角线[1, -1] // 左下对角线];for (const [dx, dy] of directions) {let count = 1; // 当前位置已有1个棋子// 正向检查for (let i = 1; i < 5; i++) {const r = row + i * dx;const c = col + i * dy;if (r >= 0 && r < size && c >= 0 && c < size && board[r][c] === currentPlayer) {count++;} else break;}// 反向检查for (let i = 1; i < 5; i++) {const r = row - i * dx;const c = col - i * dy;if (r >= 0 && r < size && c >= 0 && c < size && board[r][c] === currentPlayer) {count++;} else break;}// 五子连珠则获胜if (count >= 5) return true;}return false;}}// 初始化游戏new Gomoku('chessboard');</script>
</body></html>