Пример #1
0
        /// <summary>
        /// This method runs the ABS algorithm parallel, in the following way:
        /// Only parallelize the calculation of the score of the depth=1 nodes, then take the max of those.
        /// To do the calculation of the depth=1 node correctly, we need to pass on the Invert=true property and set MaxMoves one lower.
        /// Also, we need to sort on evaluation score as usual.
        /// Finally, in order for the pruning to work well, we have to pass on the updated Min (alpha) as much as possible.
        /// Here, we have a trade-off: on the one hand we want to pass on the updated Min value immediately to the next node, but then we can't parallelize anything.
        /// On the other hand, if we parallelize with 8 cores and start calculating 8 nodes immediately with Min = -inf, then those calculations might all be slow, and the parallelizing overhead results in time lost instead of time won.
        /// After some trial, parallelizing 4 seems to have the best results.
        /// </summary>
        /// <param name="originalGame"></param>
        /// <returns></returns>
        private Turn GetTurnParallel(Game originalGame)
        {
            try {
                GameClientStatsCollector?.StartGetTurn(originalGame);

                List <Tuple <Turn, Game, double> > games = new List <Tuple <Turn, Game, double> >();
                foreach (Turn turn in originalGame.GetValidTurns())
                {
                    TurnResult turnResult = null;
                    try {
                        turnResult = originalGame.GameState.PlayTurn(turn);
                        var    game  = originalGame.Clone();
                        double score = Evaluator.Evaluate(game, 1 - game.GameState.InTurnPlayerIndex);
                        // @@@ if the turn is directly winning, we are still going to try to explore the subtree and that leads to problems.
                        games.Add(Tuple.Create(turn, game, score));
                    } finally {
                        // roll back
                        originalGame.GameState.UndoTurn(turn, turnResult);
                    }
                }

                ConcurrentBag <Tuple <Turn, double> > bag = new ConcurrentBag <Tuple <Turn, double> >();
                object dummyLock    = new object();
                double min          = AlphaBetaSearch.GameResultLosing;
                var    orderedGames = games.OrderByDescending(t => t.Item3).ToList();
                Parallel.ForEach(orderedGames,
                                 new ParallelOptions()
                {
                    MaxDegreeOfParallelism = Math.Min(4, Environment.ProcessorCount)
                },
                                 tup => {
                    Turn turn           = tup.Item1;
                    var game            = tup.Item2;
                    AlphaBetaSearch abs = new AlphaBetaSearch(game, MaxMoves - 1, Evaluator, false, DoPrune, CollectStats, DoLog, invert: true, startingMin: min);
                    var gameResults     = abs.GetGameResult();
                    var gameResult      = gameResults.Item1;
                    lock (dummyLock) {
                        min = Math.Max(min, gameResult);
                    }
                    bag.Add(Tuple.Create(turn, gameResult));
                });

                var best = bag.OrderByDescending(tup => tup.Item2).First();
                GameResult = best.Item2;
                return(best.Item1);
            } finally {
                GameClientStatsCollector?.EndGetTurn();
            }
        }
Пример #2
0
 private Turn GetTurnNormal(Game originalGame)
 {
     try {
         GameClientStatsCollector?.StartGetTurn(originalGame);
         int             maxMoves    = GetMaxMoves(originalGame); // MaxMoves
         AlphaBetaSearch abs         = new AlphaBetaSearch(originalGame, maxMoves, Evaluator, false, DoPrune, CollectStats, DoLog);
         var             gameResults = abs.GetGameResult();
         if (gameResults.Item1 == AlphaBetaSearch.GameResultWinning)
         {
             Turn winningTurn = originalGame.GetDirectlyWinningTurn();
             if (winningTurn != null)
             {
                 return(winningTurn);
             }
         }
         GameResult      = gameResults.Item1;
         EvaluationScore = abs.EvaluationScore;
         NodeInfos       = abs.NodeInfos;
         return(gameResults.Item2.OrderByDescending(kvp => kvp.Value).First().Key);
     } finally {
         GameClientStatsCollector?.EndGetTurn();
     }
 }