Esempio n. 1
0
 /// <summary>
 /// Constructs a new instance of LSIBot with a <see cref="Controller"/> representing the player.
 /// </summary>
 /// <param name="player">The player.</param>
 /// <param name="allowPerfectInformation">[Optional] Whether or not this bot is allowed perfect information about the game state (i.e. no obfuscation and therefore no determinisation). Default value is false.</param>
 /// <param name="ensembleSize">[Optional] The size of the ensemble to use. Default value is 1.</param>
 /// <param name="playoutBotType">[Optional] The type of playout bot to be used during playouts. Default value is <see cref="PlayoutBotType.MAST"/>.</param>
 /// <param name="mastSelectionType">[Optional] The type of selection strategy used by the M.A.S.T. playout. Default value is <see cref="MASTPlayoutBot.SelectionType.EGreedy"/>.</param>
 /// <param name="playoutTurnCutoff">[Optional] The amount of turns after which to stop a simulation. Default value is <see cref="Constants.DEFAULT_PLAYOUT_TURN_CUTOFF"/>.</param>
 /// <param name="budgetType">[Optional] The type of budget that this bot will use. Default value is <see cref="BudgetType.Iterations"/>.</param>
 /// <param name="samples">[Optional] The budget for the amount of iterations LSI can use. Default value is <see cref="Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET"/>.</param>
 /// <param name="time">[Optional] The budget for the amount of milliseconds LSI can spend on searching. Default value is <see cref="Constants.DEFAULT_COMPUTATION_TIME_BUDGET"/>.</param>
 /// <param name="generationBudgetPercentage">[Optional] The percentage of the budget that should be spent during the generation phase. Default value is <see cref="Constants.DEFAULT_LSI_BUDGET_GENERATION_PERCENTAGE"/>.</param>
 /// <param name="budgetEstimationType">[Optional] The type of strategy used to estimate the budget for LSI. Default value is <see cref="BudgetEstimationType.AverageSampleTime"/>.</param>
 /// <param name="useHeuristicEvaluation">[Optional] Whether or not to use the HeuristicBot's evaluation function. Default value is false.</param>
 /// <param name="debugInfoToConsole">[Optional] Whether or not to write debug information to the console. Default value is false.</param>
 public LSIBot(Controller player,
               bool allowPerfectInformation  = false,
               int ensembleSize              = 1,
               PlayoutBotType playoutBotType = PlayoutBotType.MAST,
               MASTPlayoutBot.SelectionType mastSelectionType = MASTPlayoutBot.SelectionType.EGreedy,
               int playoutTurnCutoff                     = Constants.DEFAULT_PLAYOUT_TURN_CUTOFF,
               BudgetType budgetType                     = BudgetType.Iterations,
               int samples                               = Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET,
               long time                                 = Constants.DEFAULT_COMPUTATION_TIME_BUDGET,
               double generationBudgetPercentage         = Constants.DEFAULT_LSI_BUDGET_GENERATION_PERCENTAGE,
               BudgetEstimationType budgetEstimationType = BudgetEstimationType.AverageSampleTime,
               bool useHeuristicEvaluation               = false,
               bool debugInfoToConsole                   = false)
     : this(allowPerfectInformation, ensembleSize, playoutBotType, mastSelectionType, playoutTurnCutoff, budgetType, samples, time, generationBudgetPercentage, budgetEstimationType, useHeuristicEvaluation, debugInfoToConsole)
 {
     SetController(player);
 }
 /// <summary>
 /// Constructs a new instance of NMCTSBot with a <see cref="Controller"/> representing the player.
 /// </summary>
 /// <param name="player">The player.</param>
 /// <param name="allowPerfectInformation">[Optional] Whether or not this bot is allowed perfect information about the game state (i.e. no obfuscation and therefore no determinisation). Default value is false.</param>
 /// <param name="ensembleSize">[Optional] The size of the ensemble to use. Default value is 1.</param>
 /// <param name="playoutBotType">[Optional] The type of playout bot to be used during playouts. Default value is <see cref="PlayoutBotType.MAST"/>.</param>
 /// <param name="mastSelectionType">[Optional] The type of selection strategy used by the MAST playout. Default value is <see cref="MASTPlayoutBot.SelectionType.EGreedy"/>.</param>
 /// <param name="budgetType">[Optional] The type of budget that this bot will use. Default value is <see cref="BudgetType.Iterations"/>.</param>
 /// <param name="iterations">[Optional] The budget for the amount of iterations NMCTS can use. Default value is <see cref="Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET"/>.</param>
 /// <param name="time">[Optional] The budget for the amount of milliseconds NMCTS can spend on searching. Default value is <see cref="Constants.DEFAULT_COMPUTATION_TIME_BUDGET"/>.</param>
 /// <param name="playoutTurnCutoff">[Optional] The amount of turns after which to stop a simulation. Default value is <see cref="Constants.DEFAULT_PLAYOUT_TURN_CUTOFF"/>.</param>
 /// <param name="globalPolicy">[Optional] The exploration-threshold for the e-greedy global policy. Default value is <see cref="Constants.DEFAULT_NMCTS_GLOBAL_POLICY"/>.</param>
 /// <param name="localPolicy">[Optional] The exploration-threshold for the e-greedy local policy. Default value is <see cref="Constants.DEFAULT_NMCTS_LOCAL_POLICY"/>.</param>
 /// <param name="useHeuristicEvaluation">[Optional] Whether or not to use the HeuristicBot's evaluation function. Default value is false.</param>
 /// <param name="debugInfoToConsole">[Optional] Whether or not to write debug information to the console. Default value is false.</param>
 public NMCTSBot(Controller player,
                 bool allowPerfectInformation  = false,
                 int ensembleSize              = 1,
                 PlayoutBotType playoutBotType = PlayoutBotType.MAST,
                 MASTPlayoutBot.SelectionType mastSelectionType = MASTPlayoutBot.SelectionType.EGreedy,
                 BudgetType budgetType       = BudgetType.Iterations,
                 int iterations              = Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET,
                 long time                   = Constants.DEFAULT_COMPUTATION_TIME_BUDGET,
                 int playoutTurnCutoff       = Constants.DEFAULT_PLAYOUT_TURN_CUTOFF,
                 double globalPolicy         = Constants.DEFAULT_NMCTS_GLOBAL_POLICY,
                 double localPolicy          = Constants.DEFAULT_NMCTS_LOCAL_POLICY,
                 bool useHeuristicEvaluation = false,
                 bool debugInfoToConsole     = false)
     : this(allowPerfectInformation, ensembleSize, playoutBotType, mastSelectionType, budgetType, iterations, time, playoutTurnCutoff, globalPolicy, localPolicy, useHeuristicEvaluation, debugInfoToConsole)
 {
     SetController(player);
 }
Esempio n. 3
0
 /// <summary>
 /// Constructs a new instance of MCTSBot with a <see cref="Controller"/> representing the player.
 /// </summary>
 /// <param name="player">The player.</param>
 /// <param name="allowPerfectInformation">[Optional] Whether or not this bot is allowed perfect information about the game state (i.e. no obfuscation and therefore no determinisation). Default value is false.</param>
 /// <param name="ensembleSize">[Optional] The size of the ensemble to use. Default value is 1.</param>
 /// <param name="playoutBotType">[Optional] The type of playout bot to be used during playouts. Default value is <see cref="PlayoutBotType.MAST"/>.</param>
 /// <param name="mastSelectionType">[Optional] The type of selection strategy used by the M.A.S.T. playout. Default value is <see cref="MASTPlayoutBot.SelectionType.EGreedy"/>.</param>
 /// <param name="retainTaskStatistics">[Optional] Whether or not to retain the PlayerTask statistics between searches. Default value is false.</param>
 /// <param name="budgetType">[Optional] The type of budget that this bot will use. Default value is <see cref="BudgetType.Iterations"/>.</param>
 /// <param name="iterations">[Optional] The budget for the amount of iterations MCTS can use. Default value is <see cref="Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET"/>.</param>
 /// <param name="time">[Optional] The budget for the amount of milliseconds MCTS can spend on searching. Default value is <see cref="Constants.DEFAULT_COMPUTATION_TIME_BUDGET"/>.</param>
 /// <param name="minimumVisitThresholdForExpansion">[Optional] The minimum amount of times a node has to be visited before it can be expanded. Default value is <see cref="Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_EXPANSION"/>.</param>
 /// <param name="minimumVisitThresholdForSelection">[Optional] The minimum number of visits before using the NodeEvaluation to select the best node. Default value is <see cref="Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_SELECTION"/>.</param>
 /// <param name="playoutTurnCutoff">[Optional] The amount of turns after which to stop a simulation. Default value is <see cref="Constants.DEFAULT_PLAYOUT_TURN_CUTOFF"/>.</param>
 /// <param name="ucbConstantC">[Optional] Value for the c-constant in the UCB1 formula. Default value is <see cref="Constants.DEFAULT_UCB1_C"/>.</param>
 /// <param name="dimensionalOrdering">[Optional] The ordering for dimensions when using Hierarchical Expansion. Default value is <see cref="DimensionalOrderingType.None"/>.</param>
 /// <param name="useHeuristicEvaluation">[Optional] Whether or not to use the HeuristicBot's evaluation function. Default value is false.</param>
 /// <param name="debugInfoToConsole">[Optional] Whether or not to write debug information to the console. Default value is false.</param>
 public HMCTSBot(Controller player,
                 bool allowPerfectInformation  = false,
                 int ensembleSize              = 1,
                 PlayoutBotType playoutBotType = PlayoutBotType.MAST,
                 MASTPlayoutBot.SelectionType mastSelectionType = MASTPlayoutBot.SelectionType.EGreedy,
                 bool retainTaskStatistics = false,
                 BudgetType budgetType     = BudgetType.Iterations,
                 int iterations            = Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET,
                 long time = Constants.DEFAULT_COMPUTATION_TIME_BUDGET,
                 int minimumVisitThresholdForExpansion = Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_EXPANSION,
                 int minimumVisitThresholdForSelection = Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_SELECTION,
                 int playoutTurnCutoff = Constants.DEFAULT_PLAYOUT_TURN_CUTOFF,
                 double ucbConstantC   = Constants.DEFAULT_UCB1_C,
                 DimensionalOrderingType dimensionalOrdering = DimensionalOrderingType.None,
                 bool useHeuristicEvaluation = false,
                 bool debugInfoToConsole     = false)
     : this(allowPerfectInformation, ensembleSize, playoutBotType, mastSelectionType, retainTaskStatistics, budgetType, iterations, time, minimumVisitThresholdForExpansion, minimumVisitThresholdForSelection, playoutTurnCutoff, ucbConstantC, dimensionalOrdering, useHeuristicEvaluation, debugInfoToConsole)
 {
     SetController(player);
 }
