向前看两步------Minimax让AI学会"换位思考"
设计截图如下:

为什么需要Minimax
普通AI的局限:只看当前一步,不考虑对手的反击。
场景:AI可以选择形成活三(8000分)或冲四(10000分)。普通AI选冲四,但对手下一步会堵住冲四,AI的活三机会丢失了。
Minimax的核心思想:假设对手也会做出最优选择,选择对自己最不坏的结果。
Minimax算法原理
AI选择(最大化)
/ | \
候选1 候选2 候选3
/ \ / \ / \
对手选择(最小化)
↓ ↓ ↓ ↓ ↓ ↓
评估 评估 评估 评估 评估 评估
- Max层(AI回合):选择分数最高的走法
- Min层(对手回合):选择分数最低的走法(对AI最不利)
- 叶节点:用评估函数计算当前局面的分数
代码实现
typescript
private getHardMove(board: number[][]): Move {
const candidates = this.getSortedCandidates(board);
const maxCandidates = Math.min(12, candidates.length);
let bestMove: Move = candidates[0];
let bestScore: number = -Infinity;
let alpha: number = -Infinity;
const beta: number = Infinity;
for (let i = 0; i < maxCandidates; i++) {
const move = candidates[i];
board[move.row][move.col] = this.aiColor;
// 如果直接获胜,立即返回
if (this.checkWin(board, move.row, move.col, this.aiColor)) {
board[move.row][move.col] = EMPTY;
return move;
}
// Minimax递归(对手回合,最小化)
const score = this.minimax(board, 2, alpha, beta, false);
board[move.row][move.col] = EMPTY;
if (score > bestScore) {
bestScore = score;
bestMove = move;
}
alpha = Math.max(alpha, score);
}
return bestMove;
}
minimax递归函数
typescript
private minimax(board: number[][], depth: number, alpha: number, beta: number,
isMaximizing: boolean): number {
// 终止条件:深度为0时评估局面
if (depth === 0) {
return this.evaluateBoard(board);
}
const candidates = this.getSortedCandidates(board);
const maxCandidates = Math.min(8, candidates.length);
if (isMaximizing) {
// AI回合:找最大值
let maxEval: number = -Infinity;
for (let i = 0; i < maxCandidates; i++) {
const move = candidates[i];
board[move.row][move.col] = this.aiColor;
if (this.checkWin(board, move.row, move.col, this.aiColor)) {
board[move.row][move.col] = EMPTY;
return SCORE_FIVE; // AI获胜
}
const evalScore = this.minimax(board, depth - 1, alpha, beta, false);
board[move.row][move.col] = EMPTY;
maxEval = Math.max(maxEval, evalScore);
alpha = Math.max(alpha, evalScore);
if (beta <= alpha) break; // Alpha-Beta剪枝
}
return maxEval;
} else {
// 对手回合:找最小值
let minEval: number = Infinity;
for (let i = 0; i < maxCandidates; i++) {
const move = candidates[i];
board[move.row][move.col] = this.humanColor;
if (this.checkWin(board, move.row, move.col, this.humanColor)) {
board[move.row][move.col] = EMPTY;
return -SCORE_FIVE; // 对手获胜(对AI最不利)
}
const evalScore = this.minimax(board, depth - 1, alpha, beta, true);
board[move.row][move.col] = EMPTY;
minEval = Math.min(minEval, evalScore);
beta = Math.min(beta, evalScore);
if (beta <= alpha) break; // Alpha-Beta剪枝
}
return minEval;
}
}
搜索树图解
假设AI在搜索深度2,候选3个:
深度2 AI选择(MAX)
/ | \
深度1 对手(MIN) 对手(MIN) 对手(MIN)
/ \ / \ / \
深度0 评估 评估 评估 评估 评估 评估
80 50 60 30 90 70
自底向上计算:
深度1: min(80,50)=50 min(60,30)=30 min(90,70)=70
深度2: max(50,30,70)=70 → 选择候选1
关键设计决策
1. 深度2的选择
typescript
const score = this.minimax(board, 2, alpha, beta, false);
- 深度1:只看对手反应------不够
- 深度2:看AI→对手→AI------合理
- 深度3:AI→对手→AI→对手------更好但计算量大
移动端选择深度2是性能与棋力的平衡。
2. 候选数量限制
typescript
// 顶层:12个候选
const maxCandidates = Math.min(12, candidates.length);
// 递归层:8个候选
const maxCandidates = Math.min(8, candidates.length);
搜索树大小 = 12 × 8 × 8 = 768,在移动端可接受。
3. 立即获胜检查
typescript
if (this.checkWin(board, move.row, move.col, this.aiColor)) {
board[move.row][move.col] = EMPTY;
return move; // 不需要继续搜索
}
找到必胜走法立即返回,避免不必要的搜索。
4. 评估函数的差异
困难模式使用evaluateBoard(全盘评估),而非普通模式的evaluatePosition(单点评估):
typescript
private evaluateBoard(board: number[][]): number {
let aiScore: number = 0;
let humanScore: number = 0;
aiScore += this.evaluateLines(board, this.aiColor);
humanScore += this.evaluateLines(board, this.humanColor);
return aiScore - humanScore * 1.1;
}
总结
Minimax算法是博弈树搜索的经典方法:
- 换位思考:假设对手做出最优选择
- 最大最小:AI最大化,对手最小化
- 递归搜索:从叶节点向上回传
- 深度控制:平衡棋力与性能
困难模式通过深度2的Minimax搜索,能预见2步之后的局面变化,显著强于普通AI的单步评估。