/// <summary>
        /// Creates a SabberStoneAction by randomly selecting one of the available PlayerTasks until the End_Turn task is selected.
        /// </summary>
        /// <param name="state">The game state for which an action should be created. Note: </param>
        /// <returns>SabberStoneAction</returns>
        public SabberStoneAction CreateRandomAction(SabberStoneState state)
        {
            // Clone game so that we can process the selected tasks and get an updated options list.
            var clonedGame = state.Game.Clone();
            var playerID   = clonedGame.CurrentPlayer.Id;

            // Create an action to store the selected tasks.
            var action = new SabberStoneAction();

            // Keep adding random tasks until the player's turn is over, or the game has ended
            while (clonedGame.CurrentPlayer.Id == playerID && clonedGame.State != State.COMPLETE)
            {
                // Check if an duplicate positions need to be filtered out
                var availableOptions = clonedGame.CurrentPlayer.Options();
                if (FilterDuplicatePositionTasks)
                {
                    availableOptions = availableOptions.Where(i => i.ZonePosition <= 0).ToList();
                }
                // Select a random available task
                var selectedTask = availableOptions.RandomElementOrDefault();
                // Add the task to the action.
                action.AddTask((SabberStonePlayerTask)selectedTask);
                // Process the task on the cloned game state.
                clonedGame.Process(selectedTask);
            }

            // Check if the action is complete, if not, add EndTurn
            if (!action.IsComplete())
            {
                action.AddTask((SabberStonePlayerTask)EndTurnTask.Any(clonedGame.CurrentPlayer));
            }

            return(action);
        }
