C# 中的国际象棋引擎 - 糟糕的走法

问题描述 投票:0回答:1

我目前正在尝试编写国际象棋引擎。我写了一个简单的 AlphaBeta Minimax 和 MaterialBalance 评估(链接如下)。我正在使用 SebLagues Chess Challenge Project 来编程我的国际象棋引擎 (https://github.com/SebLague/Chess-Challenge)。我面临的问题是,深度为 4 时,我的引擎无法预见简单的将死,而深度为 4 时应该可以预见。我找不到错误,所以我认为更多的眼对可以有所帮助。

机器人只是做出奇怪的动作。如果白色获胜,则评估函数返回正值;如果黑色获胜(按预期),则评估函数返回负值,但机器人只是牺牲了所有数字,所以我认为它是搜索类或 Think 方法中的内容

PS:我是为自己做这件事,所以我没有挑战中给出的界限(这就是我上几门课等的原因)

主要课程:

public class TRACER : IChessBot
{
    //Constant Variables
    private const int DEPTH = 4; //Search depth

    //Used classes
    Search findMove = new Search();

    public Move Think(Board board, Timer timer)
    {
        //Variables
        int moveScore; //Score a certain move has
        int bestScore = int.MinValue; //Score of the current best move (low value on start to guarantee update)
        int nodeSearched = 0; //Number of nodes searched
        Move bestMove; //Current best move to be played

        //Generate all legal possible moves
        Move[] moves = board.GetLegalMoves();
        bestMove = moves[0];

        foreach (Move currentMove in moves)
        {
            //for every move -> make move virtually and evaluate how good it is
            board.MakeMove(currentMove);
            moveScore = findMove.MiniMaxAB(board, DEPTH, int.MinValue, int.MaxValue, board.IsWhiteToMove);
            board.UndoMove(currentMove);

            //if the score of this move is better than the current best -> switch
            if (moveScore > bestScore) 
            {
                bestScore = moveScore;
                bestMove = currentMove;
            }
            nodeSearched++;
            Debug.WriteLine("currentMove:{0} | moveScore:{1}", currentMove, moveScore);
        }
        Debug.WriteLine("---- bestMove:{0} | bestScore:{1} ----", bestMove, bestScore);
        return bestMove;
    }
} 

搜索类别:

namespace Chess_Challenge.src.TRACER
{
    internal class Search
    {
        //used Classes
        Evaluation eval = new Evaluation();

        //NegaMax AlphaBeta Pruning Algorith -> returns a high value for the current play (regardless of colour)
        public int MiniMaxAB(Board board, int depth, int alpha, int beta, bool maximizingPlayer)
        {
            //Variables
            int moveScore; //score of the current move

            //if depth is reached then evaluate position
            if (depth == 0)
                return eval.EvaluatePosition(board) * (maximizingPlayer ? -1 : 1);
            //if player is checkmated return low value (bad for white) or high value (bad for black)
            if (board.IsInCheckmate())
                return board.IsWhiteToMove ? int.MinValue : int.MaxValue;
            //if game is a draw return equal
            if (board.IsDraw())
                return 0;

            //Get all legal moves
            Move[] moves = board.GetLegalMoves();
        
            //for every legal move get the best move for black and white
            if (maximizingPlayer)
            {
                moveScore = int.MinValue;
                foreach (Move move in moves)
                {
                    board.MakeMove(move);
                    moveScore = MiniMaxAB(board, depth - 1, alpha, beta, !maximizingPlayer);
                    board.UndoMove(move);

                    alpha = Math.Max(alpha, moveScore);
                    if (beta <= alpha)
                        break;
                }
                return moveScore;
            }

            else
            {
                moveScore = int.MaxValue;
                foreach (Move move in moves)
                {
                    board.MakeMove(move);
                    moveScore = MiniMaxAB(board, depth - 1, alpha, beta, !maximizingPlayer);
                    board.UndoMove(move);

                    beta = Math.Min(beta, moveScore);
                    if (beta <= alpha)
                        break;
                }
                return moveScore;
            }               
        }
    }
}

评估班:

namespace Chess_Challenge.src.TRACER
{
    internal class Evaluation
    {
        // Piece values:                                .,   P,   K,   B,   R,   Q,      K
        private static readonly int[] mgPieceValues = { 0,  80, 335, 363, 460, 940, 100000};
        private static readonly int[] egPieceValues = { 0, 100, 305, 333, 563, 950, 100000};

        //Endgame Transition
        private int egT(Board board)
        {
            return BitOperations.PopCount(board.AllPiecesBitboard);
        }
        //Get the value of a single piece regarding all parameters .TODO

        public int EvaluatePosition(Board board)
        {
            int whiteMaterial = 0;
            int blackMaterial = 0;

            for (PieceType pieceType = PieceType.Pawn; pieceType <= PieceType.King; pieceType++)
            {
                whiteMaterial += mgPieceValues[(int)pieceType] * BitOperations.PopCount(board.GetPieceBitboard(pieceType, true));
                blackMaterial += mgPieceValues[(int)pieceType] * BitOperations.PopCount(board.GetPieceBitboard(pieceType, false));
            }

            return whiteMaterial - blackMaterial;
        }
    }
}

我知道物料平衡是有效的,我认为它是在搜索功能中我没有找到的东西。或者也许这只是我大脑中的一些逻辑错误。

[引擎决定不保护pawn而是滑车的图片][1] [1]:https://i.stack.imgur.com/z4jQD.png

c# logic chess
1个回答
2
投票

我认为交换这两个调用的顺序将大大有助于解决您缺少 N 中的伙伴的问题。如果对手的最后一招将死了你,那么你有多少额外的材料都没有关系!

if (board.IsInCheckmate())
        return board.IsWhiteToMove ? int.MinValue : int.MaxValue;

if (depth == 0)
         return eval.EvaluatePosition(board) * (maximizingPlayer ? -1 : 1);
        //if player is checkmated return low value (bad for white) or high value (bad for black)

我还没有尝试过这些特定的测试位置,但它们看起来非常适合您现在所处的测试阶段。 GIT 中心 国际象棋测试位置

您需要编写一个例程来加载 FEN 板描述,但它提供了一种设置测试位置和查找错误的好方法。然后,您还可以设计自己的测试来检查您的程序是否执行正确的操作。

我找不到我在网上使用的那些,但它们可能有点太难了。它们实际上是一组用 FEN 表示法表示的测试位置,供初学者使用,伴侣为 1,2,3,4,.. 逐渐变得更难(带有答案)。

© www.soinside.com 2019 - 2024. All rights reserved.