基于JS实现的中国象棋AI系统:多模块协同决策与分析
基于JavaScript实现的中国象棋AI系统:多模块协同决策与分析
引言
中国象棋是我国传统文化瑰宝,将其与现代AI技术结合,不仅能够传承传统文化,还能展示AI技术的魅力。本文将详细介绍一个基于JavaScript实现的中国象棋AI系统,该系统采用了多模块协同决策的架构,实现了意图分析、防御策略、进攻策略等多维度的棋局分析功能。
相关资源已经放在 github 上,欢迎star or fork
https://github.com/chenchihwen/chinese-chess-aihttps://github.com/chenchihwen/chinese-chess-ai在线使用
中国象棋对战游戏https://chenchihwen.github.io/chinese-chess-ai/在线无法调用 ollama 本地模型,只能使用人人对战模式
项目亮点
1. 多AI模块协同决策架构
本项目最大的亮点是采用了多AI模块协同决策的架构,包括:
-
意图分析AI:分析对手的走棋意图和潜在威胁
-
防御AI:负责评估己方将/帅的安全状况,提供防御建议
-
进攻AI:寻找进攻机会,如将军或吃掉高价值棋子
-
主决策引擎:综合各模块分析结果,做出最终决策
这种模块化设计使AI决策过程更加透明,也更符合人类棋手的思考方式。
2. 可视化AI分析结果
项目提供了直观的AI分析结果展示界面,玩家可以清晰地看到:
-
对手意图分析(包括意图描述、威胁类型和威胁等级)
-
防御分析(将/帅是否受威胁及防御建议)
-
进攻分析(是否有将军机会及进攻建议)
-
最终决策过程
这种透明化的AI决策过程,不仅增强了游戏的趣味性,还具有很好的教学价值。
3. 多层次AI决策机制
系统实现了多层次的AI决策机制:
-
LLM AI:高级AI决策(可选)
-
传统AI:基于评估函数的中等AI决策
-
随机走法生成:作为兜底方案
这种多层次的设计确保了AI系统的稳定性和可扩展性。
4. 完整的象棋规则实现
项目实现了完整的中国象棋规则,包括:
-
各类棋子的走法规则(将/帅、士/仕、象/相、马、车、炮、兵/卒)
-
特殊规则(如将帅不能照面、象不过河等)
-
胜负判定(将死、困毙等)
系统架构与逻辑流程
整体架构
项目采用模块化设计,主要包括以下几个核心模块:
-
游戏核心模块(game-core.js):负责游戏的基本逻辑和流程控制
-
规则引擎模块(game-rules.js):实现象棋规则,判断走法是否合法
-
AI模块:
-
意图分析模块(intent-analyzer.js)
-
防御模块(defender.js)
-
进攻模块(attacker.js)
-
主决策引擎(main-engine.js)
-
LLM连接器(llm-connector.js)
-
-
UI模块:负责游戏界面的渲染和交互
逻辑流程
1. 游戏初始化流程
// 游戏初始化 document.addEventListener('DOMContentLoaded', function() {game = new XiangQiGame();game.init(); });
游戏初始化时,会创建棋盘、设置初始棋子位置、加载历史数据等。
2. 玩家走棋流程
handleClick(event) {// 获取点击位置const col = Math.round((x - this.marginX) / this.cellSize);const row = Math.round((y - this.marginY) / this.cellSize);// 处理点击事件this.handleSquareClick(col, row); } handleSquareClick(col, row) {const piece = this.board[row][col];// 如果已选中棋子且点击位置是可行走法,则移动棋子if (this.selectedPiece && this.isPossibleMove(col, row)) {this.makeMove(this.selectedPiece.col, this.selectedPiece.row, col, row);return;}// 如果点击的是自己的棋子,则选中该棋子if (piece && this.isPieceOwnedByCurrentPlayer(piece)) {this.selectPiece(col, row);} else {// 否则取消选中this.selectedPiece = null;this.possibleMoves = [];this.drawBoard();} }
玩家点击棋盘时,系统会判断是选择棋子还是移动棋子,并相应地更新游戏状态。
3. AI决策流程
AI决策是本项目的核心,其流程如下:
async aiMove() {try {// 显示AI分析区域const aiAnalysisDiv = document.getElementById('aiAnalysis');if (aiAnalysisDiv) {aiAnalysisDiv.style.display = 'block';}// 1. 进行意图分析let intentAnalysis = { intent: "分析中...", threat: "无威胁", threatLevel: 0 };if (this.moveHistory.length > 0) {const lastMove = this.moveHistory[this.moveHistory.length - 1];const pieceType = lastMove.piece.toLowerCase();const pieceName = this.pieceNames[lastMove.piece] || lastMove.piece;// 分析对手意图intentAnalysis = {intent: `对手移动了${pieceName},可能在调整阵型`,threat: pieceType === 'r' || pieceType === 'c' ? "中等威胁" : "低威胁",threatLevel: pieceType === 'r' || pieceType === 'c' ? 2 : 1};}// 2. 进行防御分析const isInCheck = this.isInCheck(this.currentPlayer);const defenseAnalysis = {kingInDanger: isInCheck,defenseRecommendation: isInCheck ? "将/帅受到威胁,必须立即保护!" : "将/帅暂无威胁"};// 3. 进行进攻分析const opponent = this.currentPlayer === 'red' ? 'black' : 'red';const opponentInCheck = this.isInCheck(opponent);const attackAnalysis = {canCheckmate: opponentInCheck,attackRecommendation: opponentInCheck ? "可以将军!" : "寻找进攻机会"};// 4. 显示分析结果this.displayAnalysisResults(intentAnalysis, defenseAnalysis, attackAnalysis);// 5. 获取AI走法let move = null;let finalDecision = "";// 5.1 尝试使用LLM AIif (window.llmAI) {try {finalDecision += "使用LLM AI生成走法\n";move = await window.llmAI.getMove(this.board, this.currentPlayer, this.moveHistory);if (move && move.from && move.to) {finalDecision += `LLM AI决定从(${move.from.col},${move.from.row})移动到(${move.to.col},${move.to.row})\n`;} else {finalDecision += "LLM AI返回了无效的走法,尝试使用传统AI\n";move = null;}} catch (error) {finalDecision += `LLM AI调用失败,尝试使用传统AI\n`;move = null;}} else {finalDecision += "LLM AI未加载,使用传统AI\n";}// 5.2 如果LLM失败,使用传统AIif (!move) {move = this.getBestMove();if (move && move.from && move.to) {finalDecision += `传统AI决定从(${move.from.col},${move.from.row})移动到(${move.to.col},${move.to.row})\n`;} else {finalDecision += "传统AI返回了无效的走法,尝试生成随机走法\n";move = null;}}// 5.3 如果所有AI方法都失败,生成随机走法if (!move) {move = this.generateRandomMove(this.currentPlayer);if (move && move.from && move.to) {finalDecision += `随机生成走法从(${move.from.col},${move.from.row})移动到(${move.to.col},${move.to.row})\n`;}}// 6. 更新最终决策显示const finalDecisionDiv = document.getElementById('finalDecision');if (finalDecisionDiv) {finalDecisionDiv.textContent = finalDecision;}// 7. 执行走法if (move && move.from && move.to) {this.makeMove(move.from.col, move.from.row, move.to.col, move.to.row);} else {this.updateStatus('AI无法生成有效走法,请重新开始游戏');}} catch (error) {this.updateStatus('AI移动出错,请重新开始游戏');} }
AI决策流程包括意图分析、防御分析、进攻分析、走法生成和执行等多个步骤,每个步骤都有明确的职责和输出。
4. 棋盘渲染流程
drawBoard() {// 清除画布this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);// 绘制背景this.ctx.fillStyle = '#F5DEB3';this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);// 绘制网格线// ...// 绘制九宫格对角线this.drawPalaceDiagonals();// 绘制楚河汉界文字// ...// 绘制棋子this.drawPieces();// 绘制高亮this.drawHighlights(); }
棋盘渲染包括背景、网格线、九宫格、楚河汉界、棋子等多个元素的绘制,通过Canvas API实现。
核心AI模块详解
1. 意图分析模块
意图分析模块负责分析对手的走棋意图和潜在威胁,其核心逻辑如下:
analyze: function(board, moveHistory, currentPlayer) {// 获取对手最后一步走法let lastMove = moveHistory[moveHistory.length - 1];// 分析意图let intent = "";let threat = "无明确威胁";let threatLevel = 0;// 检查是否接近己方将/帅const ownKingPos = this.findKingPosition(board, currentPlayer);if (ownKingPos) {const distToKing = Math.abs(lastMove.to.col - ownKingPos.col) + Math.abs(lastMove.to.row - ownKingPos.row);if (distToKing <= 2) {intent = `对手${pieceName}接近我方${currentPlayer === 'red' ? '帅' : '将'},可能准备将军`;threat = "将军威胁";threatLevel = 3;} else if (distToKing <= 4) {intent = `对手${pieceName}向我方${currentPlayer === 'red' ? '帅' : '将'}方向移动,需要警惕`;threat = "潜在将军威胁";threatLevel = 2;}}// 如果没有检测到将军威胁,分析其他可能的意图if (threatLevel === 0) {// 检查是否是高价值棋子移动if (['r', 'n', 'c'].includes(pieceType)) {intent = `对手移动了高价值${pieceName},可能在准备进攻或加强控制`;threat = "战术部署";threatLevel = 1;} // 检查是否是过河的兵/卒else if (pieceType === 'p') {const isOverRiver = (opponentPlayer === 'red' && lastMove.to.row < 5) || (opponentPlayer === 'black' && lastMove.to.row > 4);if (isOverRiver) {intent = `对手${pieceName}已过河,增加了攻击面`;threat = "增加攻击面";threatLevel = 1;} else {intent = `对手移动了${pieceName},可能在调整阵型`;threat = "阵型调整";threatLevel = 0;}} else {intent = `对手移动了${pieceName},可能在调整防御或准备后续行动`;threat = "一般行动";threatLevel = 0;}}return {intent: intent,threat: threat,threatLevel: threatLevel,lastMove: lastMove}; }
2. 防御模块
防御模块负责评估己方将/帅的安全状况,提供防御建议:
analyze: function(board, currentPlayer) {// 找到己方将/帅位置let ownKingPos = null;for (let row = 0; row < 10; row++) {for (let col = 0; col < 9; col++) {const piece = board[row][col];if (piece) {const isRed = piece === piece.toUpperCase();const pieceType = piece.toLowerCase();if (pieceType === 'k' && ((currentPlayer === 'red' && isRed) || (currentPlayer === 'black' && !isRed))) {ownKingPos = { col, row };break;}}}if (ownKingPos) break;}// 检查将/帅是否受到威胁let kingInDanger = false;let threateningPieces = [];if (ownKingPos) {// 遍历对方棋子,检查是否有棋子可以攻击己方将/帅for (let row = 0; row < 10; row++) {for (let col = 0; col < 9; col++) {const piece = board[row][col];if (piece) {const isRed = piece === piece.toUpperCase();if ((currentPlayer === 'red' && !isRed) || (currentPlayer === 'black' && isRed)) {if (this.canAttack(board, { col, row, piece }, ownKingPos)) {kingInDanger = true;threateningPieces.push({ col, row, piece });}}}}}}// 生成防御建议let defenseRecommendation = "";if (kingInDanger) {defenseRecommendation = "将/帅受到威胁,必须立即保护!";} else {defenseRecommendation = "将/帅暂无威胁,可以考虑进攻或加强防御。";}return {kingInDanger: kingInDanger,threateningPieces: threateningPieces,defenseRecommendation: defenseRecommendation}; }
3. 进攻模块
进攻模块负责寻找进攻机会,如将军或吃掉高价值棋子:
analyze: function(board, currentPlayer) {// 找到对方将/帅位置let opponentKingPos = null;for (let row = 0; row < 10; row++) {for (let col = 0; col < 9; col++) {const piece = board[row][col];if (piece) {const isRed = piece === piece.toUpperCase();const pieceType = piece.toLowerCase();if (pieceType === 'k' && ((currentPlayer === 'red' && !isRed) || (currentPlayer === 'black' && isRed))) {opponentKingPos = { col, row };break;}}}if (opponentKingPos) break;}// 检查是否可以将军/吃掉对方将帅let canCheckmate = false;if (opponentKingPos) {// 遍历己方棋子,检查是否有棋子可以攻击对方将/帅for (let row = 0; row < 10; row++) {for (let col = 0; col < 9; col++) {const piece = board[row][col];if (piece) {const isRed = piece === piece.toUpperCase();if ((currentPlayer === 'red' && isRed) || (currentPlayer === 'black' && !isRed)) {if (this.canAttack(board, { col, row, piece }, opponentKingPos)) {canCheckmate = true;break;}}}}if (canCheckmate) break;}}// 生成进攻建议let attackRecommendation = "";if (canCheckmate) {attackRecommendation = "发现将军/吃帅机会,应立即执行!";} else {// 检查是否有高价值棋子可以吃// ...if (canCaptureHighValue) {attackRecommendation = "发现可以吃掉对方高价值棋子,应考虑执行。";} else {attackRecommendation = "暂无明显进攻机会,考虑调整阵型为后续进攻做准备。";}}return {canCheckmate: canCheckmate,attackRecommendation: attackRecommendation}; }
项目实现中的技术难点与解决方案
1. 多AI模块协同决策
难点:如何协调多个AI模块,使它们能够协同工作,共同做出决策。
解决方案:采用模块化设计,每个AI模块负责特定的分析任务,并通过主决策引擎进行协调。各模块通过标准化的接口进行通信,确保数据流的一致性和可靠性。
2. 象棋规则的完整实现
难点:中国象棋规则复杂,特别是马的"蹩马腿"、象的"塞象眼"等特殊规则的实现。
解决方案:将规则引擎独立为一个模块,针对每种棋子实现专门的走法判断函数,并通过单元测试确保规则的正确性。
static getKnightMoves(game, col, row) {const moves = [];const knightMoves = [[2, 1], [2, -1], [-2, 1], [-2, -1],[1, 2], [1, -2], [-1, 2], [-1, -2]];const blockPositions = [[1, 0], [1, 0], [-1, 0], [-1, 0],[0, 1], [0, -1], [0, 1], [0, -1]];for (let i = 0; i < knightMoves.length; i++) {const [dx, dy] = knightMoves[i];const [bx, by] = blockPositions[i];const newCol = col + dx;const newRow = row + dy;const blockCol = col + bx;const blockRow = row + by;if (newCol >= 0 && newCol < game.boardWidth && newRow >= 0 && newRow < game.boardHeight) {// 检查是否蹩马腿if (!game.board[blockRow][blockCol]) {const targetPiece = game.board[newRow][newCol];if (!targetPiece || !this.isPieceOwnedByCurrentPlayer(game, targetPiece)) {moves.push({ col: newCol, row: newRow });}}}}return moves; }
3. AI分析结果的可视化
难点:如何将AI的分析过程和结果以直观、易懂的方式展示给用户。
解决方案:设计专门的UI组件,将AI分析结果分类展示,并使用不同的颜色和图标增强可读性。
displayAnalysisResults(intentAnalysis, defenseAnalysis, attackAnalysis) {// 更新意图分析结果const intentDiv = document.getElementById('intentAnalysis');if (intentDiv) {let intentHtml = `<strong>对手意图分析:</strong><br>`;intentHtml += `意图: ${intentAnalysis.intent || '未知'}<br>`;intentHtml += `威胁: ${intentAnalysis.threat || '无'}<br>`;intentHtml += `威胁等级: ${intentAnalysis.threatLevel || 0}/3<br>`;intentDiv.innerHTML = intentHtml;}// 更新防御分析结果const defenseDiv = document.getElementById('defenseAnalysis');if (defenseDiv) {let defenseHtml = `<strong>防御分析:</strong><br>`;defenseHtml += `将/帅受威胁: ${defenseAnalysis.kingInDanger ? '是' : '否'}<br>`;defenseHtml += `防御建议: ${defenseAnalysis.defenseRecommendation || '无'}<br>`;defenseDiv.innerHTML = defenseHtml;}// 更新进攻分析结果const attackDiv = document.getElementById('attackAnalysis');if (attackDiv) {let attackHtml = `<strong>进攻分析:</strong><br>`;attackHtml += `可将军: ${attackAnalysis.canCheckmate ? '是' : '否'}<br>`;attackHtml += `进攻建议: ${attackAnalysis.attackRecommendation || '无'}<br>`;attackDiv.innerHTML = attackHtml;} }
4. 多层次AI决策机制的实现
难点:如何在不同的AI决策方法之间平滑切换,确保系统的稳定性和可靠性。
解决方案:采用降级策略,先尝试使用高级AI(LLM),如果失败则降级到传统AI,最后使用随机走法作为兜底方案。
// 尝试使用LLM AI if (window.llmAI) {try {move = await window.llmAI.getMove(this.board, this.currentPlayer, this.moveHistory);if (!move || !move.from || !move.to) {move = null; // 降级到传统AI}} catch (error) {move = null; // 降级到传统AI} }// 如果LLM失败,使用传统AI if (!move) {move = this.getBestMove();if (!move || !move.from || !move.to) {move = null; // 降级到随机走法} }// 如果所有AI方法都失败,生成随机走法 if (!move) {move = this.generateRandomMove(this.currentPlayer); }
项目扩展与优化方向
1. AI能力提升
-
引入深度学习模型,提高AI的棋力
-
增加开局库和残局库,提高特定阶段的AI表现
-
优化评估函数,使AI能够更准确地评估局面
2. 用户体验优化
-
添加走法提示功能,帮助初学者学习象棋
-
增加棋局回放功能,方便复盘分析
-
支持棋谱导入导出,便于分享和学习
3. 多平台支持
-
开发移动端适配版本,支持触摸操作
-
实现在线对战功能,支持玩家之间的对弈
-
添加云端AI服务,提供更强大的AI对手
4. 教学功能增强
-
添加象棋教程和练习题
-
实现AI辅助分析功能,帮助玩家提高棋艺
-
增加棋局评论功能,提供专业的棋局分析
总结
本项目通过JavaScript实现了一个功能完善的中国象棋AI系统,采用多模块协同决策的架构,实现了意图分析、防御策略、进攻策略等多维度的棋局分析功能。系统不仅能够提供合理的AI对手,还能够展示AI的决策过程,具有很好的教学价值。
项目的核心亮点在于多AI模块协同决策架构、可视化AI分析结果、多层次AI决策机制以及完整的象棋规则实现。这些特性使得本项目不仅是一个游戏,更是一个学习象棋和AI技术的平台。
未来,我们将继续优化AI能力,提升用户体验,支持多平台,增强教学功能,使这个项目成为象棋爱好者和AI学习者的理想工具。
参考资料
-
中国象棋规则:象棋巫师 - 象棋百科全书
-
JavaScript Canvas API:Canvas API - Web API | MDN
-
象棋AI算法:Chessprogramming wiki
希望这篇博文对你有所帮助,如有任何问题,欢迎在评论区留言交流!