Beispiel #2
0
        /// <summary>
        /// Completes an incomplete move caused by Hierarchical Expansion.
        /// </summary>
        /// <param name="state">The game state to create an action for.</param>
        /// <param name="action">The currently created action.</param>
        private void CompleteHEMove(SabberStoneState state, SabberStoneAction action)
        {
            // Copy state so that we can process the tasks and get an updated options list.
            var copyState = (SabberStoneState)state.Copy();

            // Process the currently selected tasks
            foreach (var task in action.Tasks)
            {
                try {
                    copyState.Game.Process(task.Task);
                }
                catch (Exception e) {
                    Console.WriteLine($"ERROR: {e.GetType()} thrown while trying to process a task.");
                    break;
                }
            }
            // Ask the Searcher to determine the best tasks to complete the action
            var completingAction = Searcher.DetermineBestTasks(copyState);

            // Add the tasks to the provided action
            foreach (var task in completingAction.Tasks)
            {
                action.AddTask(task);
            }

            // If the move is not complete yet (for example, when the game is over), add EndTurn
            if (!action.IsComplete())
            {
                action.AddTask((SabberStonePlayerTask)EndTurnTask.Any(Player));
            }
        }
        public SabberStoneAction Act(SabberStoneState state)
        {
            var timer     = System.Diagnostics.Stopwatch.StartNew();
            var gameState = (SabberStoneState)state.Copy();

            if (_debug)
            {
                Console.WriteLine();
            }
            if (_debug)
            {
                Console.WriteLine(Name());
            }
            if (_debug)
            {
                Console.WriteLine($"Starting a Heuristic search in turn {(gameState.Game.Turn + 1) / 2}");
            }

            var solution = new SabberStoneAction();

            while (gameState.CurrentPlayer() == PlayerID() && gameState.Game.State != State.COMPLETE)
            {
                var poGame = new POGame(gameState.Game, _debug);
                var task   = GetMove(poGame);
                solution.AddTask((SabberStonePlayerTask)task);
                gameState.Game.Process(task);
            }

            var time = timer.ElapsedMilliseconds;

            if (_debug)
            {
                Console.WriteLine();
            }
            if (_debug)
            {
                Console.WriteLine($"Heuristic returned with solution: {solution}");
            }
            if (_debug)
            {
                Console.WriteLine($"My total calculation time was: {time} ms.");
            }

            // Check if the solution is a complete action.
            if (!solution.IsComplete())
            {
                // Otherwise add an End-Turn task before returning.
                if (_debug)
                {
                    Console.WriteLine("Solution was an incomplete action; adding End-Turn task.");
                }
                solution.Tasks.Add((SabberStonePlayerTask)EndTurnTask.Any(Player));
            }

            if (_debug)
            {
                Console.WriteLine();
            }
            return(solution);
        }
        /// <summary>
        /// Selects an action using the e-greedy algorithm.
        /// </summary>
        /// <param name="state">The game state.</param>
        /// <returns><see cref="SabberStoneAction"/>.</returns>
        private SabberStoneAction SelectEGreedy(SabberStoneState state)
        {
            // Determine whether or not to be greedy (chance is 1-e to use best action)
            if (Util.RNG.NextDouble() < EGreedyThreshold)
            {
                // Explore a random action
                return(RandomPlayoutBot.CreateRandomAction(state));
            }

            var action     = new SabberStoneAction();
            var stateClone = state.Game.Clone();

            // Repeatedly exploit the highest (average) reward task that is available in this state
            do
            {
                SabberStonePlayerTask selectedTask;
                // Get the stats of the tasks currently available in this state
                var availableTasks      = stateClone.Game.CurrentPlayer.Options().Where(i => i.ZonePosition <= 0).Select(i => (SabberStonePlayerTask)i).ToList();
                var availableTaskHashes = availableTasks.Select(i => i.GetHashCode()).ToList();
                var availableStatistics = MASTTable.Where(i => availableTaskHashes.Contains(i.Key)).ToList();

                // Find the task with the highest average value
                var bestTask = availableStatistics.OrderByDescending(i => i.Value.AverageValue()).FirstOrDefault();

                // If no best task was found, randomly choose an available task
                if (bestTask.IsDefault())
                {
                    var randomTask = availableTasks.RandomElementOrDefault();
                    // If we also can't randomly find a task, stop
                    if (randomTask == null)
                    {
                        break;
                    }
                    selectedTask = randomTask;
                }
                else
                {
                    // Find all available tasks that have an average value similar to the best
                    var bestValue = bestTask.Value.AverageValue();
                    var compTasks = availableStatistics.Where(i =>
                                                              Math.Abs(i.Value.AverageValue() - bestValue) < AVThesis.Constants.DOUBLE_EQUALITY_TOLERANCE).ToList();
                    // Select one of the tasks
                    selectedTask = compTasks.RandomElementOrDefault().Value.Task;
                }

                // Add the task to the action we are building
                action.AddTask(selectedTask);
                // Process the task
                stateClone.Process(selectedTask.Task);

                // Continue until we have created a complete action, or the game has completed
            } while (!action.IsComplete() && stateClone.Game.State != State.COMPLETE);

            // Return the action we've created
            return(action);
        }
        /// <summary>
        /// Returns a SabberStoneAction for the current state.
        /// Note: If this player has no available options, null is returned.
        /// </summary>
        /// <param name="state">The current game state.</param>
        /// <returns>SabberStoneAction or null in the case of no available options.</returns>
        public SabberStoneAction Act(SabberStoneState state)
        {
            // Check to make sure the player to act in the game-state matches our player.
            if (state.CurrentPlayer() != Player.Id)
            {
                return(null);
            }

            // Check if there are any options, otherwise return a randomly created action.
            return(Player.Options().IsNullOrEmpty() ? SabberStoneAction.CreateNullMove(Player) : CreateRandomAction(state));
        }
        /// <summary>
        /// Selects and action using the UCB1 algorithm.
        /// </summary>
        /// <param name="state">The game state.</param>
        /// <returns><see cref="SabberStoneAction"/>.</returns>
        private SabberStoneAction SelectUCB(SabberStoneState state)
        {
            var action     = new SabberStoneAction();
            var stateClone = state.Game.Clone();

            // Repeatedly exploit the highest UCB-value task that is available in this state
            do
            {
                SabberStonePlayerTask selectedTask;
                // Get the stats of the tasks currently available in this state
                var availableTasks      = stateClone.Game.CurrentPlayer.Options().Where(i => i.ZonePosition <= 0).Select(i => (SabberStonePlayerTask)i).ToList();
                var availableTaskHashes = availableTasks.Select(i => i.GetHashCode()).ToList();
                var availableStatistics = MASTTable.Where(i => availableTaskHashes.Contains(i.Key)).ToList();
                var totalVisits         = availableStatistics.Sum(i => i.Value.Visits);

                // Find the task with the highest UCB value
                var bestTask = availableStatistics.OrderByDescending(i => i.Value.UCB(totalVisits, UCBConstantC)).FirstOrDefault();

                // If no best task was found, randomly choose an available task
                if (bestTask.IsDefault())
                {
                    var randomTask = availableTasks.RandomElementOrDefault();
                    // If we also can't randomly find a task, stop
                    if (randomTask == null)
                    {
                        break;
                    }
                    selectedTask = randomTask;
                }
                else
                {
                    // Find all available tasks that have an UCB value similar to the best
                    var bestValue = bestTask.Value.UCB(totalVisits, UCBConstantC);
                    var compTasks = availableStatistics.Where(i =>
                                                              Math.Abs(i.Value.UCB(totalVisits, UCBConstantC) - bestValue) < AVThesis.Constants.DOUBLE_EQUALITY_TOLERANCE).ToList();
                    // Select one of the tasks
                    selectedTask = compTasks.RandomElementOrDefault().Value.Task;
                }

                // Add the task to the action we are building
                action.AddTask(selectedTask);
                // Process the task
                stateClone.Process(selectedTask.Task);

                // Continue until we have created a complete action, or the game has completed
            } while (!action.IsComplete() && stateClone.Game.State != State.COMPLETE);

            // Return the action we've created
            return(action);
        }
 /// <summary>
 /// Add data for an action to this bot's MAST-table.
 /// </summary>
 /// <param name="action">The action to add the data for.</param>
 /// <param name="value">The value to add to the action.</param>
 private void AddData(SabberStoneAction action, double value)
 {
     // Adjust the values for all tasks in the action
     foreach (var task in action.Tasks)
     {
         var hashKey = task.GetHashCode();
         if (!MASTTable.ContainsKey(hashKey))
         {
             MASTTable.Add(hashKey, new PlayerTaskStatistics(task, value));
         }
         else
         {
             MASTTable[hashKey].AddValue(value);
         }
     }
 }
