開發中國象棋程式分為兩大階段:**規則引擎** (合法走法生成、局面判斷) 與 **AI 引擎** (評估函數、搜尋演算法)。本文整理從棋子類別設計、介面定義、走法生成到引入 Minimax + Alpha-Beta 剪枝 AI 的架構演進筆記,供想實作象棋 AI 的開發者參考。
public interface IChessPiece
{
bool IsRed { get; }
bool IsAlive { get; }
int X { get; set; } // 1-9 (檔)
int Y { get; set; } // 1-10 (列)
string Name { get; }
IReadOnlyList GetLegalMoves(Board board); // 依當前盤面生成合法走法
void MoveTo(int x, int y); // 執行移動 (含吃子邏輯由 Board 處理)
}
public abstract class ChessPieceBase : IChessPiece
{
public const int BoardWidth = 9;
public const int BoardHeight = 10;
public bool IsRed { get; protected set; }
public bool IsAlive { get; protected set; } = true;
public int X { get; set; }
public int Y { get; set; }
public abstract string Name { get; }
protected bool IsInsideBoard(int x, int y) => x >= 1 && x <= BoardWidth && y >= 1 && y <= BoardHeight;
public abstract IReadOnlyList GetLegalMoves(Board board);
public void MoveTo(int x, int y)
{
X = x; Y = y;
}
public void Capture() => IsAlive = false;
}
public class Horse : ChessPieceBase
{
public override string Name => IsRed ? "傌" : "馬";
// 馬腳座標偏移 (dx, dy, 腳 dx, 腳 dy)
private static readonly (int dx, int dy, int legX, int legY)[] _moves = {
(2, 1, 1, 0), (1, 2, 0, 1), (-1, 2, 0, 1), (-2, 1, -1, 0),
(-2, -1, -1, 0), (-1, -2, 0, -1), (1, -2, 0, -1), (2, -1, 1, 0)
};
public override IReadOnlyList GetLegalMoves(Board board)
{
var moves = new List();
foreach (var (dx, dy, legX, legY) in _moves)
{
int nx = X + dx, ny = Y + dy;
int lx = X + legX, ly = Y + legY;
if (!IsInsideBoard(nx, ny)) continue;
if (board.HasPiece(lx, ly)) continue; // 搶馬腳
var target = board.GetPiece(nx, ny);
if (target == null || target.IsRed != IsRed) // 空位或敵子
moves.Add(new Position(nx, ny));
}
return moves;
}
}
public class Board
{
private readonly IChessPiece[,] _grid = new IChessPiece[10, 9]; // [y, x] 1-based
public IReadOnlyList AllPieces { get; private set; }
public IChessPiece GetPiece(int x, int y) => IsInside(x, y) ? _grid[y, x] : null;
public bool HasPiece(int x, int y) => GetPiece(x, y) != null;
public void MakeMove(Move move)
{
// 執行移動、處理吃子、更新棋盤狀態、切換回合
}
public void UndoMove(Move move) { /* 回溯用 */ }
public bool IsInCheck(bool isRed) { /* 判斷將軍 */ }
public bool IsCheckmate(bool isRed) { /* 判斷將死 */ }
}
public interface IEvaluator
{
int Evaluate(Board board, bool isRedTurn); // 正分 = 紅方優勢
}
public class SimpleEvaluator : IEvaluator
{
private static readonly Dictionary _pieceValues = new()
{
{ typeof(King), 10000 }, { typeof(Advisor), 200 }, { typeof(Elephant), 200 },
{ typeof(Horse), 400 }, { typeof(Rook), 900 }, { typeof(Cannon), 450 }, { typeof(Pawn), 100 }
};
public int Evaluate(Board board, bool isRedTurn)
{
int score = 0;
foreach (var p in board.AllPieces)
{
if (!p.IsAlive) continue;
int val = _pieceValues[p.GetType()];
score += p.IsRed ? val : -val;
}
// 可加入位置權重表 (棋子在特定座標的加分)
return isRedTurn ? score : -score;
}
}
public class ChessEngine
{
private readonly IEvaluator _evaluator;
private readonly int _maxDepth;
private int _nodesSearched;
public ChessEngine(IEvaluator evaluator, int maxDepth = 4)
{
_evaluator = evaluator;
_maxDepth = maxDepth;
}
public Move GetBestMove(Board board, bool isRedTurn)
{
_nodesSearched = 0;
var bestMove = AlphaBeta(board, _maxDepth, int.MinValue, int.MaxValue, isRedTurn, out _);
return bestMove;
}
private Move AlphaBeta(Board board, int depth, int alpha, int beta, bool isRedTurn, out int score)
{
_nodesSearched++;
if (depth == 0 || board.IsCheckmate(isRedTurn) || board.IsCheckmate(!isRedTurn))
{
score = _evaluator.Evaluate(board, isRedTurn);
return null;
}
Move bestMove = null;
var moves = GenerateAllMoves(board, isRedTurn);
// 走法排序:吃子優先、歷史啟發、殺手走法 → 大幅提升剪枝效率
moves = OrderMoves(moves, board);
foreach (var move in moves)
{
board.MakeMove(move);
AlphaBeta(board, depth - 1, -beta, -alpha, !isRedTurn, out int childScore);
board.UndoMove(move);
childScore = -childScore; // 雙方視角轉換
if (childScore > alpha)
{
alpha = childScore;
bestMove = move;
if (alpha >= beta) break; // Beta cutoff
}
}
score = alpha;
return bestMove;
}
}
規則引擎是基石,AI 是靈魂。建議先完成**完整、無 Bug 的走法生成與局面判斷** (含將軍、將死、和棋規則),再引入 Minimax 搜尋框架,逐步加入評估函數權重調優、走法排序、置換表。C# 雖不如 C++ 極致效能,但配合 Span<T>、ref struct、BitOperations 等現代特性,足以打造業餘高手級引擎。