Ejemplo n.º 1
0
        public override MctsNode Simulate(POGame game)
        {
            POGame gameCopy = game.getCopy();

            // initials root node
            var initLeafs = new List <MctsNode>();
            var root      = new MctsNode(_playerId, new List <MctsNode.ScoreExt> {
                new  MctsNode.ScoreExt(1.0, _scoring)
            }, gameCopy, null, null);

            // simulate
            MctsNode bestNode = Simulate(_deltaTime, root, ref initLeafs);

            return(bestNode);
        }
Ejemplo n.º 2
0
        public override PlayerTask GetMove(POGame poGame)
        {
            var player = poGame.CurrentPlayer;

            // Implement a simple Mulligan Rule
            if (player.MulliganState == Mulligan.INPUT)
            {
                List <int> mulligan = new CustomScore().MulliganRule().Invoke(player.Choice.Choices.Select(p => poGame.getGame().IdEntityDic[p]).ToList());
                return(ChooseTask.Mulligan(player, mulligan));
            }

            if (poGame.CurrentPlayer.Options().Count == 1)
            {
                return(poGame.CurrentPlayer.Options()[0]);
            }

            POGame initialState = poGame.getCopy();

            Node root = new Node();

            Node  selectedNode;
            Node  nodeToSimulate;
            float scoreOfSimulation;
            int   iterations = 0;

            InitializeRoot(root, initialState);

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            while (stopwatch.ElapsedMilliseconds <= MAX_TIME)
            {
                poGame         = initialState;
                selectedNode   = Selection(root, iterations, ref poGame);
                nodeToSimulate = Expansion(selectedNode, ref poGame);

                for (int i = 0; i < NUM_SIMULATIONS; i++)
                {
                    scoreOfSimulation = Simulation(nodeToSimulate, poGame);
                    Backpropagation(nodeToSimulate, scoreOfSimulation);
                    iterations++;
                }
            }
            stopwatch.Stop();

            return(SelectAction.selectTask(SELECTION_ACTION_METHOD, root, iterations, EXPLORE_CONSTANT));
        }
Ejemplo n.º 3
0
        private Node Selection(Node root, int iterations, ref POGame poGame)
        {
            Node   bestNode   = new Node();
            double bestScore  = double.MinValue;
            double childScore = 0;

            POGame pOGameIfSimulationFail = poGame.getCopy();

            foreach (Node node in root.children)
            {
                childScore = TreePolicies.selectTreePolicy(TREE_POLICY, node, iterations, EXPLORE_CONSTANT, ref poGame, SCORE_IMPORTANCE, greedyAgent);
                if (childScore > bestScore)
                {
                    bestScore = childScore;
                    bestNode  = node;
                }
            }
            List <PlayerTask> taskToSimulate = new List <PlayerTask>();

            taskToSimulate.Add(bestNode.task);

            if (bestNode.task.PlayerTaskType != PlayerTaskType.END_TURN)
            {
                poGame = poGame.Simulate(taskToSimulate)[bestNode.task];
            }

            if (poGame == null)
            {
                root.children.Remove(bestNode);
                if (root.children.Count == 0)
                {
                    root = root.parent;
                }

                poGame = pOGameIfSimulationFail;
                return(Selection(root, iterations, ref poGame));
            }

            if (bestNode.children.Count != 0)
            {
                bestNode = Selection(bestNode, iterations, ref poGame);
            }

            return(bestNode);
        }
