最强五子棋游戏
Created on: March 5, 2025
Answered using Deep Research by Chat01
Created on: March 5, 2025
Answered using Deep Research by Chat01
尽你最大的努力给我弄个最强的在线五子棋游戏出来。
请确认您需要的是以下哪种信息:
请告诉我您的具体需求,或者如果有其他要求也请补充说明!
你需要开发一个可以直接玩的在线五子棋游戏出来,包含完整的html,css,js,需要有不同的AI等级,越厉害越好
我将开发一个完整的在线五子棋游戏,包括HTML、CSS和JavaScript,实现不同等级的AI对手,AI的强度将尽可能优化。这个游戏将支持玩家与AI对战,AI会采用不同难度的策略,包括基础规则引擎、Minimax算法和蒙特卡洛树搜索(MCTS)等方式。
我会在开发完成后提供完整的代码,并确保它可以直接运行,让你可以轻松体验。
请稍等,我会尽快完成开发!
以下是一个完整的五子棋在线游戏实现,包含 HTML、CSS 和 JavaScript 代码。代码包括简单AI(随机下子)、中级AI(Minimax 算法 + Alpha-Beta 剪枝)和高级AI(蒙特卡洛树搜索MCTS)的实现,可直接复制运行:
html<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <title>五子棋游戏</title> <style> body { background: #f0f0f0; font-family: Arial, sans-serif; text-align: center; margin: 0; padding: 20px; } h1 { margin-bottom: 10px; } #gameContainer { display: inline-block; } /* 棋盘样式 */ #board { display: grid; grid-template: repeat(15, 40px) / repeat(15, 40px); margin: 20px auto; border: 2px solid #333; } .cell { width: 40px; height: 40px; background: #daa520; /* 木质背景色 */ border: 1px solid #555; box-sizing: border-box; cursor: pointer; position: relative; } .cell::after { /* 棋子样式: 使用伪元素绘制圆形棋子 */ content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 30px; height: 30px; border-radius: 50%; } .black::after { background: #000; /* 黑棋 */ } .white::after { background: #fff; border: 1px solid #000; /* 白棋,描边黑色边框 */ } /* 控制面板样式 */ #controls { margin-top: 10px; } select, button { font-size: 16px; padding: 5px 10px; margin: 0 5px; } #status { font-weight: bold; margin-top: 15px; min-height: 1.5em; } </style> </head> <body> <h1>五子棋游戏</h1> <div id="gameContainer"> <!-- 控制面板 --> <div id="controls"> 难度: <select id="aiLevel"> <option value="easy">简单</option> <option value="medium">中级</option> <option value="hard">高级</option> </select> <button id="restartBtn">重新开始</button> </div> <!-- 棋盘 --> <div id="board"></div> <!-- 状态栏 --> <div id="status"></div> </div> <script> // 五子棋游戏实现 const SIZE = 15; // 棋盘大小 15x15 const EMPTY = 0; const HUMAN = 1; // 玩家 (黑棋) const AI = 2; // AI (白棋) let board = []; // 二维数组表示棋盘状态 let currentPlayer = HUMAN; // 当前落子方,黑棋先手 let gameOver = false; let aiDifficulty = 'easy'; // 默认AI难度 // 初始化棋盘UI和数据结构 const boardElem = document.getElementById('board'); const statusElem = document.getElementById('status'); function initBoard() { boardElem.innerHTML = ''; board = []; for (let r = 0; r < SIZE; r++) { board[r] = []; for (let c = 0; c < SIZE; c++) { board[r][c] = EMPTY; const cell = document.createElement('div'); cell.className = 'cell'; cell.dataset.row = r; cell.dataset.col = c; // 点击事件:玩家下子 cell.addEventListener('click', () => handlePlayerMove(r, c)); boardElem.appendChild(cell); } } // CSS Grid 布局已经在样式中定义为15行15列的网格 } // 重置游戏 function resetGame() { gameOver = false; currentPlayer = HUMAN; statusElem.textContent = "轮到您下棋 (黑棋)"; initBoard(); } // 检查胜利(是否有五子连线) function checkWin(r, c, player) { // 检查 (r,c) 处放下 player 的棋子后,是否形成五连珠 const directions = [ { dr: 0, dc: 1 }, // 水平 { dr: 1, dc: 0 }, // 垂直 { dr: 1, dc: 1 }, // 斜下 { dr: 1, dc: -1 } // 斜上 ]; for (let {dr, dc} of directions) { let count = 1; // 向一个方向计数 let rr = r + dr, cc = c + dc; while (rr >= 0 && rr < SIZE && cc >= 0 && cc < SIZE && board[rr][cc] === player) { count++; rr += dr; cc += dc; } // 反向计数 rr = r - dr; cc = c - dc; while (rr >= 0 && rr < SIZE && cc >= 0 && cc < SIZE && board[rr][cc] === player) { count++; rr -= dr; cc -= dc; } if (count >= 5) { return true; } } return false; } // 获取可下子的列表,用于AI决策(只考虑已有棋子附近,提高效率) function getValidMoves() { const moves = new Set(); let hasPiece = false; for (let r = 0; r < SIZE; r++) { for (let c = 0; c < SIZE; c++) { if (board[r][c] !== EMPTY) { hasPiece = true; // 将 (r,c) 周围一圈的空位加入候选 for (let dr = -1; dr <= 1; dr++) { for (let dc = -1; dc <= 1; dc++) { if (dr === 0 && dc === 0) continue; const nr = r + dr, nc = c + dc; if (nr >= 0 && nr < SIZE && nc >= 0 && nc < SIZE && board[nr][nc] === EMPTY) { moves.add(nr + "," + nc); } } } } } } if (!hasPiece) { // 棋盘无子时,默认推荐中心点为首步 const mid = Math.floor(SIZE / 2); return [[mid, mid]]; } // 将字符串形式转回坐标数组 return Array.from(moves).map(str => str.split(',').map(Number)); } // 简单AI:随机选择一个可用位置下子 function aiMoveEasy() { const moves = getValidMoves(); if (moves.length === 0) return null; const idx = Math.floor(Math.random() * moves.length); return moves[idx]; // 返回 [r, c] } // 中级AI:Minimax算法 + Alpha-Beta 剪枝 function aiMoveMedium() { let bestScore = -Infinity; let bestMove = null; const moves = getValidMoves(); // 优先检查:如果有直接获胜或需要堵截对手获胜的一步棋 for (let [r, c] of moves) { // 检测AI直接获胜一步 board[r][c] = AI; if (checkWin(r, c, AI)) { board[r][c] = EMPTY; return [r, c]; // 立即返回这一 winning move } board[r][c] = EMPTY; } for (let [r, c] of moves) { // 检测对手(玩家)是否有一步制胜,若有则堵截 board[r][c] = HUMAN; if (checkWin(r, c, HUMAN)) { board[r][c] = EMPTY; return [r, c]; // 在此位置下子堵截 } board[r][c] = EMPTY; } // 启动Minimax搜索 const depth = 3; // 搜索深度,可根据需要调整 function minimax(depth, alpha, beta, maximizing) { // 终止条件:达到最大深度或游戏结束 // 检查胜利状态评分 // (如果某一方已五连珠,则返回极端分值) // 注意:这里评估函数以AI为正分,玩家为负分 let evalScore = evaluateBoard(); if (Math.abs(evalScore) >= 100000 || depth === 0) { return evalScore; } if (maximizing) { let maxEval = -Infinity; const moves = getValidMoves(); for (let [r, c] of moves) { board[r][c] = AI; // 如果这一步使AI赢,直接返回极大值 if (checkWin(r, c, AI)) { board[r][c] = EMPTY; return 1000000; // 非常大的分数表示胜利 } const eval = minimax(depth - 1, alpha, beta, false); board[r][c] = EMPTY; if (eval > maxEval) maxEval = eval; if (eval > alpha) alpha = eval; if (beta <= alpha) break; // Alpha-Beta 剪枝 } return maxEval; } else { let minEval = Infinity; const moves = getValidMoves(); for (let [r, c] of moves) { board[r][c] = HUMAN; // 如果这一步使人类赢,直接返回极小值 if (checkWin(r, c, HUMAN)) { board[r][c] = EMPTY; return -1000000; // 非常小的分数表示AI败局 } const eval = minimax(depth - 1, alpha, beta, true); board[r][c] = EMPTY; if (eval < minEval) minEval = eval; if (eval < beta) beta = eval; if (beta <= alpha) break; } return minEval; } } // 简单评估函数:评估当前棋盘对AI的分数 function evaluateBoard() { let score = 0; // 遍历所有方向,计算连珠的评分 const directions = [ { dr: 0, dc: 1 }, // 水平 { dr: 1, dc: 0 }, // 垂直 { dr: 1, dc: 1 }, // 斜下 { dr: 1, dc: -1 } // 斜上 ]; // 扫描每个方向上的连珠情况 for (let {dr, dc} of directions) { for (let r = 0; r < SIZE; r++) { for (let c = 0; c < SIZE; c++) { if (board[r][c] === EMPTY) continue; // 确认当前棋子为序列的起点(前一个位置不是同色棋子) const player = board[r][c]; const prevR = r - dr, prevC = c - dc; if (prevR >= 0 && prevR < SIZE && prevC >= 0 && prevC < SIZE && board[prevR][prevC] === player) { continue; // 如果前一个位置同色,则不是起点,跳过 } // 计算连续相同棋子数 let length = 1; let rr = r + dr, cc = c + dc; while (rr >= 0 && rr < SIZE && cc >= 0 && cc < SIZE && board[rr][cc] === player) { length++; rr += dr; cc += dc; } // 计算该序列两端是否开放 let openEnds = 0; // 序列前端 if (prevR >= 0 && prevR < SIZE && prevC >= 0 && prevC < SIZE && board[prevR][prevC] === EMPTY) { openEnds++; } // 序列末端 if (rr >= 0 && rr < SIZE && cc >= 0 && cc < SIZE && board[rr][cc] === EMPTY) { openEnds++; } if (length >= 5) { // 五连及以上在checkWin中已处理,这里额外加分可以略过 // 确保AI不会在评估中错过胜利 if (player === AI) { score += 100000; // 大分 } else { score -= 100000; } } else if (length === 4) { if (openEnds > 0) { // 至少一端开放 if (player === AI) score += 10000; else score -= 10000; } } else if (length === 3) { if (openEnds === 2) { if (player === AI) score += 5000; else score -= 5000; } else if (openEnds === 1) { if (player === AI) score += 1000; else score -= 1000; } } else if (length === 2) { if (openEnds === 2) { if (player === AI) score += 100; else score -= 100; } else if (openEnds === 1) { if (player === AI) score += 10; else score -= 10; } } } } } return score; } // 遍历可能走法,选择评分最高的 for (let [r, c] of moves) { board[r][c] = AI; const moveScore = minimax(depth - 1, -Infinity, Infinity, false); board[r][c] = EMPTY; if (moveScore > bestScore) { bestScore = moveScore; bestMove = [r, c]; } } return bestMove; } // 高级AI:蒙特卡洛树搜索(MCTS)简化实现 function aiMoveHard() { const moves = getValidMoves(); let bestMove = null; let bestWinRate = -1; const simulationsPerMove = 30; // 每个候选位置进行模拟的次数,可调整 for (let [r, c] of moves) { let wins = 0; let draws = 0; // 模拟若干次随机对局 for (let sim = 0; sim < simulationsPerMove; sim++) { // 复制当前棋盘状态 const boardCopy = board.map(row => row.slice()); boardCopy[r][c] = AI; // AI尝试此步 if (simulateRandomGame(boardCopy, HUMAN)) { // 执行随机模拟,返回true表示AI最终胜利 wins++; } // (这里不专门统计平局,对胜率影响较小,也可根据需要记录) } const winRate = wins / simulationsPerMove; if (winRate > bestWinRate) { bestWinRate = winRate; bestMove = [r, c]; } } return bestMove; } // 随机模拟游戏直到结束(用于MCTS) // 返回true如果AI获胜,false如果平局或玩家获胜 function simulateRandomGame(boardState, currentTurn) { // 随机走子直到有胜者或棋盘填满 let movesList; let moveCount = 0; while (true) { movesList = []; // 获取当前棋盘所有可下子位置(采用邻近策略以加速模拟) for (let r = 0; r < SIZE; r++) { for (let c = 0; c < SIZE; c++) { if (boardState[r][c] === EMPTY) { // 若棋盘上已有子,则要求此空位附近有棋子 if (!hasNeighbor(boardState, r, c) && moveCount < 1) { // 若棋局刚开始(moveCount小),允许第一步下在中心 continue; } if (!hasNeighbor(boardState, r, c) && moveCount >= 1) { continue; } movesList.push([r, c]); } } } if (movesList.length === 0) { return false; // 无可下子位置 -> 平局 } // 随机选择一个位置下子 const [mr, mc] = movesList[Math.floor(Math.random() * movesList.length)]; boardState[mr][mc] = currentTurn; moveCount++; // 检查胜负 if (checkWin(mr, mc, currentTurn)) { return (currentTurn === AI); // 如果当前落子者赢了,返回是否为AI赢 } // 切换选手 currentTurn = (currentTurn === HUMAN ? AI : HUMAN); // 为保险起见,如果模拟步数过多(例如超过225步),跳出当作平局,避免死循环 if (moveCount > SIZE * SIZE) { return false; } } } // 辅助函数:判断某空位是否邻近已有棋子,用于随机模拟筛选走法 function hasNeighbor(boardState, r, c) { for (let dr = -1; dr <= 1; dr++) { for (let dc = -1; dc <= 1; dc++) { if (dr === 0 && dc === 0) continue; const nr = r + dr, nc = c + dc; if (nr >= 0 && nr < SIZE && nc >= 0 && nc < SIZE && boardState[nr][nc] !== EMPTY) { return true; } } } return false; } // 处理玩家点击棋盘进行落子 function handlePlayerMove(r, c) { if (gameOver || currentPlayer !== HUMAN) return; if (board[r][c] !== EMPTY) return; // 该位置已被占用 makeMove(r, c, HUMAN); if (gameOver) return; // 玩家下子后,轮到AI下子 currentPlayer = AI; statusElem.textContent = "AI思考中..."; // 使用 setTimeout 模拟思考延迟并避免阻塞UI setTimeout(() => { let aiMove; if (aiDifficulty === 'easy') { aiMove = aiMoveEasy(); } else if (aiDifficulty === 'medium') { aiMove = aiMoveMedium(); } else if (aiDifficulty === 'hard') { aiMove = aiMoveHard(); } if (aiMove) { makeMove(aiMove[0], aiMove[1], AI); } if (!gameOver) { currentPlayer = HUMAN; statusElem.textContent = "轮到您下棋 (黑棋)"; } }, 100); } // 在棋盘上下棋并更新UI和状态 function makeMove(r, c, player) { // 更新数据模型 board[r][c] = player; // 更新UI显示棋子 const cellElem = boardElem.children[r * SIZE + c]; cellElem.classList.add(player === HUMAN ? 'black' : 'white'); cellElem.style.cursor = "default"; // 放置棋子后不再可点击 // 检查胜利 if (checkWin(r, c, player)) { gameOver = true; statusElem.textContent = (player === HUMAN ? "您赢了!恭喜!" : "AI赢了!") + " 点击重新开始游戏。"; } } // 难度选择和重新开始按钮事件绑定 document.getElementById('aiLevel').addEventListener('change', function() { aiDifficulty = this.value; }); document.getElementById('restartBtn').addEventListener('click', resetGame); // 启动游戏 resetGame(); </script> </body> </html>
使用说明: