/// <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); }
/// <inheritdoc /> 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 NMCTS search in turn {(gameState.Game.Turn + 1) / 2}"); } // Setup and start the ensemble-search EnsembleSolutions = new List <SabberStoneAction>(); var search = (NMCTS <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>)Builder.Build(); var context = SearchContext <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction> .GameSearchSetup(GameLogic, EnsembleSolutions, gameState, null, search); Ensemble.EnsembleSearch(context, Searcher.Search, EnsembleSize); IterationsSpent = EnsembleSolutions.Sum(i => i.BudgetUsed); // Determine the best tasks to play based on the ensemble search, or just take the one in case of a single search. var solution = EnsembleSize > 1 ? Searcher.VoteForSolution(EnsembleSolutions, state) : EnsembleSolutions.First(); if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine($"NMCTS returned with solution: {solution}"); } if (_debug) { Console.WriteLine($"My total calculation time was: {timer.ElapsedMilliseconds} 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); }
/// <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); }
/// <inheritdoc /> public SabberStoneAction Act(SabberStoneState state) { var timer = Stopwatch.StartNew(); var stateCopy = (SabberStoneState)state.Copy(); if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine(Name()); } if (_debug) { Console.WriteLine($"Starting an LSI search in turn {(stateCopy.Game.Turn + 1) / 2}"); } // Create a new LSI search var search = new LSI <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, TreeSearchNode <SabberStoneState, SabberStoneAction>, OddmentTable <SabberStonePlayerTask> >( SideInformationStrategy, SamplingStrategy, Playout, Evaluation, GameLogic, BudgetEstimationStrategy ); // Reset the solutions collection EnsembleSolutions = new List <SabberStoneAction>(); // Create a SearchContext that just holds the current state as Source and the Search. var context = SearchContext <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction> .Context(EnsembleSolutions, stateCopy, null, null, search, null); // The Playout strategy will call the Goal strategy from the context, so we set it here context.Goal = Goal; // Execute the search Ensemble.EnsembleSearch(context, Searcher.Search, EnsembleSize); SamplesSpent = EnsembleSolutions.Sum(i => i.BudgetUsed); // Determine a solution var solution = Searcher.VoteForSolution(EnsembleSolutions, state); timer.Stop(); if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine($"LSI returned with solution: {solution}"); } if (_debug) { Console.WriteLine($"My total calculation time was: {timer.ElapsedMilliseconds}ms"); } // Check if the solution is a complete action. if (!solution.IsComplete()) { // Otherwise add an End-Turn task before returning. solution.Tasks.Add((SabberStonePlayerTask)EndTurnTask.Any(Player)); } // If we are estimating the budget by using the previous search's results, save these now if (BudgetEstimation == BudgetEstimationType.PreviousSearchAverage && BudgetEstimationStrategy is PreviousSearchAverageBudgetEstimationStrategy estimationStrategy) { estimationStrategy.PreviousSearchTime = timer.ElapsedMilliseconds; estimationStrategy.PreviousSearchIterations = SamplesSpent; } if (_debug) { Console.WriteLine(); } return(solution); }
/// <inheritdoc /> /// <summary> /// Requests the bot to return a SabberStoneAction based on the current SabberStoneState. /// </summary> /// <param name="state">The current game state.</param> /// <returns>SabberStoneAction that was voted as the best option by the ensemble.</returns> 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 MCTS search in turn {(gameState.Game.Turn + 1) / 2}"); } // Check if the task statistics in the searcher should be reset if (!RetainTaskStatistics) { Searcher.ResetTaskStatistics(); } // Setup and start the ensemble-search EnsembleSolutions = new List <SabberStoneAction>(); var search = (MCTS <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>)Builder.Build(); var context = SearchContext <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction> .GameSearchSetup(GameLogic, EnsembleSolutions, gameState, null, search); Ensemble.EnsembleSearch(context, Searcher.Search, EnsembleSize); IterationsSpent = EnsembleSolutions.Sum(i => i.BudgetUsed); // Determine the best tasks to play based on the ensemble search, or just take the one in case of a single search. var solution = EnsembleSize > 1 ? Searcher.VoteForSolution(EnsembleSolutions, state) : EnsembleSolutions.First(); var time = timer.ElapsedMilliseconds; if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine($"MCTS returned with solution: {solution}"); } if (_debug) { Console.WriteLine($"My total calculation time was: {time} ms."); } if (_debug) { Console.WriteLine(); } // Check if MoveCompletion should be used. if (!solution.IsComplete()) { CompleteHEMove(state, solution); } return(solution); }