Ejemplo n.º 4
0
        private Node Expansion(Node leaf, ref POGame poGame)
        {
            Node   nodeToSimulate;
            POGame pOGameIfSimulationFail = poGame.getCopy();

            if (leaf.timesVisited == 0 || leaf.depth >= TREE_MAXIMUM_DEPTH || leaf.task.PlayerTaskType == PlayerTaskType.END_TURN)
            {
                nodeToSimulate = leaf;
            }
            else
            {
                foreach (PlayerTask task in poGame.CurrentPlayer.Options())
                {
                    leaf.children.Add(new Node(task, leaf, leaf.depth + 1));
                }

                nodeToSimulate = leaf.children[0];
                List <PlayerTask> taskToSimulate = new List <PlayerTask>();
                taskToSimulate.Add(nodeToSimulate.task);
                if (nodeToSimulate.task.PlayerTaskType != PlayerTaskType.END_TURN)
                {
                    poGame = poGame.Simulate(taskToSimulate)[nodeToSimulate.task];
                }

                while (poGame == null)
                {
                    if (leaf.children.Count <= 1)
                    {
                        return(leaf);
                    }
                    poGame = pOGameIfSimulationFail;
                    taskToSimulate.Clear();
                    leaf.children.Remove(leaf.children[0]);
                    nodeToSimulate = leaf.children[0];
                    taskToSimulate.Add(nodeToSimulate.task);
                    if (nodeToSimulate.task.PlayerTaskType != PlayerTaskType.END_TURN)
                    {
                        poGame = poGame.Simulate(taskToSimulate)[nodeToSimulate.task];
                    }
                }
            }
            return(nodeToSimulate);
        }
Ejemplo n.º 5
0
        private Node Expand(Node node, POGame state)
        {
            Node child;

            do
            {
                child = node.Children[Rand.Next(node.Children.Count)];
            }while (child.Children.Count > 0);

            POGame childState = state.getCopy();

            childState = childState.Simulate(new List <PlayerTask> {
                child.Action
            })[child.Action];

            InitializeNode(child, childState);

            return(child);
        }
Ejemplo n.º 6
0
        public override PlayerTask GetMove(POGame poGame)
        {
            Controller player = poGame.CurrentPlayer;
            IEnumerable <KeyValuePair <PlayerTask, POGame> > validOpts = poGame.Simulate(player.Options()).Where(x => x.Value != null);
            int optcount        = validOpts.Count();
            int maxMilliseconds = 25000;             // Math.Min(Math.Max(optcount * 2000, 8000), 20000);

            // Implement a simple Mulligan Rule
            if (player.MulliganState == Mulligan.INPUT)
            {
                List <int> mulligan = new MyScore().MulliganRule().Invoke(player.Choice.Choices.Select(p => poGame.getGame().IdEntityDic[p]).ToList());
                return(ChooseTask.Mulligan(player, mulligan));
            }
            PlayerTask returnTask = validOpts.Any() ? GetMoveMCTS(poGame.getCopy(), maxMilliseconds) : player.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN);

            if (returnTask == null)
            {
                returnTask = player.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN);
            }
            return(returnTask);
        }
        public override PlayerTask GetMove(POGame poGame)
        {
            var player = poGame.CurrentPlayer;

            // Implement a simple Mulligan Rule
            if (player.MulliganState == Mulligan.INPUT)
            {
                List <int> mulligan = new ControlScore().MulliganRule().Invoke(player.Choice.Choices.Select(p => poGame.getGame().IdEntityDic[p]).ToList());
                return(ChooseTask.Mulligan(player, mulligan));
            }

            // Apply MCTS and do the best move
            PlayerTask action = null;

            try
            {
                if (mcts)
                {
                    action = MCTS(poGame.getCopy());
                }
                else
                {
                    var legalMoves = poGame.Simulate(player.Options()).Where(x => x.Value != null);
                    return(legalMoves.Any() ?
                           legalMoves.OrderBy(x => Score(x.Value, player.PlayerId)).Last().Key :
                           player.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN));
                }
            }
            catch (NullReferenceException)
            {
                action = player.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN);
            }
            if (myDebug)
            {
                Console.WriteLine();
                Console.WriteLine(poGame.FullPrint());
                Console.WriteLine("Chose action: " + action);
            }
            return(action);
        }