Beispiel #8
0
            /// <inheritdoc />
            public SabberStoneAction Sample(SabberStoneState state, OddmentTable <SabberStonePlayerTask> sideInformation)
            {
                var copyState      = (SabberStoneState)state.Copy();
                var availableTasks = GetAvailablePlayerTasks(copyState);
                var action         = new SabberStoneAction();
                var tries          = 0;

                // Keep sampling tasks while we have not passed the turn yet and there are more tasks available than only EndTurn or HeroPower, of if we haven't generated a suitable task in 100 tries
                while (!action.IsComplete() && availableTasks.Any(i => i.Task.PlayerTaskType != PlayerTaskType.END_TURN && i.Task.PlayerTaskType != PlayerTaskType.HERO_POWER) && tries < 100)
                {
                    // Sample a task from the OddmentTable
                    var task = sideInformation.Next();
                    // Check if the task is available in the current state
                    if (!availableTasks.Contains(task, PlayerTaskComparer.Comparer))
                    {
                        tries++;
                        continue;
                    }

                    tries = 0;
                    action.AddTask(task);
                    copyState.Game.Process(task.Task);
                    availableTasks = GetAvailablePlayerTasks(copyState);
                }

                if (action.IsComplete())
                {
                    return(action);
                }

                // If hero power is available, add it
                if (availableTasks.Any(i => i.Task.PlayerTaskType == PlayerTaskType.HERO_POWER))
                {
                    action.AddTask(availableTasks.First(i => i.Task.PlayerTaskType == PlayerTaskType.HERO_POWER));
                }

                // If the action is not complete yet, add EndTurn
                action.AddTask((SabberStonePlayerTask)EndTurnTask.Any(state.Game.CurrentPlayer));

                return(action);
            }
Beispiel #9
0
 /// <inheritdoc />
 public SabberStoneAction Sample(SabberStoneState state)
 {
     return(SabberStoneAction.CreateNullMove(state.CurrentPlayer() == state.Player1.Id ? state.Player1 : state.Player2));
 }