Esempio n. 4
0
        /// <summary>
        /// Constructs a new instance of LSIBot with default strategies.
        /// </summary>
        /// <param name="allowPerfectInformation">[Optional] Whether or not this bot is allowed perfect information about the game state (i.e. no obfuscation and therefore no determinisation). Default value is false.</param>
        /// <param name="ensembleSize">[Optional] The size of the ensemble to use. Default value is 1.</param>
        /// <param name="playoutBotType">[Optional] The type of playout bot to be used during playouts. Default value is <see cref="PlayoutBotType.MAST"/>.</param>
        /// <param name="mastSelectionType">[Optional] The type of selection strategy used by the M.A.S.T. playout. Default value is <see cref="MASTPlayoutBot.SelectionType.EGreedy"/>.</param>
        /// <param name="playoutTurnCutoff">[Optional] The amount of turns after which to stop a simulation. Default value is <see cref="Constants.DEFAULT_PLAYOUT_TURN_CUTOFF"/>.</param>
        /// <param name="budgetType">[Optional] The type of budget that this bot will use. Default value is <see cref="BudgetType.Iterations"/>.</param>
        /// <param name="samples">[Optional] The budget for the amount of iterations LSI can use. Default value is <see cref="Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET"/>.</param>
        /// <param name="time">[Optional] The budget for the amount of milliseconds LSI can spend on searching. Default value is <see cref="Constants.DEFAULT_COMPUTATION_TIME_BUDGET"/>.</param>
        /// <param name="generationBudgetPercentage">[Optional] The percentage of the budget that should be spent during the generation phase. Default value is <see cref="Constants.DEFAULT_LSI_BUDGET_GENERATION_PERCENTAGE"/>.</param>
        /// <param name="budgetEstimationType">[Optional] The type of strategy used to estimate the budget for LSI. Default value is <see cref="BudgetEstimationType.AverageSampleTime"/>.</param>
        /// <param name="useHeuristicEvaluation">[Optional] Whether or not to use the HeuristicBot's evaluation function. Default value is false.</param>
        /// <param name="debugInfoToConsole">[Optional] Whether or not to write debug information to the console. Default value is false.</param>
        public LSIBot(bool allowPerfectInformation  = false,
                      int ensembleSize              = 1,
                      PlayoutBotType playoutBotType = PlayoutBotType.MAST,
                      MASTPlayoutBot.SelectionType mastSelectionType = MASTPlayoutBot.SelectionType.EGreedy,
                      int playoutTurnCutoff                     = Constants.DEFAULT_PLAYOUT_TURN_CUTOFF,
                      BudgetType budgetType                     = BudgetType.Iterations,
                      int samples                               = Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET,
                      long time                                 = Constants.DEFAULT_COMPUTATION_TIME_BUDGET,
                      double generationBudgetPercentage         = Constants.DEFAULT_LSI_BUDGET_GENERATION_PERCENTAGE,
                      BudgetEstimationType budgetEstimationType = BudgetEstimationType.AverageSampleTime,
                      bool useHeuristicEvaluation               = false,
                      bool debugInfoToConsole                   = false)
        {
            PerfectInformation = allowPerfectInformation;
            EnsembleSize       = ensembleSize;
            PlayoutBotType     = playoutBotType;
            MASTSelectionType  = mastSelectionType;
            PlayoutTurnCutoff  = playoutTurnCutoff;
            BudgetType         = budgetType;
            Samples            = samples;
            Time = time;
            GenerationBudgetPercentage = generationBudgetPercentage;
            BudgetEstimation           = budgetEstimationType;
            _debug = debugInfoToConsole;

            // Create the ensemble search
            Ensemble = new EnsembleStrategySabberStone(enableStateObfuscation: true, enablePerfectInformation: PerfectInformation);

            // Adjust sample sizes for use in the Ensemble
            long budgetAllowance;

            switch (BudgetType)
            {
            case BudgetType.Iterations:
                Samples         = EnsembleSize > 0 ? Samples / EnsembleSize : Samples; // Note: Integer division by design.
                budgetAllowance = Samples;
                break;

            case BudgetType.Time:
                Time            = EnsembleSize > 0 ? Time / EnsembleSize : Time; // Note: Integer division by design.
                budgetAllowance = Time;
                break;

            default:
                throw new InvalidEnumArgumentException($"BudgetType `{BudgetType}' is not supported.");
            }

            // Simulation will be handled by the Playout.
            var sabberStoneStateEvaluation = new EvaluationStrategyHearthStone(useHeuristicEvaluation);

            Playout = new PlayoutStrategySabberStone();

            // Set the playout bots
            switch (PlayoutBotType)
            {
            case PlayoutBotType.Random:
                MyPlayoutBot       = new RandomBot(filterDuplicatePositionTasks: true);
                OpponentPlayoutBot = new RandomBot(filterDuplicatePositionTasks: true);
                break;

            case PlayoutBotType.Heuristic:
                MyPlayoutBot       = new HeuristicBot();
                OpponentPlayoutBot = new HeuristicBot();
                break;

            case PlayoutBotType.MAST:
                MyPlayoutBot       = new MASTPlayoutBot(MASTSelectionType, sabberStoneStateEvaluation);
                OpponentPlayoutBot = new MASTPlayoutBot(MASTSelectionType, sabberStoneStateEvaluation);
                break;

            default:
                throw new InvalidEnumArgumentException($"PlayoutBotType `{PlayoutBotType}' is not supported.");
            }

            // Set the budget estimation strategy.
            switch (BudgetEstimation)
            {
            case BudgetEstimationType.AverageSampleTime:
                BudgetEstimationStrategy = new AverageSampleTimeBudgetEstimationStrategy(BudgetType, budgetAllowance, GenerationBudgetPercentage, Playout);
                break;

            case BudgetEstimationType.PreviousSearchAverage:
                BudgetEstimationStrategy = new PreviousSearchAverageBudgetEstimationStrategy(BudgetType, budgetAllowance, GenerationBudgetPercentage, Playout);
                break;

            default:
                throw new InvalidEnumArgumentException($"BudgetEstimationType `{budgetEstimationType}' is not supported.");
            }

            // LSI will need a goal-strategy to determine when a simulation is done
            Goal = new GoalStrategyTurnCutoff(PlayoutTurnCutoff);

            // LSI will need an evaluation-strategy to evaluate the strength of samples
            Evaluation = new EvaluationStrategyHearthStone();

            // Application will be handled by the GameLogic
            // Hierarchical Expansion is set to TRUE because of incremental task validation during action sampling.
            GameLogic = new SabberStoneGameLogic(Goal, hierarchicalExpansion: true);

            // The side information strategy needs access to several of these.
            SideInformationStrategy = new SabberStoneSideInformationStrategy(Playout, Evaluation, GameLogic);

            // The sampling strategy used to sample actions during the generation phase.
            SamplingStrategy = new SabberStoneLSISamplingStrategy(GameLogic);
        }