Ejemplo n.º 8
0
        public MctsNode(int playerId, List <ScoreExt> scorings, POGame game, PlayerTask task, MctsNode parent)
        {
            _parent   = parent;
            _scorings = scorings;
            _playerId = playerId;
            _game     = game.getCopy();
            _task     = task;

            VisitCount = 1;

            if (Task != null)
            {
                Dictionary <PlayerTask, POGame> dir = Game.Simulate(new List <PlayerTask> {
                    Task
                });
                POGame newGame = dir[Task];

                Game = newGame;
                // simulation has failed, maybe reduce score?
                if (Game == null)
                {
                    _endTurn = 1;
                }
                else
                {
                    _gameState = Game.State == SabberStoneCore.Enums.State.RUNNING ? 0
                                                : (PlayerController.PlayState == PlayState.WON ? 1 : -1);
                    _endTurn = Game.CurrentPlayer.Id != _playerId ? 1 : 0;

                    foreach (ScoreExt scoring in Scorings)
                    {
                        scoring.Controller = PlayerController;
                        _score            += scoring.Value * scoring.Rate();
                    }
                    _score     /= Scorings.Count;
                    TotalScore += _score;
                }
            }
        }
Ejemplo n.º 9
0
        public PlayerTask Search()
        {
            List <PlayerTask> options = player.Options();

            if (options.Count == 1 && options[0].PlayerTaskType == PlayerTaskType.END_TURN)
            {
                return(options.First());
            }

            StopWatch.Start();
            var selectionStrategy = SelectionStrategies.GetSelectionStrategy(Selection);
            var stateRateStrategy = StateRateStrategies.GetStateRateStrategy(StateRate);

            while (StopWatch.ElapsedMilliseconds < COMPUTATIONAL_BUDGET)
            {
                POGame state    = InitialState.getCopy();
                Node   lastNode = TreePolicy(Root);
                float  delta    = DefaultPolicyHeuristic(lastNode);
                Backup(lastNode, delta);
            }
            StopWatch.Stop();

            return(ChildSelection.SelectBestChild(InitialState, Root, EXPLORATION_CONSTANT, player, selectionStrategy, stateRateStrategy).Action);
        }
 public MinMaxAgentState(POGame game)
 {
     this.currentGameState = game.getCopy();
     this.actionsToReachCurrentGameState = new List <PlayerTask>();
     this.entireActionList = new List <PlayerTask>(currentGameState.CurrentPlayer.Options());
 }
