예제 #1
0
        //static Dictionary<Game, SearchResultInfo> _games = new Dictionary<Game, SearchResultInfo>();
        public static unsafe SearchResultInfo Search(uint depth, bool isMax, Game theGame, int alpha, int beta)
        {
            Game.Logger($"-----------------Start searching depth = {depth} alpha = {alpha}------------------");
            theGame.LogGrid();
            if (isMax)
            {
                if (depth == 0)
                {
                    Game.Logger($"Depth = 0, score : {Evaluate(theGame, depth)}");
                    return(new SearchResultInfo
                    {
                        Score = Evaluate(theGame, depth)
                    });
                }
                var       newGame  = new Game(theGame);
                Direction?bestMove = null;
                foreach (var direction in Directions)
                {
                    Game.Logger($"Searching {direction}");
                    //var game = new Game(theGame);
                    var res = newGame.Update(direction);
                    if (res.HasMoved)
                    {
                        if (res.HasWon)
                        {
                            return new SearchResultInfo
                                   {
                                       Score         = int.MaxValue,
                                       MoveDirection = direction
                                   }
                        }
                        ;
                        else
                        {
                            Game.Logger("Searching down by max.");

                            var result = Search(depth - 1, false, newGame, alpha, beta);
                            if (result.Score > alpha)
                            {
                                bestMove = direction;
                                alpha    = result.Score;
                                if (alpha >= beta)
                                {
                                    break;
                                }
                            }
                        }
                    }
                    newGame.Reset(theGame);
                }
                Game.Logger($"result = {alpha} {bestMove}");
                return(new SearchResultInfo
                {
                    Score = alpha,
                    MoveDirection = bestMove
                });
            }
            else
            {
                var bitmap      = theGame.GetBitmap();
                var ptr         = stackalloc int[48];
                var cellScores  = new StaticList(ptr);
                var emptyCells  = new StaticList(ptr + 16);
                int lowestScore = int.MaxValue;
                for (int i = 0; i < 16; ++i)
                {
                    ushort mask = (ushort)(1 << i);
                    if ((bitmap & mask) == 0)
                    {
                        var x = i / 4;
                        var y = i % 4;
                        theGame.AddCellTrivial(x, y, 1);
                        var score = theGame.Smoothness() - theGame.Dispersion();
                        Game.Logger($"Add cell at {x}, {y} gets score {score}, Smooth = {theGame.Smoothness()}, Monotonic = {theGame.Monotonicity()} Dispersion = {theGame.Dispersion()}");
                        theGame.LogGrid();
                        cellScores.Add(score);
                        lowestScore = Math.Min(score, lowestScore);
                        theGame.RemoveCellTrivial(x, y);
                        emptyCells.Add(i);
                    }
                }

                var lowestCells = new StaticList(ptr + 32);
                for (int i = 0; i < emptyCells.Count; ++i)
                {
                    if (cellScores[i] == lowestScore)
                    {
                        lowestCells.Add(emptyCells[i]);
                    }
                }
                for (int i = 0; i < lowestCells.Count; ++i)
                {
                    var cell = lowestCells[i];
                    Game.Logger($"Add cell at {cell}, score is {lowestScore}");
                    var x = cell / 4;
                    var y = cell % 4;
                    theGame.AddCellTrivial(x, y, 1);
                    Game.Logger("Searching down by min.");
                    var result = Search(depth, true, theGame, alpha, beta);
                    theGame.RemoveCellTrivial(x, y);
                    if (result.Score < beta)
                    {
                        beta = result.Score;
                        Game.Logger($"Beta updated {beta}");
                        if (alpha >= beta)
                        {
                            Game.Logger("Cutoff");
                            break;
                        }
                    }
                }
                return(new SearchResultInfo
                {
                    Score = beta,
                    MoveDirection = null
                });
            }
        }