Simulated Games: obtaining results
Remember that in order to obtain meaningful results, certain number of iteration must be run first. See Step 9 from defining a game in 10 steps.
Using the algorithm via Reasoner only
Please visit this page SimulatedGameReasoner.
Using the SimulatedGame interface
There are six methods of SimulatedGame you can use to read the results
-
C++
-
C#
std::unordered_map<const ISimulatedGameUnit*, std::vector<const ISimulatedGameAction*>> GetExpectedPlans() (1)
std::unordered_map<const ISimulatedGameUnit*, std::vector<SimulatedGameActionMetadata>> GetExpectedPlansWithMetadata() (2)
std::vector<SimulatedGameActionMetadata> GetStartingUnitActionsWithMetadata() const (3)
std::vector<std::pair<const ISimulatedGameUnit*, const ISimulatedGameAction*>> GetExpectedPlayout() const (4)
const ISimulatedGameAction* GetStartingUnitBestAction() const (5)
const SimulatedGameActionMetadata GetStartingUnitBestActionMetadata() const (6)
public Dictionary<ISimulatedGameUnit, List<ISimulatedGameAction>> GetExpectedPlans() (1)
public Dictionary<ISimulatedGameUnit, List<SimulatedGameActionMetadata>> GetExpectedPlansWithMetadata() (2)
public Dictionary<ISimulatedGameAction, SimulatedGameActionMetadata> GetStartingUnitActionsMetadata() (3)
public List<Tuple<ISimulatedGameUnit, ISimulatedGameAction>> GetExpectedPlayout() (4)
public ISimulatedGameAction GetStartingUnitBestAction() (5)
public SimulatedGameActionMetadata GetStartingUnitBestActionMetadata() (6)
1 | This method performs a single simulation of the game using only actions for which statistics are stored.
Each unit chooses the best action according with respect to the average expected score for the team the unit is assigned to. In other words - this is a simulation of the most probable gameplay from the current state. The keys in the dictionary are all units that have made actions. The values are list of action of a particular unit in chronological order (order of execution). |
2 | This method is the same as (1), but some additional statistics are returned. Please take a look at SimulatedGameActionMetadata below. |
3 | This method returns statistics of actions (represented as SimulatedGameActionMetadata) for the StartingUnit (that acts as first). |
4 | This method performs a single simulation of the game likewise the first method. Like in (1), the simulation stops when there are no more statistics for actions. This method differs from (1) in terms of the returning value. Here, actions are stored in order as pairs (unit that performed the action, action) - not grouped by units like in the (1) case. |
5 | This is the simplest method. It returns just the best evaluated action (in terms of the expected score) for the starting unit in the game. |
6 | This is like (5) that returns the best evaluated action for the starting unit, but with additional statistics. |
If you need only the next action for a unit (and it’s not a starting unit, for which we have a simpler method), then you can call method (1) and take only the first element from the obtained list. |
-
C++
-
C#
game.GetExpectedPlans()[myUnit].front()
game.GetExpectedPlans()[myUnit].First()
SimulatedGameActionMetadata
represents an action with additional parameters that describe its quality evaluated by the MCTS algorithm.
It contains:
-
Action
- reference to the action the metadata was compted for -
Score
- the expected of the action, which is based on the scores you provide in terminal states. -
Visits
- the number of times the action was sampled. Score = TotalScore/Visits.
For more information, consult Step 7 from defining a game in 10 steps. This is the average score that is calculated mostly on the most probable playouts.
Translating the results
After running SimulatedGame you receive actions as results. Let us recall:
-
Actions (ISimulatedAction) - performed in SimulatedGame
-
Behaviors (Behavior) - performed in the actual game
You have to provide the logic that translates actions into behaviors. We do not assume that an action is mapped one-to-one to a behavior, although this is a typical case. If you are using the game object directly, you manually choose how to use the obtained actions as results.
If you are using SimulatedGameReasoner
provide an implementation of the ISimulatedActionTranslator
interface.
API Reference
-
C++
-
C#
class ISimulatedActionTranslator
{
public:
/// <summary>
/// Translate actions from SimulatedGames (@actions) into any number of corresponing behaviors and add push them to the @plan object.
/// </summary>
/// <param name="entity">The entity that performs the behaviors.</param>`
/// <param name="simulatedGameUnit">The unit from SimulatedGame that performed the actions.</param>
/// <param name="actions">The actions to be translated to behaviors.</param>
/// <param name="plan">A plan object which is a container for behaviors this method has to generate.</param>
virtual void AddBehaviors(AIEntity& entity, const ISimulatedGameUnit& simulatedGameUnit, std::vector<const ISimulatedGameAction*> actions, Plan& plan) = 0;
};
public interface ISimulatedActionTranslator
{
/// <summary>
/// Translate actions from SimulatedGames (@actions) into any number of corresponing behaviors and add push them to the @plan object.
/// </summary>
/// <param name="entity">The entity that performs the behaviors.</param>
/// <param name="simulatedGameUnit">The unit from SimulatedGame that performed the actions.</param>
/// <param name="actions">The actions to be translated to behaviors.</param>
/// <param name="plan">A plan object which is a container for behaviors this method has to generate.</param>
void AddBehaviors(in AIEntity entity, in ISimulatedGameUnit simulatedGameUnit,in IEnumerable<ISimulatedGameAction> actions, ref Plan plan);
}