Ejemplo n.º 11
0
        //POGame poGame2;
        public override PlayerTask GetMove(POGame poGame)
        {
            var player = poGame.CurrentPlayer;

            // Implement a simple Mulligan Rule
            if (player.MulliganState == Mulligan.INPUT)
            {
                List <int> mulligan = new CustomScore().MulliganRule().Invoke(player.Choice.Choices.Select(p => poGame.getGame().IdEntityDic[p]).ToList());
                return(ChooseTask.Mulligan(player, mulligan));
            }

#if DEBUG
            Console.WriteLine($"root:{GetGameHashCode(poGame)}");
#endif
            PlayerTask bestAction = null;
            if (poGame.CurrentPlayer.Options().Count == 1)
            {
                bestAction = poGame.CurrentPlayer.Options()[0];
            }
            else
            {
                stopwatchForThisTurn.Start();

                long       bestActionCode = 0;
                Trajectory trajectory     = new Trajectory();

                List <PlayerTask> taskToSimulate = new List <PlayerTask>(1);
                taskToSimulate.Add(null);
                POGame poGameRoot = poGame;

                Node root;
                long gameHashCodeRoot = GetGameHashCode(poGameRoot);
                if (!nodeHashMap.TryGetValue(gameHashCodeRoot, out root))
                {
                    root = new Node();
                    nodeHashMap.Add(gameHashCodeRoot, root);
                }

                Expand(root, poGameRoot);

                /*foreach (var child in root.edges)
                 * {
                 *      Console.WriteLine(child.actionHashCode);
                 * }*/

                long      think_time = (30 * 1000 - stopwatchForThisTurn.ElapsedMilliseconds) / Math.Max(3, 5 - movesInThisTurn);
                Stopwatch stopwatch  = new Stopwatch();
                stopwatch.Start();
                //for (int itr = 0; itr < 100; ++itr)
                while (stopwatch.ElapsedMilliseconds <= think_time)
                {
                    Node node = root;
                    poGame = poGameRoot.getCopy();
                    long gameHashCode       = gameHashCodeRoot;
                    long actionHashCodeNext = 0;
                    bool simulateResult     = true;
                    int  index = 0;
                    trajectory.Clear();

                    // traverse
                    do
                    {
                        index = Select(node);

                        /*if (index >= node.edges.Count)
                         * {
                         *      Console.WriteLine($"{index}, {node.edges.Count}, {node == root}");
                         *      Debugger.Break();
                         * }*/
                        actionHashCodeNext = node.edges[index].actionHashCode;

                        // Until the end of my own turn
                        if (actionHashCodeNext == 0)
                        {
                            trajectory.Add((node, index));
                            break;
                        }

                        taskToSimulate[0] = null;
                        foreach (PlayerTask task in poGame.CurrentPlayer.Options())
                        {
                            if (GetActionHashCode(task) == actionHashCodeNext)
                            {
                                taskToSimulate[0] = task;
                                break;
                            }
                        }
                        if (taskToSimulate[0] == null)
                        {
                            // Hash key conflict
                            return(poGame.CurrentPlayer.Options().First());

                            /*foreach (PlayerTask task in poGame.CurrentPlayer.Options())
                             * {
                             *      Console.WriteLine($"{task}, {GetActionHashCode(task)}");
                             * }
                             * Console.WriteLine("---");
                             * foreach (var edge in node.edges)
                             * {
                             *      Console.WriteLine($"{edge.task}, {edge.actionHashCode}");
                             * }
                             * poGame2 = node.poGame;
                             * Console.WriteLine(poGame2.Turn);
                             * Console.WriteLine(gameHashCode);
                             * Console.WriteLine("---");
                             * foreach (var minion in poGame.CurrentPlayer.BoardZone)
                             * {
                             *      Console.WriteLine(minion.CantAttackHeroes);
                             * }
                             * var tasks = poGame.CurrentPlayer.Options();
                             * foreach (PlayerTask task in tasks)
                             * {
                             *      Console.WriteLine($"{task}, {GetActionHashCode(task)}");
                             * }
                             * Debugger.Break();*/
                        }

                        poGame = poGame.Simulate(taskToSimulate)[taskToSimulate[0]];
                        long gameHashCodeNext = GetGameHashCode(poGame);
                        if (gameHashCode == gameHashCodeNext)
                        {
                            // loop
                            node.edges.RemoveAt(index);
                            continue;
                        }
                        gameHashCode = gameHashCodeNext;

                        trajectory.Add((node, index));

                        if (!nodeHashMap.TryGetValue(gameHashCode, out node))
                        {
                            node = new Node();
                            //node.poGame = poGame;
                            nodeHashMap.Add(gameHashCode, node);
                        }
                    } while (node.edges != null);

                    if (simulateResult == false)
                    {
                        continue;
                    }

                    if (actionHashCodeNext != 0)
                    {
#if DEBUG
                        Console.WriteLine($"expand:{gameHashCode}");
#endif
                        Expand(node, poGame);

                        float value = Simulate(node, poGame);
                        Backup(trajectory, value);
                    }
                    else
                    {
                        float value;
                        if (node.edges[index].visitCount == 0)
                        {
                            value = ScoreToValue(Score(poGame));
                        }
                        else
                        {
                            value = node.edges[index].totalValue / node.edges[index].visitCount;
                        }
                        Backup(trajectory, value);
                    }
                }
                stopwatch.Stop();
                //Console.WriteLine($"{think_time}, {root.visitCount}, {root.visitCount * 1000 / stopwatch.ElapsedMilliseconds} nps");

                // Choose the most visited node
                float best = Single.MinValue;
                foreach (Edge child in root.edges)
                {
                    if (child.visitCount >= best)
                    {
                        best           = child.visitCount;
                        bestActionCode = child.actionHashCode;
                    }
                }

                // Choose an action with a matching hash code
                foreach (PlayerTask task in poGameRoot.CurrentPlayer.Options())
                {
                    if (GetActionHashCode(task) == bestActionCode)
                    {
                        bestAction = task;
                        break;
                    }
                }
            }

            stopwatchForThisTurn.Stop();
            ++movesInThisTurn;
            if (bestAction.PlayerTaskType == PlayerTaskType.END_TURN)
            {
                //Console.WriteLine(movesInThisTurn);
                stopwatchForThisTurn.Reset();
                movesInThisTurn = 0;
                nodeHashMap.Clear();
            }

            return(bestAction);
        }
            public override PlayerTask GetMove(POGame game)
            {
                var player = game.CurrentPlayer;

                // Implement a simple Mulligan Rule
                if (player.MulliganState == Mulligan.INPUT)
                {
                    List <int> mulligan = new CustomScore().MulliganRule().Invoke(player.Choice.Choices.Select(p => game.getGame().IdEntityDic[p]).ToList());
                    return(ChooseTask.Mulligan(player, mulligan));
                }

                var opponent = game.CurrentOpponent;
                var options  = player.Options();



                var validOpts = game.Simulate(options).Where(x => x.Value != null);
                var optcount  = validOpts.Count();

#if DEBUG
                /*
                 * var score_res = validOpts.Select(x => score(x, player.PlayerId, (optcount >= 5) ? ((optcount >= 25) ? 1 : 2) : 3)).OrderBy(x => x.Value);
                 *
                 * Console.WriteLine("Round Nr:" + Convert.ToString(game.Turn));
                 * Console.WriteLine("HeroHP: " + Convert.ToString(player.Hero.Health) + "\tOppHP: " + Convert.ToString(game.CurrentOpponent.Hero.Health));
                 * Console.WriteLine("HeroMinionHP: " + Convert.ToString(player.BoardZone.Sum(p => p.Health)) + "\tOppMinionHP: " + Convert.ToString(game.CurrentOpponent.BoardZone.Sum(p => p.Health)));
                 * Console.WriteLine("HeroMinionAtk: " + Convert.ToString(player.BoardZone.Sum(p => p.AttackDamage)) + "\tOppMinionAtk: " + Convert.ToString(game.CurrentOpponent.BoardZone.Sum(p => p.AttackDamage)));
                 * Console.WriteLine("HeroNbMinions: " + Convert.ToString(player.BoardZone.Count) + "\tOppMinionNB: " + Convert.ToString(game.CurrentOpponent.BoardZone.Count));
                 *
                 *
                 * foreach (var tmp_score in score_res)
                 *      {
                 *
                 *              Console.WriteLine(Convert.ToString(tmp_score.Key) + Convert.ToString(tmp_score.Value));
                 *      }
                 *      Console.WriteLine("-------------------------------------------------------");
                 * //PrintLog(game,  score_res);
                 */
#endif


                /*
                 * if (player.Hero.Health < DEFENSE_HEALTH_THRESHOLD * player.Hero.BaseHealth)
                 *      RuntimeScaling[0] += 0.1;
                 *
                 * if (opponent.Hero.Health < DEFENSE_HEALTH_THRESHOLD * opponent.Hero.Health)
                 *      RuntimeScaling[1] += 0.1;
                 */
                var opt1 = options.Where(x => x.HasSource && x.Source.Card.Name == "Reno Jackson");
                //if (opt1.Count() > 0 && (player.Hero.Health - opponent.Hero.AttackDamage - opponent.BoardZone.Sum(p => p.AttackDamage) <= 3 || player.Hero.Health<10))
                //if (opt1.Count() > 0 && (player.Hero.Health - opponent.Hero.AttackDamage - opponent.BoardZone.Sum(p => p.AttackDamage) <= 6 ))
                if (opt1.Count() > 0 && (player.Hero.Health - opponent.Hero.AttackDamage - opponent.BoardZone.Sum(p => p.AttackDamage) <= 3 || player.Hero.Health < 10))
                {
                    var tmp_game = game.getCopy();
                    //Reno Jackson has 6 mana

                    int mana = (tmp_game.CurrentPlayer.RemainingMana - 6) > 0 ? (tmp_game.CurrentPlayer.RemainingMana - 6) : 0;
                    //Console.WriteLine("mana " + Convert.ToString(tmp_game.CurrentPlayer.BaseMana));

                    var validOptsLoc = tmp_game.Simulate(options).Where(x => x.Value != null);
                    var optcountLoc  = validOptsLoc.Count();

                    var score_resLoc = validOptsLoc.Select(x => score(x, player.PlayerId, (optcountLoc >= 5) ? ((optcountLoc >= 25) ? 1 : 2) : 3)).Where(x => (x.Key.Source == null || x.Key.Source.Cost <= mana || x.Value == Int32.MaxValue)).Where(x => Convert.ToString(x.Key).Contains("Fireblast") != true || mana >= 1).OrderBy(x => x.Value);

                    /*Console.WriteLine("OPTS");
                     *
                     * foreach (var tmp_score in score_resLoc)
                     * {
                     *
                     *      Console.WriteLine(Convert.ToString(tmp_score.Key) + Convert.ToString(tmp_score.Value));
                     * }
                     * Console.WriteLine("-------------------------------------------------------");
                     *
                     * Console.WriteLine("Round Nr:" + Convert.ToString(game.Turn));
                     * Console.WriteLine("HeroHP: " + Convert.ToString(player.Hero.Health) + "\tOppHP: " + Convert.ToString(game.CurrentOpponent.Hero.Health));
                     * Console.WriteLine("HeroMinionHP: " + Convert.ToString(player.BoardZone.Sum(p => p.Health)) + "\tOppMinionHP: " + Convert.ToString(game.CurrentOpponent.BoardZone.Sum(p => p.Health)));
                     * Console.WriteLine("HeroMinionAtk: " + Convert.ToString(player.BoardZone.Sum(p => p.AttackDamage)) + "\tOppMinionAtk: " + Convert.ToString(game.CurrentOpponent.BoardZone.Sum(p => p.AttackDamage)));
                     * Console.WriteLine("HeroNbMinions: " + Convert.ToString(player.BoardZone.Count) + "\tOppMinionNB: " + Convert.ToString(game.CurrentOpponent.BoardZone.Count));
                     *
                     * //Console.WriteLine("OPTS:" + Convert.ToString(score_res.First()));
                     * //Console.WriteLine("OPTS:" + Convert.ToString(score_res.Last()));
                     * //Console.WriteLine("OPTS:" + Convert.ToString(score_res.Count()));
                     */

                    if (score_resLoc.Count() > 1)
                    {
                        //Console.WriteLine("OPTION TAKEN" + Convert.ToString(score_resLoc.Last().Key));

                        return(score_resLoc.Last().Key);
                    }


                    //Console.WriteLine("REEEEEEEEEEENNNNNNNNNNNOOOOOOOOOOOOOOO:" + Convert.ToString(player.Hero.Health));
                    //Console.WriteLine("OPTS:" + Convert.ToString(opt1.First()));
                    return(opt1.First());
                }

                var returnValue = validOpts.Any() ?
                                  validOpts.Select(x => score(x, player.PlayerId, (optcount >= 5) ? ((optcount >= 25) ? 1 : 2) : 3)).OrderBy(x => x.Value).Where(x => Convert.ToString(x.Key).Contains("Reno Jackson") != true).Last().Key :
                                  player.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN);

                return(returnValue);

                KeyValuePair <PlayerTask, int> score(KeyValuePair <PlayerTask, POGame> state, int player_id, int max_depth = 3)
                {
                    int max_score = int.MinValue;

                    if (max_depth > 0 && state.Value.CurrentPlayer.PlayerId == player_id)
                    {
                        var subactions = state.Value.Simulate(state.Value.CurrentPlayer.Options()).Where(x => x.Value != null);

                        foreach (var subaction in subactions)
                        {
                            max_score = Math.Max(max_score, score(subaction, player_id, max_depth - 1).Value);
                        }
                    }
                    max_score = Math.Max(max_score, Score(state.Value, player_id));
                    return(new KeyValuePair <PlayerTask, int>(state.Key, max_score));
                }
            }
