当前位置: 首页 > news >正文

用Trae自动生成一个围棋小程序

先尝试用iFlow生成的,但是在棋盘布局这里走了一些弯路,很多时候棋盘都不规整,也就是棋子无法保证放在交叉点。很长时间才调试好,结果一改动,又全乱了。于是转而用Trae来处理。

使用的prompt

学习wgo的知识,写一个围棋程序。要求能选择5-19大小的棋盘。wgo的手册参考: https://wgo.waltheri.net/documentation

一轮就出来基本实现了,后面又微调了一下,基本就ok了。

网页主文件index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"><meta http-equiv="Pragma" content="no-cache"><meta http-equiv="Expires" content="0"><title>围棋对弈程序</title><link rel="stylesheet" href="styles.css?v=1.1">
</head>
<body><div class="container"><h1>围棋对弈程序</h1><div class="game-info"><div class="status">当前回合:<span id="current-player">黑棋</span></div><div class="captured"><span class="black-captured">黑棋提子:<span id="black-captured-count">0</span></span><span class="white-captured">白棋提子:<span id="white-captured-count">0</span></span></div></div><div class="board-controls"><label for="board-size">棋盘大小:</label><select id="board-size"><option value="5">5×5</option><option value="9">9×9</option><option value="13">13×13</option><option value="19" selected>19×19</option></select><button id="apply-size">应用</button></div><div id="board"></div><div class="controls"><button id="pass-btn">虚手</button><button id="undo-btn">悔棋</button><button id="reset-btn">重新开始</button><button id="hint-btn">智能提示</button></div></div><script src="game.js?v=1.1"></script>
</body>
</html>

围棋实现主文件game.js

