Hiding Information
It is vital to ensure that when an Agent is making a decision it is not able to access any information in the full game state which is invisible to it. This is especially true when running a competition, but also applies when comparing different AI techniques to deal with imperfect information games.
The crucial method that needs to be implemented carefully for any new game is:
@Override
public AbstractGameState _copy(int playerID) {...}
This is called to get the current game state from the perspective of the agent before feeding the result to the getAction(AbstractGameState state, List<AbstractAction> availableActions)
method on the AI (or Human GUI) agent.
The convention TAG uses is that the following are true for any Game State (GS) that is fed to an Agent:
- Any information the player knows is accurate in GS
- Any information the player does not know is randomised in GS across all possible values (possible from the point of view of the player that is)
- Information is clearly marked in GS as to whether the player knows it accurately or not
This means that the GS an Agent receives is a single ‘determinisation’ of the true state. It is important to realise that the agent can freely look at the contents of the hidden hand of cards (for example) of another player, but cannot rely on this data being at all accurate.
The third point in the list above is controlled by the VisibilityMode
of the Component, which is one of VISIBLE_TO_ALL, HIDDEN_TO_ALL, VISIBLE_TO_OWNER, FIRST_VISIBLE_TO_ALL, LAST_VISIBLE_TO_ALL
.
By default, if there is no IComponentContainer
interface implemented, it is assumed that a Component is fully visible to all players.
Beyond this, the PartialObservableDeck
Component provides a much richer interface to define visibility of each individual item in the Deck to each individual player (a Deck does not need to contain Cards, for example you can have a Deck of Loot tokens, or a Deck of Dice). For this reason, PartialObservableDeck
has a VisibilityMode
of MIXED_VISIBIILITY
.
Hence, when implementing a Game ensure that you:
- Mark all Components with their Visibility status. (And use
PartialObservableDeck
for most situations where information is partially hidden, as it comes with a whole load of useful methods, such as shuffling all hidden items.) - In the
_copy(int playerId)
method of GS, take care to shuffle/randomise all information that is hidden from the perspective ofplayerId
. - Ensure you provide sufficient public
getXXX()
methods on the GS so that an AI agent can get the information it needs/wants to make a decision.
When implementing an Agent:
- Remember that although you can interrogate GS to see hidden information in an opponent’s hand or elsewhere, this is entirely random.
- If you want to get another determinisation, you can call
_copy(playerId)
again. This for example is what Information Set MCTS does on each iteration.
Points to Note
There are a few flies in the ointment (or opportunities for future work):
- AbstractGameState retains a History of all actions taken so far. This History is written from the perspective of the player taking the action and may therefore refer to information hidden to others. The purpose of the History is to ease debugging and GUI display, and not to be used to define the state. For this reason the History is wiped when redeterminising a state in a competition.
- Currently there is no facility to define a specific reduced information set for an item; it is either known or unknown. This is an issue for future development, probably via an enhancement to
PartialObservableDeck
. An example this would be required for is Hanabi, where we may know that a card is Blue, but not exactly which Blue card. - The redeterminisation of a GS does not need to result in a ‘likely’ set of data, just a theoretically possible one. There is no mechanism to apply a non-uniform posterior distribution that takes account, for example, of previous actions (in Poker a high bid is more likely to indicate good cards…this is completely ignored, and the redeterminisation may give two Aces to the player who just folded).
- There are currently limited options to tweak the internals of a GS by an Agent as a default - if for example an AI Agent wants to enforce its own calculate posterior distribution over hidden information. This is entirely down to the game implemention.