You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Monte Carlo Tree Search的国际象棋Bot未达预期水平排查

蒙特卡洛树搜索国际象棋Bot的BUG排查求助

我正在为Sebastian Lague的「Tiny Chess Bots」竞赛开发一款国际象棋Bot,它采用带Upper Confidence Bounds的Monte Carlo Tree Search实现,但当前表现极差——即便将迭代次数提升至100万+,仍会出现第4步丢皇后这类低级失误,因此我怀疑代码存在问题。

以下是C# Mybot.cs文件的完整代码,其中Monte Carlo Tree Search的实现位于文件后半部分:

public static class Rand{
    public static Random random = new ();
}

public class Node{
    public int visits = 2;
    public double score = 1;
    public Move move;
    public Node parent;
    public List<Node> children = new List<Node>{};
    //public Node LastBestChild = null!;

    public Node(Move m, Node p){
        move = m; //move is from parent to node
        parent = p;
    }

    public void ExpandNode(Board b){
        Move[] moves = b.GetLegalMoves();
        for(int l=0; l<moves.Length; l++){
            children.Add(new Node(moves[l], this));
        }
    }

    public void Update(double result){
        visits += 1;
        //result: 0 for loss and 1 for win and 0.5 for draw
        score +=  result;

        }

    public bool IsLeaf(){
        return (children.Count == 0);
    }

    public bool HasParent(){
        return (parent != null);
    }

    public double UCBValue(){
        return ((score/visits)+ 0.4*Math.Sqrt(Math.Log(parent.visits)/visits));
    }

    public Node MaxUCB(){
        double maxVal = children[0].UCBValue();
        Node maxNode = children[0];
        foreach(Node n in children){
            double temp = n.UCBValue();
            //Console.WriteLine(n.move.ToString() + ": UCB = " + temp.ToString());
            if(temp > maxVal || (temp == maxVal && Rand.random.Next(0,1) == 0)){
                maxVal = temp;
                maxNode = n;
            }
        }
        return maxNode;
    }

    public Node MaxVisits(){
        double maxVal = children[0].visits;
        Node maxNode = children[0];
        foreach(Node n in children){
            Console.WriteLine(n.move.ToString() + ": visits = " + n.visits.ToString() + ": score = " + n.score.ToString());
            double temp = n.visits;
            if(temp > maxVal || (temp == maxVal && Rand.random.Next(0,1) == 0)){
                maxVal = temp;
                maxNode = n;
            }
        }
        Console.WriteLine("###########################################################################");
        return maxNode;
    }

};



public class MyBot : IChessBot
{
    public Move Think(Board board, Timer timer)
    {
        Move[] moves = board.GetLegalMoves();
        Node root = new Node(Move.NullMove, null!);

        for(int i = 0; i < 20000; i++){
            Board board1 = Board.CreateBoardFromFEN(board.GetFenString());
            Node currentNode = root;
            
            //Select
            while (!currentNode.IsLeaf()){
                currentNode = currentNode.MaxUCB();
                
                //Update Board when moving from Node to Node
                board1.MakeMove(currentNode.move);
            }

            //Expansion
            if (board1.GetLegalMoves().Length > 0){
                currentNode.ExpandNode(board1);
                currentNode = currentNode.children[Rand.random.Next(0, currentNode.children.Count)];
                
                //Update Board when moving from Node to Node
                board1.MakeMove(currentNode.move);
            }


            //Rollouts
            Move[] legalMoves = board1.GetLegalMoves();
            int numCurrentMoves = legalMoves.Length;
            bool colour = board.IsWhiteToMove;

            while (!board1.IsInCheckmate() && !board1.IsDraw()){ 
                Move moveToMake = legalMoves[Rand.random.Next(0, numCurrentMoves)];
            
                //Update board
                board1.MakeMove(moveToMake);
            
                legalMoves = board1.GetLegalMoves();
                numCurrentMoves = legalMoves.Length;

                colour  = !colour;
            }

            //Get results
            double result =0;
            if(board1.IsDraw()){
                result = 0.5;
            } else{
                if (board1.IsWhiteToMove == colour){
                    result = 1;
                }
            }

            //Back propagation
            while (currentNode.HasParent()){
                currentNode.Update(result);
                currentNode = currentNode.parent;
                result = 1-result;
            }
            currentNode.Update(result);


        }

        //Select Best Move
        Move bestMove = root.MaxVisits().move;
        return bestMove;
    }
}

我已尝试以下调试手段,但均未解决问题:

  • 反转布尔标志——怀疑因多一次取反而导致最大化了损失而非收益;
  • 记录顶层节点的分数与访问量——未发现明显异常;
  • 调整迭代次数与UCBValue函数中的探索常数——效果甚微。

现寻求帮助排查代码错误,以提升Bot的对局水平。

内容的提问来源于stack exchange,提问作者Jakub Skop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:54:57