Esempio n. 5
0
        /// <summary>
        /// Constructs a new instance of MCTSBot with default strategies.
        /// </summary>
        /// <param name="allowPerfectInformation">[Optional] Whether or not this bot is allowed perfect information about the game state (i.e. no obfuscation and therefore no determinisation). Default value is false.</param>
        /// <param name="ensembleSize">[Optional] The size of the ensemble to use. Default value is 1.</param>
        /// <param name="playoutBotType">[Optional] The type of playout bot to be used during playouts. Default value is <see cref="PlayoutBotType.MAST"/>.</param>
        /// <param name="mastSelectionType">[Optional] The type of selection strategy used by the MAST playout. Default value is <see cref="MASTPlayoutBot.SelectionType.EGreedy"/>.</param>
        /// <param name="retainTaskStatistics">[Optional] Whether or not to retain the PlayerTask statistics between searches. Default value is false.</param>
        /// <param name="budgetType">[Optional] The type of budget that this bot will use. Default value is <see cref="BudgetType.Iterations"/>.</param>
        /// <param name="iterations">[Optional] The budget for the amount of iterations MCTS can use. Default value is <see cref="Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET"/>.</param>
        /// <param name="time">[Optional] The budget for the amount of milliseconds MCTS can spend on searching. Default value is <see cref="Constants.DEFAULT_COMPUTATION_TIME_BUDGET"/>.</param>
        /// <param name="minimumVisitThresholdForExpansion">[Optional] The minimum amount of times a node has to be visited before it can be expanded. Default value is <see cref="Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_EXPANSION"/>.</param>
        /// <param name="minimumVisitThresholdForSelection">[Optional] The minimum number of visits before using the NodeEvaluation to select the best node. Default value is <see cref="Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_SELECTION"/>.</param>
        /// <param name="playoutTurnCutoff">[Optional] The amount of turns after which to stop a simulation. Default value is <see cref="Constants.DEFAULT_PLAYOUT_TURN_CUTOFF"/>.</param>
        /// <param name="ucbConstantC">[Optional] Value for the c-constant in the UCB1 formula. Default value is <see cref="Constants.DEFAULT_UCB1_C"/>.</param>
        /// <param name="dimensionalOrdering">[Optional] The ordering for dimensions when using Hierarchical Expansion. Default value is <see cref="DimensionalOrderingType.None"/>.</param>
        /// <param name="useHeuristicEvaluation">[Optional] Whether or not to use the HeuristicBot's evaluation function. Default value is false.</param>
        /// <param name="debugInfoToConsole">[Optional] Whether or not to write debug information to the console. Default value is false.</param>
        public HMCTSBot(bool allowPerfectInformation  = false,
                        int ensembleSize              = 1,
                        PlayoutBotType playoutBotType = PlayoutBotType.MAST,
                        MASTPlayoutBot.SelectionType mastSelectionType = MASTPlayoutBot.SelectionType.EGreedy,
                        bool retainTaskStatistics = false,
                        BudgetType budgetType     = BudgetType.Iterations,
                        int iterations            = Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET,
                        long time = Constants.DEFAULT_COMPUTATION_TIME_BUDGET,
                        int minimumVisitThresholdForExpansion = Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_EXPANSION,
                        int minimumVisitThresholdForSelection = Constants.DEFAULT_MCTS_MINIMUM_VISIT_THRESHOLD_FOR_SELECTION,
                        int playoutTurnCutoff = Constants.DEFAULT_PLAYOUT_TURN_CUTOFF,
                        double ucbConstantC   = Constants.DEFAULT_UCB1_C,
                        DimensionalOrderingType dimensionalOrdering = DimensionalOrderingType.None,
                        bool useHeuristicEvaluation = false,
                        bool debugInfoToConsole     = false)
        {
            PerfectInformation   = allowPerfectInformation;
            EnsembleSize         = ensembleSize;
            PlayoutBotType       = playoutBotType;
            MASTSelectionType    = mastSelectionType;
            RetainTaskStatistics = retainTaskStatistics;
            BudgetType           = budgetType;
            Iterations           = iterations;
            Time = time;
            MinimumVisitThresholdForExpansion = minimumVisitThresholdForExpansion;
            MinimumVisitThresholdForSelection = minimumVisitThresholdForSelection;
            PlayoutTurnCutoff   = playoutTurnCutoff;
            UCBConstantC        = ucbConstantC;
            DimensionalOrdering = dimensionalOrdering;
            _debug = debugInfoToConsole;

            // Create the ensemble search
            Ensemble = new EnsembleStrategySabberStone(enableStateObfuscation: true, enablePerfectInformation: PerfectInformation);

            // Simulation will be handled by the Playout.
            var sabberStoneStateEvaluation = new EvaluationStrategyHearthStone(useHeuristicEvaluation);

            Playout = new PlayoutStrategySabberStone();

            // Set the playout bots
            switch (PlayoutBotType)
            {
            case PlayoutBotType.Random:
                MyPlayoutBot       = new RandomBot(filterDuplicatePositionTasks: true);
                OpponentPlayoutBot = new RandomBot(filterDuplicatePositionTasks: true);
                break;

            case PlayoutBotType.Heuristic:
                MyPlayoutBot       = new HeuristicBot();
                OpponentPlayoutBot = new HeuristicBot();
                break;

            case PlayoutBotType.MAST:
                MyPlayoutBot       = new MASTPlayoutBot(MASTSelectionType, sabberStoneStateEvaluation);
                OpponentPlayoutBot = new MASTPlayoutBot(MASTSelectionType, sabberStoneStateEvaluation);
                break;

            default:
                throw new InvalidEnumArgumentException($"PlayoutBotType `{PlayoutBotType}' is not supported.");
            }

            // We'll be cutting off the simulations after X turns, using a GoalStrategy.
            Goal = new GoalStrategyTurnCutoff(PlayoutTurnCutoff);

            // Expansion, Application and Goal will be handled by the GameLogic.
            GameLogic = new SabberStoneGameLogic(Goal, true, DimensionalOrdering);

            // Create the INodeEvaluation strategy used in the selection phase.
            var nodeEvaluation = new ScoreUCB <SabberStoneState, SabberStoneAction>(UCBConstantC);

            // Build MCTS
            Builder = MCTS <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction> .Builder();

            Builder.ExpansionStrategy  = new MinimumTExpansion <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>(MinimumVisitThresholdForExpansion);
            Builder.SelectionStrategy  = new BestNodeSelection <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>(MinimumVisitThresholdForSelection, nodeEvaluation);
            Builder.EvaluationStrategy = sabberStoneStateEvaluation;
            switch (BudgetType)
            {
            case BudgetType.Iterations:
                Builder.Iterations = EnsembleSize > 0 ? Iterations / EnsembleSize : Iterations;     // Note: Integer division by design.
                break;

            case BudgetType.Time:
                Builder.Time = EnsembleSize > 0 ? Time / EnsembleSize : Time;     // Note: Integer division by design.
                break;

            default:
                throw new InvalidEnumArgumentException($"BudgetType `{BudgetType}' is not supported.");
            }
            Builder.BackPropagationStrategy    = new EvaluateOnceAndColourBackPropagation <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>();
            Builder.FinalNodeSelectionStrategy = new BestRatioFinalNodeSelection <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>();
            Builder.SolutionStrategy           = new SolutionStrategySabberStone(true, nodeEvaluation);
            Builder.PlayoutStrategy            = Playout;
        }
        /// <summary>
        /// Constructs a new instance of NMCTSBot with default strategies.
        /// </summary>
        /// <param name="allowPerfectInformation">[Optional] Whether or not this bot is allowed perfect information about the game state (i.e. no obfuscation and therefore no determinisation). Default value is false.</param>
        /// <param name="ensembleSize">[Optional] The size of the ensemble to use. Default value is 1.</param>
        /// <param name="playoutBotType">[Optional] The type of playout bot to be used during playouts. Default value is <see cref="PlayoutBotType.MAST"/>.</param>
        /// <param name="mastSelectionType">[Optional] The type of selection strategy used by the MAST playout. Default value is <see cref="MASTPlayoutBot.SelectionType.EGreedy"/>.</param>
        /// <param name="budgetType">[Optional] The type of budget that this bot will use. Default value is <see cref="BudgetType.Iterations"/>.</param>
        /// <param name="iterations">[Optional] The budget for the amount of iterations NMCTS can use. Default value is <see cref="Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET"/>.</param>
        /// <param name="time">[Optional] The budget for the amount of milliseconds NMCTS can spend on searching. Default value is <see cref="Constants.DEFAULT_COMPUTATION_TIME_BUDGET"/>.</param>
        /// <param name="playoutTurnCutoff">[Optional] The amount of turns after which to stop a simulation. Default value is <see cref="Constants.DEFAULT_PLAYOUT_TURN_CUTOFF"/>.</param>
        /// <param name="globalPolicy">[Optional] The exploration-threshold for the e-greedy global policy. Default value is <see cref="Constants.DEFAULT_NMCTS_GLOBAL_POLICY"/>.</param>
        /// <param name="localPolicy">[Optional] The exploration-threshold for the e-greedy local policy. Default value is <see cref="Constants.DEFAULT_NMCTS_LOCAL_POLICY"/>.</param>
        /// <param name="useHeuristicEvaluation">[Optional] Whether or not to use the HeuristicBot's evaluation function. Default value is false.</param>
        /// <param name="debugInfoToConsole">[Optional] Whether or not to write debug information to the console. Default value is false.</param>
        public NMCTSBot(bool allowPerfectInformation  = false,
                        int ensembleSize              = 1,
                        PlayoutBotType playoutBotType = PlayoutBotType.MAST,
                        MASTPlayoutBot.SelectionType mastSelectionType = MASTPlayoutBot.SelectionType.EGreedy,
                        BudgetType budgetType       = BudgetType.Iterations,
                        int iterations              = Constants.DEFAULT_COMPUTATION_ITERATION_BUDGET,
                        long time                   = Constants.DEFAULT_COMPUTATION_TIME_BUDGET,
                        int playoutTurnCutoff       = Constants.DEFAULT_PLAYOUT_TURN_CUTOFF,
                        double globalPolicy         = Constants.DEFAULT_NMCTS_GLOBAL_POLICY,
                        double localPolicy          = Constants.DEFAULT_NMCTS_LOCAL_POLICY,
                        bool useHeuristicEvaluation = false,
                        bool debugInfoToConsole     = false)
        {
            PerfectInformation = allowPerfectInformation;
            EnsembleSize       = ensembleSize;
            PlayoutBotType     = playoutBotType;
            MASTSelectionType  = mastSelectionType;
            BudgetType         = budgetType;
            Iterations         = iterations;
            Time = time;
            PlayoutTurnCutoff = playoutTurnCutoff;
            GlobalPolicy      = globalPolicy;
            LocalPolicy       = localPolicy;
            _debug            = debugInfoToConsole;

            // Create the ensemble search
            Ensemble = new EnsembleStrategySabberStone(enableStateObfuscation: true, enablePerfectInformation: PerfectInformation);

            // Simulation will be handled by the Playout
            var sabberStoneStateEvaluation = new EvaluationStrategyHearthStone(useHeuristicEvaluation);

            Playout = new PlayoutStrategySabberStone();

            // Set the playout bots
            switch (PlayoutBotType)
            {
            case PlayoutBotType.Random:
                MyPlayoutBot       = new RandomBot(filterDuplicatePositionTasks: true);
                OpponentPlayoutBot = new RandomBot(filterDuplicatePositionTasks: true);
                break;

            case PlayoutBotType.Heuristic:
                MyPlayoutBot       = new HeuristicBot();
                OpponentPlayoutBot = new HeuristicBot();
                break;

            case PlayoutBotType.MAST:
                MyPlayoutBot       = new MASTPlayoutBot(MASTSelectionType, sabberStoneStateEvaluation);
                OpponentPlayoutBot = new MASTPlayoutBot(MASTSelectionType, sabberStoneStateEvaluation);
                break;

            default:
                throw new InvalidEnumArgumentException($"PlayoutBotType `{PlayoutBotType}' is not supported.");
            }

            // And the random sampling bot
            RandomSamplingBot = new RandomBot(filterDuplicatePositionTasks: true);

            // We'll be cutting off the simulations after X turns, using a GoalStrategy
            Goal = new GoalStrategyTurnCutoff(PlayoutTurnCutoff);

            // Application and Goal will be handled by the GameLogic
            GameLogic = new SabberStoneGameLogic(Goal, false);

            // Build NMCTS
            Builder = NMCTS <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction> .Builder();

            Builder.ExplorationStrategy = new ChanceExploration <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>(LocalPolicy);
            Builder.PlayoutStrategy     = Playout;
            Builder.PolicyGlobal        = GlobalPolicy;
            Builder.SamplingStrategy    = new SabberStoneNMCSamplingStrategy(RandomSamplingBot);
            Builder.SolutionStrategy    = new SolutionStrategySabberStone(false, new AverageScore <SabberStoneState, SabberStoneAction>());
            Builder.EvaluationStrategy  = sabberStoneStateEvaluation;
            switch (BudgetType)
            {
            case BudgetType.Iterations:
                Builder.Iterations = EnsembleSize > 0 ? Iterations / EnsembleSize : Iterations;     // Note: Integer division by design.
                break;

            case BudgetType.Time:
                Builder.Time = EnsembleSize > 0 ? Time / EnsembleSize : Time;     // Note: Integer division by design.
                break;

            default:
                throw new InvalidEnumArgumentException($"BudgetType `{BudgetType}' is not supported.");
            }
        }