问题描述
一周以来,我一直在尝试在我的 C# 国际象棋引擎中实现极大极小算法,它进行了合法的移动但没有意义的移动。我找不到错误,希望有人能发现它。我试图通过测试每种方法来隔离问题,除了极小极大之外,它们似乎都可以正常工作。
public enum Piece
{
Empty,Pawn_W,Pawn_B,Knight_W,Knight_B,Bishop_W,Bishop_B,Rook_W,Rook_B,Queen_W,Queen_B,King_W,King_B
}
public bool IsPieceWhite(Piece piece)
{
if (piece == Piece.Pawn_W || piece == Piece.Knight_W ||
piece == Piece.Bishop_W || piece == Piece.Rook_W ||
piece == Piece.Queen_W || piece == Piece.King_W)
return true;
else return false;
}
public bool IsPieceBlack(Piece piece)
{
if (piece == Piece.Pawn_B || piece == Piece.Knight_B ||
piece == Piece.Bishop_B || piece == Piece.Rook_B ||
piece == Piece.Queen_B || piece == Piece.King_B)
return true;
else return false;
}
public int GetPieceWorth(Piece piece)
{
if (piece == Piece.Pawn_W || piece == Piece.Pawn_B)
return 1;
if (piece == Piece.Knight_W || piece == Piece.Knight_B)
return 3;
if (piece == Piece.Bishop_W || piece == Piece.Bishop_B)
return 3;
if (piece == Piece.Rook_W || piece == Piece.Rook_B)
return 5;
if (piece == Piece.Queen_W || piece == Piece.Queen_B)
return 9;
if (piece == Piece.King_W || piece == Piece.King_B)
return 9999999;
return 0;
}
Piece[,] CurrentBoard = GetStartingBoard();
Piece[,] bestMove;
public int depthB = 3;
public double minimax(Piece[,] board,int depth,bool maximizingPlayer)
{
if (depth == 0)
{
double result = EvaluatePosition(board,maximizingPlayer);
return result;
}
if (maximizingPlayer)
{
double best = Double.MinValue;
double value = Double.MinValue;
foreach (var move in GenerateMoves(board,maximizingPlayer))
{
Piece[,] clonedMove = CloneBoard(move);
value = Math.Max(value,minimax(clonedMove,depth - 1,false));
if (depth == depthB && value >= best)
{
best = value;
bestMove = clonedMove;
}
}
return value;
}
else
{
double best = Double.MaxValue;
double value = Double.MaxValue;
foreach (var move in GenerateMoves(board,] clonedMove = CloneBoard(move);
value = Math.Min(value,true));
if (depth == depthB && value <= best)
{
best = value;
bestMove = clonedMove;
}
}
return value;
}
}
public Piece[,] CloneBoard(Piece[,] boardPos)
{
Piece[,] copy = boardPos.Clone() as Piece[,];
return copy;
}
public double EvaluatePosition(Piece[,] boardPos,bool ForWhite)
{
double eval = 0;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
if (boardPos[i,j] != Piece.Empty)
{
if (IsPieceWhite(boardPos[i,j]))
{
eval += GetPieceWorth(boardPos[i,j]);
}
else if (IsPieceBlack(boardPos[i,j]))
{
eval -= GetPieceWorth(boardPos[i,j]);
}
}
}
}
if (ForWhite)
return eval;
else
return eval * -1;
}
//a-h,0-7
//Piece[,] board = new Piece[8,8];
public static Piece[,] GetStartingBoard()
{
Piece[,8];
for (int i = 0; i < 8; i++)
{
//initiate pawns
board[1,i] = Piece.Pawn_W;
board[6,i] = Piece.Pawn_B;
}
//white pieces
board[0,0] = Piece.Rook_W;
board[0,1] = Piece.Knight_W;
board[0,2] = Piece.Bishop_W;
board[0,3] = Piece.Queen_W;
board[0,4] = Piece.King_W;
board[0,5] = Piece.Bishop_W;
board[0,6] = Piece.Knight_W;
board[0,7] = Piece.Rook_W;
//black pieces
board[7,0] = Piece.Rook_B;
board[7,1] = Piece.Knight_B;
board[7,2] = Piece.Bishop_B;
board[7,3] = Piece.Queen_B;
board[7,4] = Piece.King_B;
board[7,5] = Piece.Bishop_B;
board[7,6] = Piece.Knight_B;
board[7,7] = Piece.Rook_B;
//test
//board[1,4] = Piece.Pawn_B;
//board[6,2] = Piece.Pawn_W;
return board;
}
我上传了一段引擎与自己对战的短片,以展示奇怪的动作:https://www.youtube.com/watch?v=A0HVgXYSciY
解决方法
终于能够使极大极小函数起作用。感谢大家的帮助!
工作方式:
public int minimax(Piece[,] board,int depth,bool maximizingPlayer,bool WhiteToPlay)
{
if (depth == 0)
{
int result = EvaluatePosition(board,WhiteToPlay);
return result;
}
var moves = GenerateMoves(board,WhiteToPlay);
if (maximizingPlayer)
{
int value = int.MinValue;
foreach (var move in moves)
{
int minmaxResult = minimax(move,depth - 1,false,!WhiteToPlay);
value = Math.Max(value,minmaxResult);
if (depth == depthB)
{
moveScores.Add(move,minmaxResult);
}
}
return value;
}
else
{
int value = int.MaxValue;
foreach (var move in moves)
{
int minmaxResult = minimax(move,true,!WhiteToPlay);
value = Math.Min(value,minmaxResult);
}
}
return value;
}
}