Ejemplo n.º 13
0
 public MinMaxAgentState(POGame game)
 {
     State = game.getCopy();
     ActionsToReachState = new List <PlayerTask>();
     EntireActionList    = new List <PlayerTask>(State.CurrentPlayer.Options());
 }
        public override MctsNode Simulate(POGame game)
        {
            Console.WriteLine("Current win rate is " + 0);
            POGame gameCopy = game.getCopy();

            // initials root node
            var children = new List <MctsNode>();
            var parent   = new MctsNode(_playerId, new List <MctsNode.ScoreExt> {
                new MctsNode.ScoreExt(1, _scoring)
            }, gameCopy, null, null);

            // simulate
            MctsNode bestNode = Simulate(_deltaTime, parent, ref children);

            // initials opponent's history
            Initialize(gameCopy);

            var simulationQueue = new Queue <KeyValuePair <POGame, List <MctsNode> > >();

            simulationQueue.Enqueue(new KeyValuePair <POGame, List <MctsNode> >(gameCopy, children));

            int i = 0;

            while (i < _predictionParameters.SimulationDepth &&
                   simulationQueue.Count > 0)
            {
                // calculate the lower and upper time bound of the current depth
                double lowerSimulationTimeBound = _deltaTime + i * (2 * _deltaTime);

                KeyValuePair <POGame, List <MctsNode> > simulation = simulationQueue.Dequeue();
                List <MctsNode> leafs = simulation.Value;

                leafs = leafs.Where(l => l.Game != null)
                        .OrderByDescending(l => l.Score)
                        .Take(leafs.Count > _predictionParameters.LeafCount
                                                ? _predictionParameters.LeafCount : leafs.Count)
                        .ToList();
                if (leafs.Count < 0)
                {
                    return(bestNode);
                }

                Controller        opponent       = GetOpponent(simulation.Key);
                List <Prediction> predicitionMap = GetPredictionMap(simulation.Key, opponent);
                var oldSimulations = new Dictionary <POGame, List <MctsNode> >();

                // the simulation time for one leaf
                double timePerLeaf = (2 * _deltaTime) / leafs.Count;

                // get all games from all leaf nodes
                for (int j = 0; j < leafs.Count; j++)
                {
                    // calculate the lower time bound of the current leaf
                    double lowerLeafTimeBound = lowerSimulationTimeBound + j * timePerLeaf;

                    MctsNode leafNode = leafs[j];
                    POGame   oppGame  = leafNode.Game;
                    double   leafScore;
                    // XXX: game can be null

                    leafScore = SimulateOpponentWithPrediction(lowerLeafTimeBound, timePerLeaf,
                                                               oppGame, opponent, predicitionMap, ref oldSimulations);
                    // back-propagate score
                    backpropagate(leafNode, leafScore);
                }



                // add new simulations
                foreach (KeyValuePair <POGame, List <MctsNode> > sim in oldSimulations)
                {
                    simulationQueue.Enqueue(sim);
                }
                i++;
            }
            MctsNode resultnode = parent.Children
                                  .OrderByDescending(c => c.TotalScore)
                                  .First();

            Console.WriteLine("Current win rate is " + resultnode.TotalScore);
            return(resultnode);
        }
        private double SimulateOpponentWithPrediction(double lowerTimeBound, double timePerLeaf, POGame oppGame, Controller opponent,
                                                      IReadOnlyList <Prediction> predicitionMap, ref Dictionary <POGame, List <MctsNode> > newSimulations)
        {
            double predictionScore = 0;

            if (!(predicitionMap?.Any() ?? false))
            {
                return(predictionScore);
            }
            int denominator = predicitionMap.Count;
            var scorings    = predicitionMap.GroupBy(p => p.Deck.Scoring)
                              .Select(c => new MctsNode.ScoreExt(((double)c.Count() / denominator), c.Key))
                              .OrderByDescending(s => s.Value).ToList();

            // the simulation time for one prediction
            double timePerPrediction = timePerLeaf / predicitionMap.Count;

            // use prediction for each game
            for (int i = 0; i < predicitionMap.Count; i++)
            {
                Prediction   prediction = predicitionMap[i];
                SetasideZone setasideZone;
                setasideZone = new SetasideZone(opponent);

                // create deck zone
                List <Card> deckCards = prediction.Deck.Cards;
                DeckZone    deckZone;
                deckZone = new DeckZone(opponent);
                createZone(opponent, deckCards, deckZone, ref setasideZone);
                deckZone.Shuffle();

                // create hand zone
                List <Card> handCards = prediction.Hand.Cards;
                HandZone    handZone;
                handZone = new HandZone(opponent);
                createZone(opponent, handCards, handZone, ref setasideZone);

                var oppLeafNodes = new List <MctsNode>();

                // forward game
                POGame forwardGame = oppGame.getCopy();

                // upper time bound for simulation the opponent using the current prediction
                double oppSimulationTime = lowerTimeBound + (i + 1) * timePerPrediction / 2;

                // simulate opponent's moves
                while (forwardGame != null &&
                       forwardGame.State == SabberStoneCore.Enums.State.RUNNING &&
                       forwardGame.CurrentPlayer.Id == opponent.Id)
                {
                    // simulate
                    var      oppRoot     = new MctsNode(opponent.Id, scorings, forwardGame, null, null);
                    MctsNode bestOppNode = Simulate(oppSimulationTime, oppRoot, ref oppLeafNodes);
                    // get solution
                    List <PlayerTask> solutions = bestOppNode.GetSolution();
                    for (int j = 0; j < solutions.Count && (forwardGame != null); j++)
                    {
                        PlayerTask oppTask = solutions[j];
                        Dictionary <PlayerTask, POGame> dir = forwardGame.Simulate(new List <PlayerTask> {
                            oppTask
                        });
                        forwardGame = dir[oppTask];

                        if (forwardGame != null && forwardGame.CurrentPlayer.Choice != null)
                        {
                            break;
                        }
                    }
                }

                // upper time bound for simulation the player using the forwarded game
                double simulationTime = oppSimulationTime + timePerPrediction / 2;
                double score          = 0;
                var    leafs          = new List <MctsNode>();

                // simulate player using forwarded opponent game
                while (forwardGame != null &&
                       forwardGame.State == SabberStoneCore.Enums.State.RUNNING &&
                       forwardGame.CurrentPlayer.Id == _playerId)
                {
                    // simulate
                    var root = new MctsNode(_playerId, new List <MctsNode.ScoreExt> {
                        new MctsNode.ScoreExt(1.0, _scoring)
                    }, forwardGame, null, null);
                    MctsNode bestNode = Simulate(simulationTime, root, ref leafs);
                    // get solution
                    List <PlayerTask> solutions = bestNode.GetSolution();
                    for (int j = 0; j < solutions.Count && (forwardGame != null); j++)
                    {
                        PlayerTask task = solutions[j];
                        Dictionary <PlayerTask, POGame> dir = forwardGame.Simulate(new List <PlayerTask> {
                            task
                        });
                        forwardGame = dir[task];

                        if (forwardGame != null && forwardGame.CurrentPlayer.Choice != null)
                        {
                            break;
                        }
                    }
                    // TODO: maybe penalty forwardGame == null
                    score = bestNode.TotalScore;
                }
                predictionScore += score;

                if (forwardGame != null)
                {
                    newSimulations.Add(forwardGame, leafs);
                }
            }
            return(predictionScore);
        }