Hiding Information

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. (Well, actually this is only true for Components that implement the IComponentContainer interface. If this interface is not implemented, then the default assumption is that the 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 (and a Deck does not need to contain Cards, you can have a Deck of Loot tokens, or a Deck of Dice if you want/need to) - for this reason PartialObservableDeck has a VisibilityMode of MIXED_VISIBIILITY.

Hence, when implementing a Game ensure that you:

  1. 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.)
  2. In the _copy(int playerId) method of GS, take care to shuffle/randomise all information that is hidden from the perspective of playerId.
  3. 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:

  1. Remember that although you can interrogate GS to see hidden information in an opponent’s hand or elsewhere, this is entirely random.
  2. 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.