Skip to content

AEC Loop

Both Gwent wrappers are PettingZoo AEC environments. AEC means only one agent is selected to act at a time, and trainers advance the game by repeatedly reading the active agent and submitting one action.

Standard Loop

Use env(...) for trainer integrations that should get PettingZoo's standard out-of-bounds and order-enforcing wrappers:

from gwent.rl.pettingzoo import env

game = env(seed=123)
game.reset()

for agent in game.agent_iter():
    observation, reward, termination, truncation, info = game.last()
    if termination or truncation:
        action = None
    else:
        mask = observation["action_mask"]
        action = int(mask.nonzero()[0][0])
    game.step(action)

Use raw_env(...) when tests or debugging need direct access to Gwent-specific diagnostic properties such as core_state, rng, observation_feature_names, selected_decks, or drafts.

Turn Selection

agent_selection is derived from the core engine:

  • If a pending choice exists, the pending-choice player acts.
  • Otherwise the current active_player acts.
  • In the deckbuilding meta environment, the active builder acts until both decks are selected and an inner match environment starts.

Non-active agents still have observations, but their action_mask is all zeros and infos[agent]["legal_action_ids"] is empty.

Dead Steps

When an agent is terminated or truncated, call step(None) as PettingZoo expects. The wrapped env(...) form enforces order and bounds before actions reach the raw environment. The raw environment delegates dead-step handling to PettingZoo's AEC base helpers.

Masks And Infos

Every observation is a dictionary:

{
    "observation": np.ndarray,
    "action_mask": np.ndarray,
}

For the selected live agent, action_mask.nonzero() matches infos[agent]["legal_action_ids"]. For all other agents, the mask is empty. Illegal live actions fail loudly instead of silently ending the match.