Example #1
0
            /// <inheritdoc />
            public OddmentTable <SabberStonePlayerTask> Create(SearchContext <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction> context, int samplesForGeneration)
            {
                // So we have an issue here, because it's Hearthstone we don't know in advance how many dimensions we have.
                //      -> We can just evenly distribute budget over the currently available dimensions
                //      -- Reason is that some dimensions would be `locked' until after a specific dimensions is explored
                //      -> Another option is to expand all possible sequences, this might be too complex though...

                // In Hearthstone we don't really have multiple available actions per dimension
                // It's more like you either play/attack or not
                // Although each minion can have multiple choices on what to attack

                // We can still try to distillate individual actions
                // It might be best to keep track of these through a dictionary/array
                //      So we'd randomly choose actions and simulate when `end-turn' is chosen
                //      And then update the value of any selected PlayerTask

                // I guess use OddmentTable again?

                var table = new Dictionary <SabberStonePlayerTask, double>(PlayerTaskComparer.Comparer);

                // So, we have a number of samples to use
                // For each of those, generate a random SabberStoneAction and playout
                for (var i = 0; i < samplesForGeneration; i++)
                {
                    var action = PlayoutBot.CreateRandomAction(context.Source);

                    var newState = GameLogic.Apply(context, (SabberStoneState)context.Source.Copy(), action);

                    var endState = Playout.Playout(context, newState);

                    var value = Evaluation.Evaluate(context, null, endState);

                    foreach (var task in action.Tasks)
                    {
                        if (!table.ContainsKey(task))
                        {
                            table.Add(task, 0);
                        }
                        table[task] += value;
                    }
                }

                // Create the Oddment table
                var oddmentTable = new OddmentTable <SabberStonePlayerTask>();

                foreach (var kvPair in table)
                {
                    oddmentTable.Add(kvPair.Key, kvPair.Value, recalculate: false);
                }

                oddmentTable.Recalculate();

                return(oddmentTable);
            }
Example #2
0
        /// <summary>
        /// Selects the best half of a collection of actions by evaluating them based on the provided search context.
        /// </summary>
        /// <param name="context">The current search context.</param>
        /// <param name="actions">The collection of actions to filter.</param>
        /// <param name="samplesPerAction">How many samples to run per action.</param>
        /// <returns>Collection of actions which Count is half of the original collection, rounded up. This collection is ordered by descending value.</returns>
        private List <ActionValue> SelectBestHalf(SearchContext <D, P, A, S, A> context, IReadOnlyCollection <ActionValue> actions, int samplesPerAction)
        {
            var clone = context.Cloner;

            // Evaluate each action by running a playout for it.
            foreach (var item in actions)
            {
                var tempNode = new N {
                    Payload = item.Action
                };
                var newState = GameLogic.Apply(context, clone.Clone(context.Source), item.Action);

                double value = 0;
                for (var i = 0; i < samplesPerAction; i++)
                {
                    try {
                        var endState = Playout.Playout(context, clone.Clone(newState));
                        value += Evaluation.Evaluate(context, tempNode, endState);
                        SamplesUsedEvaluation++;
                    }
                    catch (Exception e) {
                        //Console.WriteLine($"ERROR: {e.GetType()} while cloning state.");
                        // TODO fix
                        // Cloning here seems to very seldom cause a NullReference in the SabberStone dll
                        // I believe failing and just using 0 as a value here is acceptable
                    }
                }

                item.Value = value;
            }

            // Return the half with the highest value.
            var half = (int)Math.Max(1, Math.Ceiling(actions.Count / 2.0));

            return(actions.OrderByDescending(i => i.Value).Take(half).ToList());
        }