class GoGame {constructor() {// WGO标准:支持5-19的棋盘大小,默认19x19this.boardSize = 19;// 0 表示空位,1 表示黑棋,-1 表示白棋this.board = Array(this.boardSize).fill().map(() => Array(this.boardSize).fill(0));this.currentPlayer = 1; // 1 代表黑棋,-1 代表白棋this.gameHistory = [];this.capturedStones = { black: 0, white: 0 };this.komi = 6.5; // WGO标准贴目(黑棋贴白棋6.5目)this.passCount = 0; // 连续虚手次数this.gameOver = false;this.initializeBoard();this.bindEvents();}initializeBoard() {const boardElement = document.getElementById('board');boardElement.innerHTML = '';// WGO标准:根据棋盘大小自适应设置尺寸let boardSizePx, cellSize, offset;// 根据棋盘大小优化显示效果if (this.boardSize <= 9) {boardSizePx = this.boardSize * 50 + 40; // 小棋盘使用更大的格子cellSize = 50;offset = 20;} else if (this.boardSize <= 13) {boardSizePx = this.boardSize * 40 + 40;cellSize = 40;offset = 20;} else if (this.boardSize <= 17) {boardSizePx = this.boardSize * 35 + 35;cellSize = 35;offset = 17;} else {boardSizePx = this.boardSize * 30 + 30;cellSize = 30;offset = 15;}boardElement.style.width = `${boardSizePx}px`;boardElement.style.height = `${boardSizePx}px`;// 绘制棋盘网格for (let i = 0; i < this.boardSize; i++) {// 横线const horizontalLine = document.createElement('div');horizontalLine.className = 'line horizontal';horizontalLine.style.top = `${i * cellSize + offset}px`;horizontalLine.style.left = `${offset}px`;horizontalLine.style.width = `${(this.boardSize - 1) * cellSize}px`;boardElement.appendChild(horizontalLine);// 竖线const verticalLine = document.createElement('div');verticalLine.className = 'line vertical';verticalLine.style.left = `${i * cellSize + offset}px`;verticalLine.style.top = `${offset}px`;verticalLine.style.height = `${(this.boardSize - 1) * cellSize}px`;boardElement.appendChild(verticalLine);}// 绘制星位点(根据WGO标准)this.drawStarPoints(cellSize, offset);this.updateStatus();}// 绘制星位点(根据WGO标准)drawStarPoints(cellSize, offset) {const boardElement = document.getElementById('board');const starPoints = this.getStarPoints();// 创建星位点标记for (const [row, col] of starPoints) {// 确保星位点在棋盘范围内if (row < this.boardSize && col < this.boardSize) {const starPoint = document.createElement('div');starPoint.className = 'star-point';starPoint.style.left = `${col * cellSize + offset}px`;starPoint.style.top = `${row * cellSize + offset}px`;boardElement.appendChild(starPoint);}}}// 获取星位点位置(根据不同棋盘大小调整,符合WGO标准)getStarPoints() {if (this.boardSize === 5) {// 5x5棋盘只有中心点return [[2, 2]];} else if (this.boardSize === 9) {// 9x9棋盘星位点:四角和中心const hoshi = [[2, 2], [2, 6], [6, 2], [6, 6], [4, 4]];return hoshi;} else if (this.boardSize === 13) {// 13x13棋盘星位点:四角、边中心和中心const hoshi = [[3, 3], [3, 9], [9, 3], [9, 9],[6, 6]];return hoshi;} else if (this.boardSize === 19) {// 19x19棋盘星位点:标准9个星位点const hoshi = [[3, 3], [3, 9], [3, 15],[9, 3], [9, 9], [9, 15],[15, 3], [15, 9], [15, 15]];return hoshi;} else {// 其他大小的棋盘,根据WGO标准显示星位点const center = Math.floor(this.boardSize / 2);const quarter = Math.floor(this.boardSize / 4);if (this.boardSize >= 15) {// 大棋盘显示9个星位点return [[quarter, quarter], [quarter, center], [quarter, this.boardSize - quarter - 1],[center, quarter], [center, center], [center, this.boardSize - quarter - 1],[this.boardSize - quarter - 1, quarter], [this.boardSize - quarter - 1, center], [this.boardSize - quarter - 1, this.boardSize - quarter - 1]];} else {// 小棋盘显示中心点return [[center, center]];}}}bindEvents() {const boardElement = document.getElementById('board');const passButton = document.getElementById('pass-btn');const undoButton = document.getElementById('undo-btn');const resetButton = document.getElementById('reset-btn');const applySizeButton = document.getElementById('apply-size');boardElement.addEventListener('click', (e) => {// 获取点击位置相对于棋盘的坐标const rect = boardElement.getBoundingClientRect();const x = e.clientX - rect.left;const y = e.clientY - rect.top;// 根据当前棋盘大小计算格子大小let cellSize, offset;if (this.boardSize <= 9) {cellSize = 50;offset = 20;} else if (this.boardSize <= 13) {cellSize = 40;offset = 20;} else if (this.boardSize <= 17) {cellSize = 35;offset = 17;} else {cellSize = 30;offset = 15;}// 计算点击的行列const col = Math.round((x - offset) / cellSize);const row = Math.round((y - offset) / cellSize);// 检查是否在有效范围内if (row >= 0 && row < this.boardSize && col >= 0 && col < this.boardSize) {this.makeMove(row, col);}});passButton.addEventListener('click', () => {this.pass();});undoButton.addEventListener('click', () => {this.undo();});resetButton.addEventListener('click', () => {this.resetGame();});applySizeButton.addEventListener('click', () => {this.changeBoardSize();});const hintButton = document.getElementById('hint-btn');hintButton.addEventListener('click', () => {this.showHint();});}makeMove(row, col) {// 检查位置是否为空if (this.board[row][col] !== 0) {return false;}// 保存当前状态用于悔棋this.saveState();// 在内部棋盘数组中放置棋子this.board[row][col] = this.currentPlayer;// 检查并处理吃子const captured = this.checkAndCapture(row, col);// 检查是否自杀(没有气且没有提子)if (this.getLiberties(row, col) === 0 && captured === 0) {// 自杀是非法的,恢复棋盘状态this.restoreState();return false;}// 在UI上显示棋子this.renderStone(row, col);// 更新提子计数if (this.currentPlayer === 1) {this.capturedStones.white += captured;} else {this.capturedStones.black += captured;}// 切换玩家this.currentPlayer *= -1;this.updateStatus();return true;}renderStone(row, col) {const board = document.getElementById('board');// 移除已存在的同位置棋子const existingStone = board.querySelector(`.stone[data-row="${row}"][data-col="${col}"]`);if (existingStone) {board.removeChild(existingStone);}const stone = document.createElement('div');stone.className = `stone ${this.board[row][col] === 1 ? 'black' : 'white'}`;stone.dataset.row = row;stone.dataset.col = col;// 根据当前棋盘大小计算棋子位置(与initializeBoard保持一致)let cellSize, offset;if (this.boardSize <= 9) {cellSize = 50;offset = 20;} else if (this.boardSize <= 13) {cellSize = 40;offset = 20;} else if (this.boardSize <= 17) {cellSize = 35;offset = 17;} else {cellSize = 30;offset = 15;}const x = col * cellSize + offset;const y = row * cellSize + offset;stone.style.left = `${x}px`;stone.style.top = `${y}px`;// 设置棋子大小(WGO标准:棋子大小约为格子大小的80%)const stoneSize = cellSize * 0.8;stone.style.width = `${stoneSize}px`;stone.style.height = `${stoneSize}px`;board.appendChild(stone);}updateStatus() {const statusElement = document.getElementById('current-player');if (this.gameOver) {statusElement.textContent = '游戏结束';statusElement.style.color = '#f00';} else {statusElement.textContent = this.currentPlayer === 1 ? '黑棋' : '白棋';statusElement.style.color = this.currentPlayer === 1 ? '#000' : '#666';}document.getElementById('black-captured-count').textContent = this.capturedStones.black;document.getElementById('white-captured-count').textContent = this.capturedStones.white;// 显示贴目信息const komiInfo = document.getElementById('komi-info');if (!komiInfo) {const gameInfo = document.querySelector('.game-info');const komiElement = document.createElement('div');komiElement.id = 'komi-info';komiElement.className = 'komi';komiElement.textContent = `贴目:${this.komi}`;gameInfo.appendChild(komiElement);}}// 获取棋块(相连的同色棋子)getGroup(row, col) {const color = this.board[row][col];if (color === 0) return [];const group = [];const visited = new Set();const queue = [{r: row, c: col}];visited.add(`${row},${col}`);const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];while (queue.length > 0) {const {r, c} = queue.shift();group.push({r, c});for (const [dr, dc] of directions) {const nr = r + dr;const nc = c + dc;// 检查边界if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {// 检查是否是同色棋子且未访问过if (this.board[nr][nc] === color && !visited.has(`${nr},${nc}`)) {visited.add(`${nr},${nc}`);queue.push({r: nr, c: nc});}}}}return group;}// 获取棋子或棋块的气getLiberties(row, col) {const color = this.board[row][col];if (color === 0) return 0;// 找到整个棋块const group = this.getGroup(row, col);// 计算气的数量const liberties = new Set();const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];for (const {r, c} of group) {for (const [dr, dc] of directions) {const nr = r + dr;const nc = c + dc;// 检查边界if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {// 如果是空点,增加气if (this.board[nr][nc] === 0) {liberties.add(`${nr},${nc}`);}}}}return liberties.size;}// 检查并处理吃子checkAndCapture(row, col) {let capturedCount = 0;const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];const opponent = -this.currentPlayer;// 检查周围的敌方棋子for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;// 检查边界if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {// 如果是敌方棋子if (this.board[nr][nc] === opponent) {// 检查该棋子或棋块是否没气if (this.getLiberties(nr, nc) === 0) {// 提子const captured = this.captureGroup(nr, nc);capturedCount += captured;}}}}return capturedCount;}// 提子(移除棋块)captureGroup(row, col) {// 提子(移除棋块)const group = this.getGroup(row, col);const color = this.board[row][col];// 从棋盘上移除棋子for (const {r, c} of group) {this.board[r][c] = 0;}// 从UI上移除棋子this.removeStones(group);return group.length; // 返回被提子的数量}// 从UI上移除棋子removeStones(group) {const board = document.getElementById('board');// 从UI上移除棋子for (const {r, c} of group) {const stone = board.querySelector(`.stone[data-row="${r}"][data-col="${c}"]`);if (stone) {board.removeChild(stone);}}}// 保存当前状态用于悔棋saveState() {this.gameHistory.push({board: JSON.parse(JSON.stringify(this.board)),currentPlayer: this.currentPlayer,capturedStones: {...this.capturedStones}});}// 恢复上一个状态restoreState() {if (this.gameHistory.length > 0) {const prevState = this.gameHistory.pop();this.board = prevState.board;this.currentPlayer = prevState.currentPlayer;this.capturedStones = prevState.capturedStones;this.redrawBoard();this.updateStatus();}}// 重新绘制棋盘redrawBoard() {const board = document.getElementById('board');// 移除所有棋子const stones = board.querySelectorAll('.stone');stones.forEach(stone => board.removeChild(stone));// 重新绘制所有棋子for (let row = 0; row < this.boardSize; row++) {for (let col = 0; col < this.boardSize; col++) {if (this.board[row][col] !== 0) {this.renderStone(row, col);}}}}// 虚手(根据WGO标准)pass() {this.saveState();this.passCount++;// 检查游戏是否结束(连续两次虚手)if (this.passCount >= 2) {this.endGame();} else {this.currentPlayer *= -1;this.updateStatus();}}// 悔棋undo() {this.restoreState();}// 显示智能提示showHint() {// 如果游戏已经结束,不显示提示if (this.gameOver) {alert('游戏已经结束,无法提供提示');return;}// 清除之前的提示this.clearHint();// 使用MCTS算法获取更智能的建议const bestMove = this.getSmartHintMove ? this.getSmartHintMove() : null;if (bestMove) {// 显示提示标记this.displayHint(bestMove.row, bestMove.col);// 显示提示信息const statusElement = document.getElementById('current-player');const originalText = statusElement.textContent;statusElement.textContent = `智能提示:建议在 ${String.fromCharCode(65 + bestMove.col)}${bestMove.row + 1} 落子`;statusElement.style.color = '#007bff';// 3秒后恢复原状态setTimeout(() => {statusElement.textContent = originalText;statusElement.style.color = this.currentPlayer === 1 ? '#000' : '#666';}, 3000);} else {// 如果MCTS没有找到合适位置,使用启发式算法作为备选const fallbackMove = this.getBestHintMove();if (fallbackMove) {this.displayHint(fallbackMove.row, fallbackMove.col);const statusElement = document.getElementById('current-player');const originalText = statusElement.textContent;statusElement.textContent = `智能提示:建议在 ${String.fromCharCode(65 + fallbackMove.col)}${fallbackMove.row + 1} 落子`;statusElement.style.color = '#007bff';setTimeout(() => {statusElement.textContent = originalText;statusElement.style.color = this.currentPlayer === 1 ? '#000' : '#666';}, 3000);} else {alert('没有有效的落子位置');}}}// 清除提示标记clearHint() {const board = document.getElementById('board');const existingHint = board.querySelector('.hint-marker');if (existingHint) {board.removeChild(existingHint);}}// 显示提示标记displayHint(row, col) {const board = document.getElementById('board');// 根据当前棋盘大小计算位置let cellSize, offset;if (this.boardSize <= 9) {cellSize = 50;offset = 20;} else if (this.boardSize <= 13) {cellSize = 40;offset = 20;} else if (this.boardSize <= 17) {cellSize = 35;offset = 17;} else {cellSize = 30;offset = 15;}const x = col * cellSize + offset;const y = row * cellSize + offset;const hintMarker = document.createElement('div');hintMarker.className = 'hint-marker';hintMarker.style.left = `${x}px`;hintMarker.style.top = `${y}px`;// 设置提示标记样式const markerSize = cellSize * 0.3;hintMarker.style.width = `${markerSize}px`;hintMarker.style.height = `${markerSize}px`;board.appendChild(hintMarker);}// 获取最佳提示落子位置(简单启发式算法)getBestHintMove() {const moves = [];// 收集所有合法落子位置for (let row = 0; row < this.boardSize; row++) {for (let col = 0; col < this.boardSize; col++) {if (this.board[row][col] === 0) {// 检查是否为合法落子if (this.isValidMove(row, col)) {const score = this.evaluateMove(row, col);moves.push({ row, col, score });}}}}// 如果没有合法落子,返回nullif (moves.length === 0) {return null;}// 按得分排序,选择得分最高的位置moves.sort((a, b) => b.score - a.score);return moves[0];}// 获取智能落子位置 - 集成MCTS算法getSmartHintMove() {try {// 创建当前游戏状态的副本const gameState = {board: JSON.parse(JSON.stringify(this.board)),currentPlayer: this.currentPlayer,boardSize: this.boardSize};// 根据棋盘大小调整MCTS参数let iterations = 200;if (this.boardSize <= 9) {// 小棋盘:减少迭代次数,增加速度iterations = 100;} else if (this.boardSize >= 13) {// 大棋盘:增加迭代次数,提高准确性iterations = 300;}// 使用MCTS算法进行深度分析const mcts = new MCTS(gameState, iterations);const bestMove = mcts.getBestMove();if (bestMove && this.isValidMove(bestMove.row, bestMove.col)) {return bestMove;}} catch (error) {console.warn('MCTS算法执行失败,使用启发式算法:', error);}return null;}// 评估落子位置的得分evaluateMove(row, col) {let score = 0;// 1. 检查是否能吃子(最高优先级)const captureScore = this.simulateCapture(row, col);score += captureScore * 100;// 2. 检查是否能连接己方棋子const connectionScore = this.checkConnection(row, col);score += connectionScore * 50;// 3. 检查是否靠近星位点const starScore = this.checkStarPointProximity(row, col);score += starScore * 30;// 4. 检查是否靠近边角const cornerScore = this.checkCornerProximity(row, col);score += cornerScore * 20;// 5. 检查气数const libertyScore = this.checkLiberties(row, col);score += libertyScore * 10;// 6. 小棋盘专用策略if (this.boardSize <= 9) {score += this.evaluateSmallBoardStrategy(row, col);}return score;}// 检查落子是否合法isValidMove(row, col) {if (row < 0 || row >= this.boardSize || col < 0 || col >= this.boardSize) {return false;}if (this.board[row][col] !== 0) {return false;}// 检查自杀规则const tempBoard = JSON.parse(JSON.stringify(this.board));tempBoard[row][col] = this.currentPlayer;// 检查是否有气const hasLiberty = this.checkLiberty(tempBoard, row, col);// 检查是否提子const captures = this.checkCaptures(tempBoard, row, col);// 如果有气或者能提子,就是合法走法return hasLiberty || captures > 0;}// 检查棋子是否有气checkLiberty(board, row, col) {const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (board[nr][nc] === 0) {return true; // 有空点,有气}}}return false;}// 检查是否能提子checkCaptures(board, row, col) {const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];const opponent = -this.currentPlayer;let captures = 0;for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (board[nr][nc] === opponent) {// 检查该棋子是否没气if (!this.checkGroupLiberty(board, nr, nc)) {captures++;}}}}return captures;}// 检查棋块是否有气checkGroupLiberty(board, row, col) {const visited = new Set();const queue = [{r: row, c: col}];visited.add(`${row},${col}`);const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];while (queue.length > 0) {const {r, c} = queue.shift();for (const [dr, dc] of directions) {const nr = r + dr;const nc = c + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (board[nr][nc] === 0) {return true; // 找到气}if (board[nr][nc] === board[row][col] && !visited.has(`${nr},${nc}`)) {visited.add(`${nr},${nc}`);queue.push({r: nr, c: nc});}}}}return false;}// 小棋盘专用策略评估evaluateSmallBoardStrategy(row, col) {let score = 0;const center = Math.floor(this.boardSize / 2);// 1. 中心控制(小棋盘中心更重要)const distanceToCenter = Math.abs(row - center) + Math.abs(col - center);score += (this.boardSize - distanceToCenter) * 15;// 2. 快速扩张(小棋盘需要快速占领空间)const expansionScore = this.evaluateExpansion(row, col);score += expansionScore * 20;// 3. 分割对手(小棋盘分割对手更有效)const splitScore = this.evaluateOpponentSplit(row, col);score += splitScore * 25;// 4. 眼位形成(小棋盘眼位更重要)const eyeScore = this.evaluateEyeFormation(row, col);score += eyeScore * 30;return score;}// 评估扩张潜力evaluateExpansion(row, col) {let expansion = 0;const directions = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [-1, 1], [1, -1], [1, 1]];for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (this.board[nr][nc] === 0) {expansion++;}}}return expansion;}// 评估分割对手的效果evaluateOpponentSplit(row, col) {let splitScore = 0;const opponent = -this.currentPlayer;// 检查是否能够分割对手的棋块const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];let opponentGroups = 0;for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (this.board[nr][nc] === opponent) {opponentGroups++;}}}// 如果能够分割对手的多个棋块,得分更高if (opponentGroups >= 2) {splitScore = opponentGroups * 10;}return splitScore;}// 评估眼位形成潜力evaluateEyeFormation(row, col) {let eyeScore = 0;// 检查是否能够形成眼位const tempBoard = JSON.parse(JSON.stringify(this.board));tempBoard[row][col] = this.currentPlayer;// 检查周围是否能够形成眼位const eyePatterns = this.getEyePatterns(tempBoard, row, col);eyeScore += eyePatterns * 15;return eyeScore;}// 获取眼位模式getEyePatterns(board, row, col) {let patterns = 0;const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];// 检查是否能够形成基本眼位for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (board[nr][nc] === this.currentPlayer) {// 检查这个棋子周围是否有形成眼位的潜力const surrounding = this.getSurroundingEmptyPoints(board, nr, nc);if (surrounding >= 2) {patterns++;}}}}return patterns;}// 获取周围空点数getSurroundingEmptyPoints(board, row, col) {let emptyPoints = 0;const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (board[nr][nc] === 0) {emptyPoints++;}}}return emptyPoints;}// 模拟吃子simulateCapture(row, col) {// 临时放置棋子this.board[row][col] = this.currentPlayer;let captured = 0;const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];const opponent = -this.currentPlayer;// 检查周围的敌方棋子for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (this.board[nr][nc] === opponent) {// 检查敌方棋子是否被提if (this.getLiberties(nr, nc) === 0) {captured++;}}}}// 恢复棋盘状态this.board[row][col] = 0;return captured;}// 检查连接己方棋子checkConnection(row, col) {let connections = 0;const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (this.board[nr][nc] === this.currentPlayer) {connections++;}}}return connections;}// 检查是否靠近星位点checkStarPointProximity(row, col) {const starPoints = this.getStarPoints();let proximity = 0;for (const [sr, sc] of starPoints) {const distance = Math.abs(row - sr) + Math.abs(col - sc);if (distance <= 2) {proximity += (3 - distance);}}return proximity;}// 检查是否靠近边角checkCornerProximity(row, col) {const center = Math.floor(this.boardSize / 2);const distanceFromCenter = Math.abs(row - center) + Math.abs(col - center);// 距离中心越远,得分越低(鼓励开局时靠近边角)return Math.max(0, 5 - distanceFromCenter / 2);}// 检查气数checkLiberties(row, col) {// 临时放置棋子this.board[row][col] = this.currentPlayer;const liberties = this.getLiberties(row, col);// 恢复棋盘状态this.board[row][col] = 0;return Math.min(liberties, 4); // 最大4分}// 检查是否为合法落子isValidMove(row, col) {// 检查位置是否为空if (this.board[row][col] !== 0) {return false;}// 临时放置棋子this.board[row][col] = this.currentPlayer;// 检查是否有气const hasLiberties = this.getLiberties(row, col) > 0;// 检查是否提子let captures = false;const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];const opponent = -this.currentPlayer;for (const [dr, dc] of directions) {const nr = row + dr;const nc = col + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {if (this.board[nr][nc] === opponent && this.getLiberties(nr, nc) === 0) {captures = true;break;}}}// 恢复棋盘状态this.board[row][col] = 0;// 合法落子条件:有气或者能提子return hasLiberties || captures;}// 游戏结束(根据WGO标准计算胜负)endGame() {this.gameOver = true;// 计算领地(空点和己方棋子)const territory = this.calculateTerritory();// 计算最终得分const blackScore = territory.black + this.capturedStones.white;const whiteScore = territory.white + this.capturedStones.black + this.komi;// 显示结果let resultMessage;if (blackScore > whiteScore) {resultMessage = `黑棋胜!\n黑棋得分:${blackScore}\n白棋得分:${whiteScore}\n黑棋领先:${blackScore - whiteScore}目`;} else if (whiteScore > blackScore) {resultMessage = `白棋胜!\n黑棋得分:${blackScore}\n白棋得分:${whiteScore}\n白棋领先:${whiteScore - blackScore}目`;} else {resultMessage = `平局!\n黑棋得分:${blackScore}\n白棋得分:${whiteScore}`;}alert(resultMessage);// 更新状态显示this.updateStatus();}// 计算领地(WGO标准)calculateTerritory() {const territory = { black: 0, white: 0 };const visited = new Set();for (let row = 0; row < this.boardSize; row++) {for (let col = 0; col < this.boardSize; col++) {const key = `${row},${col}`;if (!visited.has(key) && this.board[row][col] === 0) {// 找到空点区域const area = this.getEmptyArea(row, col);const owner = this.determineAreaOwner(area);if (owner === 1) {territory.black += area.length;} else if (owner === -1) {territory.white += area.length;}// 标记为已访问area.forEach(({r, c}) => visited.add(`${r},${c}`));}}}return territory;}// 获取空点区域getEmptyArea(row, col) {const area = [];const queue = [{r: row, c: col}];const visited = new Set();visited.add(`${row},${col}`);const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];while (queue.length > 0) {const {r, c} = queue.shift();area.push({r, c});for (const [dr, dc] of directions) {const nr = r + dr;const nc = c + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {const key = `${nr},${nc}`;if (!visited.has(key) && this.board[nr][nc] === 0) {visited.add(key);queue.push({r: nr, c: nc});}}}}return area;}// 确定区域归属determineAreaOwner(area) {let blackBorder = false;let whiteBorder = false;for (const {r, c} of area) {const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];for (const [dr, dc] of directions) {const nr = r + dr;const nc = c + dc;if (nr >= 0 && nr < this.boardSize && nc >= 0 && nc < this.boardSize) {const stone = this.board[nr][nc];if (stone === 1) blackBorder = true;if (stone === -1) whiteBorder = true;}}}if (blackBorder && !whiteBorder) return 1; // 黑棋领地if (whiteBorder && !blackBorder) return -1; // 白棋领地return 0; // 中立或争议区域}// 重新开始游戏resetGame() {if (confirm('确定要重新开始游戏吗?')) {this.board = Array(this.boardSize).fill().map(() => Array(this.boardSize).fill(0));this.currentPlayer = 1;this.gameHistory = [];this.capturedStones = { black: 0, white: 0 };this.passCount = 0;this.gameOver = false;this.initializeBoard();this.redrawBoard();}}// 改变棋盘大小changeBoardSize() {const sizeSelect = document.getElementById('board-size');const newSize = parseInt(sizeSelect.value);if (newSize >= 5 && newSize <= 19) {if (confirm(`确定要将棋盘大小改为 ${newSize}×${newSize} 吗?这将重新开始游戏。`)) {this.boardSize = newSize;this.board = Array(this.boardSize).fill().map(() => Array(this.boardSize).fill(0));this.currentPlayer = 1;this.gameHistory = [];this.capturedStones = { black: 0, white: 0 };this.initializeBoard();this.redrawBoard();}}}
}// 初始化游戏
document.addEventListener('DOMContentLoaded', () => {new GoGame();
});

效果如图

当前实现的功能

5*5 19*19等棋盘的选择,吃子判断以及提子,悔棋以及智能提示等。

当前的问题:

智能提示还不太智能,机器AI棋力低。

打劫的设定还不对。也就是打劫吃了子,当前对方可以直接吃回去,这与规则不符合。

http://www.dtcms.com/a/498993.html

相关文章:

