public OddmentTable <int> Create(SearchContext <object, TicTacToeState, TicTacToeMove, object, TicTacToeMove> context, int samplesForGeneration) { var table = new Dictionary <int, double>(); for (var i = 0; i < samplesForGeneration; i++) { var action = new TicTacToeMove(TicTacToeMoveGenerator.AllEmptyPositions(context.Source).RandomElementOrDefault(), context.Source.ActivePlayerID); var newState = GameLogic.Apply(context, (TicTacToeState)context.Source.Copy(), action); var endState = PlayoutStrategy.Playout(context, newState); var value = EvaluationStrategy.Evaluate(context, new TreeSearchNode <TicTacToeState, TicTacToeMove>(action), endState); if (!table.ContainsKey(action.PositionToPlace)) { table.Add(action.PositionToPlace, 0); } table[action.PositionToPlace] += value; } var maxValue = table.Values.Max(); var minValue = table.Values.Min(); var oddmentTable = new OddmentTable <int>(); foreach (var kvPair in table) { var normalisedValue = Util.Normalise(kvPair.Value, minValue, maxValue); oddmentTable.Add(kvPair.Key, normalisedValue, recalculate: false); } oddmentTable.Recalculate(); return(oddmentTable); }
/// <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); }
public TicTacToeMove Sample(TicTacToeState state, OddmentTable <int> sideInformation) { // Get all available positions in this state var emptyPositions = TicTacToeMoveGenerator.AllEmptyPositions(state); var positionSelected = false; var selectedPosition = -1; while (!positionSelected) { // Sample a position from the OddmentTable selectedPosition = sideInformation.Next(); // Check if this position can be played, otherwise generate a new one positionSelected = emptyPositions.Contains(selectedPosition); } return(new TicTacToeMove(selectedPosition, state.ActivePlayerID)); }
/// <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); }