首页 > 解决方案 > C# 中国际象棋的 MiniMax 算法无法正常工作

问题描述

一个星期以来,我一直在尝试在我的 C# 国际象棋引擎中实现 minimax 算法,它做出了合法的移动,但没有有意义的移动。我找不到错误,希望有人能发现它。我试图通过测试每种方法来隔离问题,除了极小值之外,它们似乎都可以正常工作。


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, maximizingPlayer))
        {
            Piece[,] clonedMove = CloneBoard(move);
            value = Math.Min(value, minimax(clonedMove, depth - 1, 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[,] board = new Piece[8, 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

标签: c#chessminimax

解决方案


终于能够使极小极大函数工作。感谢所有的帮助!

工作方法:

        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, depth - 1, true, !WhiteToPlay);
                    value = Math.Min(value, minmaxResult);
                    if (depth == depthB)
                    {
                        moveScores.Add(move, minmaxResult);
                    }
                }
                return value;
            }
        }

推荐阅读