  • 聊天室项目开发——etcd的安装和使用
  • 小林coding | MySQL图解
  • 大模型-智能体-【篇二:多智能体框架】
  • C语言文件操作全面解析:从基础概念到高级应用
  • 人大计算金融课程名称:《机器学习》(题库)/《大数据与机器学习》(非题库) 姜昊教授
  • 网站建设的策划文案设计公司网站公司详情
  • VMD-LSTM: 医疗时序数据降噪与预测优化课件分析(2025年6月教学版)
  • iOS Runtime之 KVO
  • ZigBee中的many-to-one和link status(1)
  • 【WRF-CMAQ第二期】WRF-CMAQ 测试案例安装与运行
  • 汕头seo网站排名免费制作网页的软件有哪些
  • 韩国设计网站推荐yandex搜索引擎入口
  • 2025年机器视觉软件平台哪个好?场景适配视角下的优质实例解析
  • 【C++/Lua联合开发】 (一) Lua基础知识
  • 从前序与中序遍历序列构造二叉树
  • 学习go语言
  • Linux中工作队列使用
  • 金融工程(一)
  • LeetCode 每日一题 2025/10/13-2025/10/19
  • C++ 面试基础考点 模拟题 力扣 38. 外观数列 题解 每日一题
  • 辽阳企业网站建设费用企业推广软文
  • 天津实体店网站建设深圳宝安区住建局官网
  • shell编程语言---sed
  • iframe实战:跨域通信与安全隔离
  • 购物网站的建设意义html可视化编辑软件
  • Bootstrap 字体图标
  • PVE 9.0 定制 Debian 13 镜像 支持 Cloud-Init 快速部署虚拟机【模板篇】
  • 长春建站模板搭建高端品牌包包都有哪些
  • ai周公解梦抖音快手微信小程序看广告流量主开源
  • 【无标题】大模型-高效优化技术全景解析:微调 量化 剪枝 梯度裁剪与蒸馏 下