Unity 在尝试运行棋盘游戏模拟时冻结和崩溃

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

我创建了棋盘游戏 Santorini 的 2D 克隆以及 AI。 AI 使用带有 Alpha Beta 修剪的 Minimax 算法,我能够调整算法运行的深度。 AI 似乎工作正常,我能够“玩”并观看两个 AI 的相互对抗,深度达到 100,游戏运行得很好。

我遇到的问题发生在我尝试运行 AI 相互对战的“模拟”时。我在其中创建了一个新的 Unity 场景,其中所有 UI 从一些信息中删除了一部分,例如玩过的游戏,AI 赢得了什么等......游戏的核心功能没有被触及,但是每当我尝试运行在像 5 这样非常低的深度下进行模拟,团结是冻结的。我想也许如果我离开它足够长的时间它会回来,但似乎没有。我必须关闭并重新加载 Unity。

我不想一次运行多个游戏,模拟一次只运行一个游戏,我能够在随机 AI 上运行模拟就好了。所以我假设问题来自 Minimax 算法,但正如我之前提到的,它在我的其他“播放”场景中工作得很好,所以我不确定出了什么问题。

这是我的 minimax 算法的主要代码。

public (Builder, Square, Square) getAiMove(Board board, bool team)
    {
        //set best score to +/- inf depending on team
        int bestScore = team ? int.MinValue : int.MaxValue;
        playerSearching = team;

        //generate all possible moves for team from current position
        List<(Builder, Square)> moves = board.FindTeamMoves(team);
        //create best move and builds (start as null)
        (Builder, Square) bestMove = (null, null);
        Square bestBuild = null;

        //loop through every move generated, each returning a score, where the best score/move will be selected
        foreach ((Builder,Square) move in moves)
        {
            // create copy of board and builder, copy move on new board
            Board boardCopy = board.CopyBoard();
            Builder builderCopy = boardCopy.squares[(int)move.Item1.BuilderSquare.Pos.x, (int)move.Item1.BuilderSquare.Pos.y].OccupiedBuilder;
            Square moveCopy = boardCopy.squares[(int)move.Item2.Pos.x, (int)move.Item2.Pos.y];

            int score = 0;
            
            //make move on new board
            boardCopy.MakeMove(builderCopy, moveCopy);

            //find all possible builds from new position
            List<Square> builds = boardCopy.FindBuilds(builderCopy.BuilderSquare.Pos);

            //loop through all possible builds
            foreach (Square build in builds)
            {
                // create another copy of board to try every possible build
                Board boardCopyTwo = boardCopy.CopyBoard();
                Square buildCopy = boardCopyTwo.squares[(int)build.Pos.x, (int)build.Pos.y];

                //make build on new board
                boardCopyTwo.Build(buildCopy);

                //call minimaxAB to generate a score
                score = Minimax(boardCopyTwo, maxDepth, !team);

                //if minimax returns a score better than current, replace best score
                //black team is aiming for a score as high as possible while white team is aimijng for a score as low as possible
                if ((team && score > bestScore) || (!team && score < bestScore))
                {
                    //update score, move and build
                    bestScore = score;
                    bestMove = move;
                    bestBuild = board.squares[(int)build.Pos.x, (int)build.Pos.y];
                }
            }
        }
        //format move and build to be returned        
        (Builder, Square, Square) AiTurn = (bestMove.Item1, bestMove.Item2, bestBuild);
        return AiTurn;
    }

    //Minimax algorithm with Alpha Beta Pruning enabled
    public int Minimax(Board board, int depth, bool maximizingPlayer)
    {
        //? WHITE = MIN PLAYER +inf
        //? BLACK = MAX PLAYER -inf

        bool checkWinVal = board.CheckWin(!maximizingPlayer);
        bool checkLossVal = board.CheckLoss(maximizingPlayer);
        
        if (checkWinVal || checkLossVal || depth == 0)
        {
            //generate score for given board position and return            
            if (aiHeuristic == 1)
            {
                return board.BasicEvaluation(maximizingPlayer, checkLossVal, depth);
            }
            else if (aiHeuristic == 2)
            {
                return board.evaluateBoard(maximizingPlayer, checkLossVal);
            }   
        }

        if (maximizingPlayer) //MAX PLAYER (BLACK) TURN
        {
            //set best move to negative inf
            int maxScore =  int.MinValue;
            //Generate every possible move for black team
            List<(Builder, Square)> moves = board.FindTeamMoves(true);

            // Check every possible move at this depth
            foreach ((Builder, Square) move in moves)
            {
                Board boardCopy = board.CopyBoard();
                Builder builderCopy = boardCopy.squares[(int)move.Item1.BuilderSquare.Pos.x, (int)move.Item1.BuilderSquare.Pos.y].OccupiedBuilder;
                Square moveCopy = boardCopy.squares[(int)move.Item2.Pos.x, (int)move.Item2.Pos.y];

                boardCopy.MakeMove(builderCopy, moveCopy);

                List<Square> builds = boardCopy.FindBuilds(builderCopy.BuilderSquare.Pos);

                foreach (Square build in builds)
                {
                    Board boardCopyTwo = boardCopy.CopyBoard();
                    Square buildCopy = boardCopyTwo.squares[(int)build.Pos.x, (int)build.Pos.y];

                    boardCopyTwo.Build(buildCopy);

                    //recursively call Minimax (flip flopping between players until max depth reached)
                    int score = Minimax(boardCopyTwo, depth - 1, false);

                    //get max score
                    maxScore = Math.Max(maxScore, score);
                }
            }
            return maxScore;
        }
        else //MIN PLAYER (WHITE) TURN
        {
            // set best move to pos inf
            int minScore =  int.MaxValue;
            //Generate every possible move for white team
            List<(Builder, Square)> moves = board.FindTeamMoves(false);

            // Check every possible move at this depth
            foreach ((Builder, Square) move in moves)
            {
                Board boardCopy = board.CopyBoard();
                Builder builderCopy = boardCopy.squares[(int)move.Item1.BuilderSquare.Pos.x, (int)move.Item1.BuilderSquare.Pos.y].OccupiedBuilder;
                Square moveCopy = boardCopy.squares[(int)move.Item2.Pos.x, (int)move.Item2.Pos.y];

                boardCopy.MakeMove(builderCopy, moveCopy);

                List<Square> builds = boardCopy.FindBuilds(builderCopy.BuilderSquare.Pos);

                foreach (Square build in builds)
                {
                    Board boardCopyTwo = boardCopy.CopyBoard();
                    Square buildCopy = boardCopyTwo.squares[(int)build.Pos.x, (int)build.Pos.y];

                    boardCopyTwo.Build(buildCopy);

                    int score = Minimax(boardCopyTwo, depth - 1, true);
                    
                    minScore = Math.Min(minScore, score);
                }
            }
            return minScore;
        }
    }

还包括指向其他游戏文件的链接:

https://pastebin.com/qFfZt1NA -- 游戏管理器(核心游戏功能)

https://pastebin.com/MJ4kWAR6 -- 极小极大算法

https://pastebin.com/VE8k48iU -- SimulationUI(模拟场景)

https://pastebin.com/9Um1QdN7 -- boardUI(游戏场景)

任何帮助解决这个问题的人都将不胜感激!

c# algorithm unity3d freeze
© www.soinside.com 2019 - 2024. All rights reserved.