/* * Calculates the expected value over all possible states that could result from * taking the given action in the given state. */ private double ExpectedValue(GameState state, Action action, IDepthLimit searchLimit) { state.ApplyAction(action); double placementProbability = 1.0 / state.EmptyCells; double probability2 = placementProbability * Constants.TILE_PROBABILITY_2; double probability4 = placementProbability * Constants.TILE_PROBABILITY_4; double expectedValue = 0; // Tries all possible placements of '2' and '4' tiles, calculating the // value of each outcome and aggregating values into the expected value. foreach (var cell in state.GetEmptyCells()) { var tile2 = new Tile(cell, 2); state.AddTile(tile2); expectedValue += MaxValue(state, searchLimit) * probability2; state.RemoveTile(cell); var tile4 = new Tile(cell, 4); state.AddTile(tile4); expectedValue += MaxValue(state, searchLimit) * probability4; state.RemoveTile(cell); } return(expectedValue); }
/* * Returns the maximum value over all states reachable from the given state. */ private double MaxValue(GameState state, IDepthLimit searchLimit) { if (state.IsWin) { return(100.0); } else if (state.IsLoss) { return(0); } else if (searchLimit.Done()) { return(Evaluate(state)); } double maxValue = NO_VALUE; foreach (var action in ShuffledLegalActions(state)) { searchLimit.IncreaseDepth(); double expectedValue = ExpectedValue(new GameState(state), action, searchLimit); searchLimit.DecreaseDepth(); if (expectedValue > maxValue) { maxValue = expectedValue; } } return(maxValue); }
/// <summary> /// Returns the list of legal actions in a game state with their corresponding /// expected values. /// </summary> /// <param name="state">the game state</param> /// <param name="searchLimit">a depth limit for the search algorithm</param> public IEnumerable <ActionValue> GetPolicies(GameState state, IDepthLimit searchLimit) { foreach (var action in ShuffledLegalActions(state)) { searchLimit.IncreaseDepth(); double value = ExpectedValue(new GameState(state), action, searchLimit); searchLimit.DecreaseDepth(); yield return(new ActionValue() { Action = action, Value = value }); } }
/// <summary> /// Returns the best action to take in a game state using the given depth limit. /// If no actions are legal, NoAction is returned. /// </summary> /// <param name="state">the game state</param> /// <param name="searchLimit">the depth limit</param> public Action GetPolicy(GameState state, IDepthLimit searchLimit) { return(GetPolicies(state, searchLimit).Best()); }