Class GameContext

java.lang.Object
net.demilich.metastone.game.GameContext
All Implemented Interfaces:
java.io.Serializable, java.lang.Cloneable, java.lang.Comparable<GameContext>, EntityZoneTable, Inventory

public class GameContext
extends java.lang.Object
implements java.lang.Cloneable, java.io.Serializable, Inventory, EntityZoneTable, java.lang.Comparable<GameContext>
A game context helps execute a match of Spellsource, providing a place to store state, deliver requests for actions to players, apply those player actions through a GameLogic, and then save the updated state as a result of those actions.

For example, this code starts a game between two opponents that perform random actions:

 
 GameContext context = GameContext.fromTwoRandomDecks();
 context.setBehaviour(GameContext.PLAYER_1, new PlayRandomBehaviour());
 context.setBehaviour(GameContext.PLAYER_2, new PlayRandomBehaviour());
 context.play();
 // The game is over here.
 
 

This will start a game between two opponents that try to play a little smarter, using the Spellsource agent GameStateValueBehaviour. It will also use a pair of decks to do it.

 
 GameContext context = new GameContext();
 for (int playerId : new int[] {GameContext.PLAYER_1, GameContext.PLAYER_2}) {
   context.setBehaviour(playerId, new GameStateValueProvider());
   context.setDeck(playerId, Deck.randomDeck("RED", DeckFormat.getFormat("Standard")));
 }
 context.play();
 
 

The most important part of the game state is encoded inside the fields of the Player object in getPlayers(), like Player.getMinions(). The actions taken by the players are delegated to the Behaviour objects in getBehaviours().

Game state is composed of a variety of fields that live inside the context. These fields are:

  • The getPlayers() player objects. This includes zones, attributes on the player object itself, and some statistics fields.
  • The getEnvironment() "environment variables," referring to state or memory in the game that does not live on entities.
  • The getTriggers() value from the getLogic() trigger manager.
  • The DeckFormat living in getDeckFormat().
  • The next entity ID that will be returned by GameLogic.generateId(), which is stored in GameLogic.getIdFactory()'s values.
  • The seed of GameLogic.getSeed() and the internal serialized state of the GameLogic.getRandom() random object indicating the next value.
  • The getTempCards() temporary cards in a catalogue. These include cards that are generated by effects like Build-A-Beast.
  • The getTurn() current turn.
  • The getTurnState() current turn state.
  • The getActivePlayerId() currently active player ID.
  • The getActionsThisTurn() number of actions taken this turn.
  • The state implicit in the call stack of the currently executing action. While this cannot be inspected or easily serialized, consider that while awaiting a mulligan, battlecry choice or discover action this instance is in the middle of executing a function but still has a valid game state.

To get a copy of the state, use getGameStateCopy(); while you can access a modifiable copy of the GameState with getGameState(), you're encouraged only use the GameLogic methods (which mutate the state stored inside this game context) in order to always have valid data.

Game actions are chosen by Behaviour objects living inside getBehaviours(). Typically, the GameLogic instance will call getActivePlayer() for the currently active player, call getBehaviours() to get the behaviour, and then call Behaviour.requestAction(GameContext, Player, List) to request which action of a list of actions the player takes. Note that this is just called as a plain function, so the end user of the GameContext is responsible for the blocking that would occur if e.g. the Behaviour waits on user input to answer the action request. Ordinarily, as long as the thread running GameContext doesn't do anything but process the game, blocking on user input isn't an issue; only one player may take an action at a time.

State is mutated by the GameLogic instance. It will process a player's selected GameAction with performAction(int, GameAction), mutating the state fields in the GameContext appropriately until it encounters the next request for actions (e.g., once an action has been processed, when a battlecry is resolved, or when the player must choose which card to discover). It is not necessarily dangerous to modify the game state without using GameLogic, though doing so many break what players would expect to happen based on the text of cards.

Generally, this instance does not provide a way to "choose" actions in game. The end user of a GameContext is expected to provide a Player instance with a Behaviour that suits the end user's needs. Override the methods of the Behaviour to model how you'd like to behave given the information incoming to those methods.

Executing the card code is complicated, and follows the adage: Every sufficiently complex program has a poorly implemented version of common Lisp. At a high level, players take turns generating GameAction objects, whose GameAction.execute(GameContext, int) implementation does things like GameLogic.castSpell(int, SpellDesc, EntityReference, EntityReference, TargetSelection, boolean, GameAction) or GameLogic.summon(int, Minion, Entity, int, boolean). "spell" fields inside the CardDesc of the card currently being played get executed by looking at their SpellArg.CLASS and creating an instance of the corresponding subclass of Spell. Subsequent "sub-spells" are called by SpellUtils.castChildSpell(GameContext, Player, SpellDesc, Entity, Entity). Various components like ValueProvider or Condition are defined in the card JSON and used to provide program-like functionality.

To illustrate, the key parts of the call stack of a player playing the card Novice Engineer looks like this:

  1. At the top of the stack: play(). This is the main entry point for a started game and we exit this when the game is over.
  2. takeActionInTurn(), which is the core step in the game loop. To get possible play actions, we called Card.play() on each card in the hand, which gives us GameAction objects. Then, we called Behaviour.requestAction(GameContext, Player, List) to get which action we wanted the player to take of the possible choices from getValidActions().
  3. GameAction.execute(GameContext, int), which actually starts the chain of effects for playing a card.
  4. GameLogic.summon(int, Minion, Entity, int, boolean), which summons minions.
  5. GameLogic.resolveOpeners(int, Actor)}, which resolves the battlecry written on Novice Engineer.
  6. GameLogic.castSpell(int, SpellDesc, EntityReference, EntityReference, TargetSelection, boolean, GameAction), which actually evaluates all effects, not just spells. This method will create an instance of a DrawCardSpell and eventually calls...
  7. Spell.cast(GameContext, Player, SpellDesc, Entity, List), which provides common targeting code for spell effects. The meat and bones of effects like drawing a card is done by:
  8. Spell.cast(GameContext, Player, SpellDesc, Entity, List), the method that all 200+ spells implement to actually cause effects in game. DrawCardSpell therefore gets its...
  9. DrawCardSpell#onCast(GameContext, Player, SpellDesc, Entity, Entity) method called. In order to cause a card to be drawn, this method calls...
  10. GameLogic.drawCard(int, Entity), which is where the actual work of moving a card from the Player.getDeck() Zones.DECK to the hand occurs.
The runGym methods in the test code for this module provides an great template for testing rules and card behaviour using Spellsource.
See Also:
for more about how a game is "played.", for the interface that the delegates player actions and notifications to. This is both the "event handler" specification for which events a player may be interested in; and also a "delegate" in the sense that the object implementing this interface makes decisions about what actions in the game to take (with e.g. ., for an example behaviour that just makes random decisions when requested., for the class that actually implements the Spellsource game rules. This class requires a because it manipulates the state stored in it., for a class that encapsulates all of the state of a game of Spellsource., to access and modify the game state., to get a copy of the state that can be stored and diffed., to see a summary of a player's activity during a game., for a way to enumerate through all of the entities in the game., Serialized Form
  • Field Details

  • Constructor Details

    • GameContext

      public GameContext()
      Creates a game context with two empty players and two PlayRandomBehaviour behaviours.

      Hero cards are not given to the players. Thus, this is not enough typically to mutate and run a game. Use GameContext(String...) to create a game initialized with the specified hero classes.

    • GameContext

      public GameContext​(GameContext fromContext)
      Creates a game context from another context by copying it.
      Parameters:
      fromContext - The other context to copy.
    • GameContext

      public GameContext​(java.lang.String... heroClasses)
      Creates an uninitialized game context (i.e., no cards in the decks of the players or behaviours specified). A hero card is retrieved and given to each player.

      This is typically the absolute minimum needed to mutate and run a game.

      Parameters:
      heroClasses - The player's hero classes.
  • Method Details

    • fromTrace

      public static GameContext fromTrace​(Trace trace)
      Creates a game context from a trace.
      Parameters:
      trace -
      Returns:
    • addTempCard

      public void addTempCard​(Card card)
      Adds a temporary card. A temporary card is a card that exists only in this instance and not in the CardCatalogue.
      Parameters:
      card - The card to add, typically made with code.
    • clone

      public GameContext clone()
      Clones the game context, recursively cloning the game state and logic.

      Internally, this is used by AI functions to evaluate a game state until a win condition (or just the end of the turn) is reached.

      This method is not thread safe. Two threads can't clone and mutate a context at the same time.

      Overrides:
      clone in class java.lang.Object
      Returns:
      A cloned instance of the game context.
    • close

      @Suspendable protected void close()
      Clears state to ensure this context isn't referencing it anymore.
    • endGame

      @Suspendable protected void endGame()
      Ends the game immediately.
    • notifyPlayersGameOver

      @Suspendable protected void notifyPlayersGameOver()
    • calculateStatistics

      protected void calculateStatistics()
    • endTurn

      @Suspendable public void endTurn()
      Ends the current player's turn immediately, setting the active player to their opponent.
    • updateAndGetGameOver

      @Suspendable public boolean updateAndGetGameOver()
      Determines whether the game is over (decided). As a side effect, records the current result of the game.
      Returns:
      true if the game has been decided by concession or because one of the two heroes have been destroyed.
    • getActivePlayer

      public Player getActivePlayer()
      Gets a reference to the currently active player (the player whose turn it is).
      Returns:
      The player whose turn it is.
    • getActivePlayerId

      public int getActivePlayerId()
      Gets the integer ID of the player whose current turn it is.
      Returns:
      The integer ID.
    • getAdjacentMinions

      public java.util.List<Actor> getAdjacentMinions​(EntityReference targetReference)
      Gets the minions adjacent to the given minion. Omits permanents.
      Parameters:
      targetReference - The minion whose adjacent minions we should get.
      Returns:
      The adjacent minions.
    • getCardById

      public Card getCardById​(java.lang.String cardId)
      Gets a card by ID, checking both the catalogue and the cards in getTempCards().
      Parameters:
      cardId - The string card ID.
      Returns:
      A clone of the Card.
    • getDamageStack

      public java.util.Deque<java.lang.Integer> getDamageStack()
      Retrieves all the damage values that are supposed to be applied.

      Implements spells that override the amount of damage something deals.

      Returns:
      The stack.
    • getDeckFormat

      public DeckFormat getDeckFormat()
      Gets the DeckFormat of this context, or the currently legal cards in terms of CardSet objects.
      Returns:
      A DeckFormat object.
    • getEnvironment

      public java.util.Map<Environment,​java.lang.Object> getEnvironment()
      Gets a reference to the game context's environment, a piece of game state that keeps tracks of which minions are currently being summoned, which targets are being targeted, how much damage is set to be dealt, etc.

      This helps implement a variety of complex rules in the game.

      Returns:
      A mutable map of environment variables.
      See Also:
      for a description of the environment variables.
    • getOutputCard

      public Card getOutputCard()
      Gets the current output card.
      Returns:
      The event card.
      See Also:
      for more.
    • getEventTargetStack

      public java.util.Deque<EntityReference> getEventTargetStack()
      Gets the current event target stack.
      Returns:
      A stack of targets.
      See Also:
      for more.
    • getLeftMinions

      public java.util.List<Actor> getLeftMinions​(EntityReference minionReference)
      Gets the minions to the left on the battlefield of the given minion.
      Parameters:
      minionReference - An EntityReference pointing to the minion.
      Returns:
      A list of entities to the left of the provided minion.
    • getLogic

      public GameLogic getLogic()
      Gets a reference to the game logic associated with this context.
      Returns:
      A GameLogic instance.
      See Also:
      for more.
    • getMinionCount

      public int getMinionCount​(Player player)
      Gets the number of minions a player has.
      Parameters:
      player - The player to query.
      Returns:
      The count of minions.
    • getOpponent

      public Player getOpponent​(Player player)
      Gets the opponent from the point of view of the given player.
      Parameters:
      player - The friendly player.
      Returns:
      The opposing player from the point of view of the player argument.
    • getOppositeMinions

      public java.util.List<Actor> getOppositeMinions​(EntityReference minionReference)
      Gets the Actor entities geometrically opposite of the given minionReference on the Zones.BATTLEFIELD.
      Parameters:
      minionReference - The minion from whose perspective we will consider "opposite."
      Returns:
      The list of Actor (typically one or two) that are geometrically opposite from the minion referenced by minionReference.
    • getPlayer

      public Player getPlayer​(int index)
      Gets the player at the given index.
      Parameters:
      index - PLAYER_1 or PLAYER_2
      Returns:
      A reference to the player with that ID / at that index.
    • hasPlayer

      public boolean hasPlayer​(int id)
      Parameters:
      id - PLAYER_1 or PLAYER_2
      Returns:
      true if the game context has a valid Player object at that index.
    • getPlayer1

      public Player getPlayer1()
      Gets the first player.
      Returns:
      A player object.
    • getPlayer2

      public Player getPlayer2()
      Gets the second player.
      Returns:
      A player object.
    • getPlayers

      public java.util.List<Player> getPlayers()
      Each player holds the player's AbstractBehaviour and all of the Entity objects in the game.
      Returns:
      A read only list of Player objects.
    • getBehaviours

      public java.util.List<Behaviour> getBehaviours()
    • getRightMinions

      public java.util.List<Actor> getRightMinions​(EntityReference minionReference)
      Gets minions geometrically right of the given minionReference on the Zones.BATTLEFIELD that belongs to the specified player.
      Parameters:
      minionReference - The minion reference.
      Returns:
      A list of Actor (sometimes empty) of minions to the geometric right of the minionReference.
    • getSummonReferenceStack

      public java.util.Deque<EntityReference> getSummonReferenceStack()
      Gets the minions whose summoning is currently being processed.

      This stack can have multiple entries because battlecries or secrets can trigger summoning of other minions in the middle of evaluating a GameLogic.summon(int, Minion, Entity, int, boolean).

      Returns:
      A stack of summons.
    • getTotalMinionCount

      public int getTotalMinionCount()
      Gets the total number of minions on both player's Zones.BATTLEFIELD.
      Returns:
      A total.
    • getTurn

      public int getTurn()
      Gets the current turn.
      Returns:
      The turn. 0 is the first turn.
    • getTurnState

      public TurnState getTurnState()
      Gets the current TurnState
      Returns:
      The turn state of this context.
    • getValidActions

      public java.util.List<GameAction> getValidActions()
    • getWinningPlayerId

      public int getWinningPlayerId()
      Gets the winning player's ID or -1 if no player is the winner.
      Returns:
      The winning player's ID or -1 if no player is the winner.
    • getIgnoreEvents

      public boolean getIgnoreEvents()
      When true, the game logic doesn't handle an events being raised.
      Returns:
      true if the game context should ignore incoming events.
    • init

      @Suspendable public void init()
      Initializes a game.

      This function will choose a starting player, then move cards into the mulligan (set aside) zone, ask for mulligans, and start the game. resume() will start the first turn.

    • init

      @Suspendable public void init​(int startingPlayerId)
      Initialized the game with the specified starting player. When called by itself, does not initialize the trace.
      Parameters:
      startingPlayerId -
    • traceMulligans

      protected void traceMulligans​(java.util.List<Card> mulligansActive, java.util.List<Card> mulligansNonActive)
    • startTrace

      protected void startTrace()
      Ensures that the game state is traced / recorded
    • performAction

      @Suspendable public void performAction​(int playerId, GameAction gameAction)
      Executes the specified game action, typically by calling GameLogic.performGameAction(int, GameAction).
      Parameters:
      playerId - The player who's performing the action.
      gameAction - The action to perform.
      See Also:
      for more about game actions.
    • play

      @Suspendable public void play()
      Plays the game.

      When a game is played, mulligans are requested from both players, and then each player is asked for actions until the player can't take any.

      Play relies on the Behaviour delegates to determine what a player's chosen action is. It takes the chosen action and feeds it to the GameLogic, which executes the effects of that action until the next action needs to be requested.

      See Also:
      for a breakdown of a specific turn.
    • play

      @Suspendable public void play​(boolean fork)
    • takeActionInTurn

      @Suspendable public boolean takeActionInTurn()
      Requests an action from a player and takes it in the turn.

      This method will call Behaviour.requestAction(GameContext, Player, List) to get an action from the currently active player. It then calls performAction(int, GameAction) with the returned GameAction.

      Returns:
      false if the player selected an EndTurnAction, indicating the player would like to end their turn.
    • resolveSingleTarget

      public Entity resolveSingleTarget​(EntityReference targetKey) throws TargetNotFoundException
      Tries to find the entity references by the EntityReference.
      Parameters:
      targetKey - The reference to find.
      Returns:
      The Entity pointed to by the EntityReference, or null if the provided entity reference was null or EntityReference.NONE
      Throws:
      TargetNotFoundException - if the reference could not be found. Game rules shouldn't be looking for references that cannot be found.
    • resolveSingleTarget

      public Entity resolveSingleTarget​(EntityReference targetKey, boolean rejectRemovedFromPlay) throws TargetNotFoundException
      Resolves a single target given the specification, even if the specification is a EntityReference.isTargetGroup()
      Parameters:
      targetKey -
      rejectRemovedFromPlay -
      Returns:
      Throws:
      TargetNotFoundException
    • resolveTarget

      public java.util.List<Entity> resolveTarget​(Player player, Entity source, EntityReference targetKey)
      Interprets EntityReference that specifies a group of Entity objects, like EntityReference.ALL_MINIONS.
      Parameters:
      player - The player from whose point of view this method interprets the EntityReference.
      source - The entity from whose point of view this method interprets the EntityReference.
      targetKey - The EntityReference.
      Returns:
      A potentially empty list of entities.
      See Also:
      for more about how target resolution works.
    • setIgnoreEvents

      public void setIgnoreEvents​(boolean ignoreEvents)
    • getEventValue

      public int getEventValue()
    • getTargetOverride

      @Nullable public @Nullable Entity getTargetOverride​(@NotNull @NotNull Player player, @Nullable @Nullable Entity source)
      Retrieves the current target override specified in the environment.

      A target override can be a specific EntityReference or a "group reference" (logical entity reference) that returns exactly zero or one targets. The override should almost always succeed, and it would be surprising if there were overrides that resulted in no targets being found.

      Parameters:
      player - The player for whom the override should be evaluated.
      source - The source entity of this override.
      Returns:
      An Entity or null if no override is specified.
    • startGame

      @Suspendable protected void startGame()
      Fire the start game events here instead
    • getNonActivePlayerId

      public int getNonActivePlayerId()
    • startTurn

      @Suspendable public void startTurn​(int playerId)
      Starts the turn for a player.
      Parameters:
      playerId - The player whose turn should be started.
    • toString

      public java.lang.String toString()
      Overrides:
      toString in class java.lang.Object
    • tryFind

      @Nullable public @Nullable Entity tryFind​(EntityReference targetKey)
      Tries to find an entity given the reference.
      Parameters:
      targetKey - The reference to the entity.
      Returns:
      The found Entity, or null if no entity was found.
    • tryFind

      @Nullable public @Nullable Entity tryFind​(EntityReference targetKey, boolean rejectRemovedFromPlay)
      Tries to find an entity given the reference.
      Parameters:
      targetKey - The reference to the entity.
      rejectRemovedFromPlay -
      Returns:
      The found Entity, or null if no entity was found.
    • setLogic

      public void setLogic​(GameLogic logic)
    • setDeckFormat

      public GameContext setDeckFormat​(DeckFormat deckFormat)
    • setEnvironment

      public void setEnvironment​(java.util.Map<Environment,​java.lang.Object> environment)
    • getWinner

      public Player getWinner()
    • setWinner

      public void setWinner​(Player winner)
    • getStatus

      public GameStatus getStatus()
    • setStatus

      public void setStatus​(GameStatus result)
    • setTurnState

      public void setTurnState​(TurnState turnState)
    • setTurn

      public void setTurn​(int turn)
    • getActionsThisTurn

      public int getActionsThisTurn()
    • setActionsThisTurn

      public void setActionsThisTurn​(int actionsThisTurn)
    • setPlayer1

      public void setPlayer1​(Player player1)
    • setPlayer2

      public void setPlayer2​(Player player2)
    • setGameState

      public void setGameState​(GameState state)
    • setPlayer

      public GameContext setPlayer​(int index, Player player)
    • setActivePlayerId

      public void setActivePlayerId​(int id)
    • getTargetLogic

      public TargetLogic getTargetLogic()
    • setTargetLogic

      public void setTargetLogic​(TargetLogic targetLogic)
    • getTempCards

      public CardList getTempCards()
    • setTempCards

      public void setTempCards​(CardList tempCards)
    • isDisposed

      public boolean isDisposed()
    • getGameId

      public java.lang.String getGameId()
    • getEntities

      public java.util.stream.Stream<Entity> getEntities()
      Gets all the entities in the game, aside from hidden ones, as a Stream.
      Returns:
      The Stream of game entities.
    • onWillPerformGameAction

      @Suspendable public void onWillPerformGameAction​(int playerId, GameAction action)
    • onDidPerformGameAction

      @Suspendable public void onDidPerformGameAction​(int playerId, GameAction action)
    • getGameState

      public GameState getGameState()
    • getGameStateCopy

      public GameState getGameStateCopy()
    • concede

      @Suspendable public void concede​(int playerId)
      Concedes a game by destroying the specified player's hero and calling end game.
      Parameters:
      playerId - The player that should concede/lose
    • onEnchantmentFired

      @Suspendable public void onEnchantmentFired​(Enchantment enchantment)
      Raised when a Enchantment is fired (i.e., a secret is about to be played or a special effect hosted by a minion/weapon is about to happen).
      Parameters:
      enchantment - The spell trigger that fired.
    • getSpellValueStack

      public java.util.Deque<java.lang.Integer> getSpellValueStack()
      Returns the spell values calculated so far by MetaSpell spells.

      Implements Living Mana. Using a stack fixes issues where a later MetaSpell busts an earlier one.

      Returns:
      A stack of Integer spell values.
    • getEventValueStack

      public java.util.Deque<java.lang.Integer> getEventValueStack()
    • getSpellTargetStack

      public java.util.Deque<EntityReference> getSpellTargetStack()
    • getOutputStack

      public java.util.Deque<EntityReference> getOutputStack()
    • getAttackerReferenceStack

      public java.util.Deque<EntityReference> getAttackerReferenceStack()
    • getLastCardPlayedMap

      public java.util.Map<java.lang.Integer,​EntityReference> getLastCardPlayedMap()
    • setLastCardPlayed

      public void setLastCardPlayed​(int playerId, EntityReference cardReference)
    • getLastCardPlayedBeforeCurrentSequenceMap

      public java.util.Map<java.lang.Integer,​EntityReference> getLastCardPlayedBeforeCurrentSequenceMap()
    • setLastCardPlayedBeforeCurrentSequence

      public void setLastCardPlayedBeforeCurrentSequence​(int playerId, EntityReference cardReference)
    • getLastCardPlayed

      public EntityReference getLastCardPlayed​(int playerId)
    • getLastCardPlayed

      public EntityReference getLastCardPlayed()
    • getLastSpellPlayedThisTurnMap

      public java.util.Map<java.lang.Integer,​EntityReference> getLastSpellPlayedThisTurnMap()
    • setLastSpellPlayedThisTurn

      public void setLastSpellPlayedThisTurn​(int playerId, EntityReference cardReference)
    • getLastCardPlayedBeforeCurrentSequence

      public EntityReference getLastCardPlayedBeforeCurrentSequence()
    • getLastCardPlayedBeforeCurrentSequence

      public EntityReference getLastCardPlayedBeforeCurrentSequence​(int playerId)
    • getAftermaths

      public EnvironmentAftermathTriggeredList getAftermaths()
    • getNonActivePlayer

      protected Player getNonActivePlayer()
    • resume

      @Suspendable public void resume()
      Resumes a game, playing it to completion.

      Useful for implementing Monte Carlo Tree Search AI algorithms.

    • getEventSourceStack

      public java.util.Deque<EntityReference> getEventSourceStack()
      Retrieves the stack of event sources.
      Returns:
      A stack of event source EntityReference objects.
    • simulate

      public static SimulationResult simulate​(java.util.List<GameDeck> decks, java.util.function.Supplier<Behaviour> player1, java.util.function.Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, java.util.concurrent.atomic.AtomicInteger matchCounter)
      Runs a simulation of the decks with the specified AIs.

      This call will be blocking regardless of using it in a parallel fashion.

      Parameters:
      decks - Decks to run the match with. At least two are required.
      player1 - A Supplier (function which returns a new instance) of a Behaviour that corresponds to an AI to use for this player.

      For example, use the argument GameStateValueBehaviour::new to specify that the first player's AI should be a game state value behaviour.

      player2 - A Supplier (function which returns a new instance) of a Behaviour that corresponds to an AI to use for this player.
      gamesPerMatchup - The number of games per matchup to play. The number of matchups total can be calculated with simulationCount(int, int, boolean).
      useJavaParallel - When true, uses the Java Streams Parallel interface to parallelize this computation on this JVM instance.
      matchCounter - When not null, the simulator will increment this counter each time a match is completed. This can be used to implement progress on a different thread.
    • simulate

      public static SimulationResult simulate​(java.util.List<GameDeck> decks, java.util.function.Supplier<Behaviour> player1, java.util.function.Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, boolean includeMirrors)
      Runs a simulation of the decks with the specified AIs.

      This call will be blocking regardless of using it in a parallel fashion.

      Parameters:
      decks - Decks to run the match with. At least one is required if includeMirrors is true, otherwise at least two.
      player1 - A Supplier (function which returns a new instance) of a Behaviour that corresponds to an AI to use for this player.

      For example, use the argument GameStateValueBehaviour::new to specify that the first player's AI should be a game state value behaviour.

      player2 - A Supplier (function which returns a new instance) of a Behaviour that corresponds to an AI to use for this player.
      gamesPerMatchup - The number of games per matchup to play. The number of matchups total can be calculated with simulationCount(int, int, boolean).
      useJavaParallel - When true, uses the Java Streams Parallel interface to parallelize this computation on this JVM instance.
      includeMirrors - When true, includes mirror matchups for each deck.
    • simulate

      public static SimulationResult simulate​(java.util.List<GameDeck> decks, java.util.function.Supplier<Behaviour> player1, java.util.function.Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, boolean includeMirrors, java.util.concurrent.atomic.AtomicInteger matchCounter, java.util.function.Consumer<GameContext> mutateConstructedGameContext, java.util.function.Consumer<GameContext> afterGameContextInit)
      Runs a simulation of the decks with the specified AIs.

      This call will be blocking regardless of using it in a parallel fashion.

      When more than two decks are specified, the players will have their statistics merged with multiple decks.

      Parameters:
      decks - Decks to run the match with. At least two are required.
      player1 - A Supplier (function which returns a new instance) of a Behaviour that corresponds to an AI to use for this player.

      For example, use the argument GameStateValueBehaviour::new to specify that the first player's AI should be a game state value behaviour.

      player2 - A Supplier (function which returns a new instance) of a Behaviour that corresponds to an AI to use for this player.
      gamesPerMatchup - The number of games per matchup to play. The number of matchups total can be calculated with simulationCount(int, int, boolean).
      useJavaParallel - When true, uses the Java Streams Parallel interface to parallelize this computation on this JVM instance.
      includeMirrors - When true, includes mirror matchups
      matchCounter - When not null, the simulator will increment this counter each time a match is
      mutateConstructedGameContext - A handler that can modify the game context for customization after it was initialized with the specified decks but before mulligans. For example, the GameLogic.getSeed() can
      afterGameContextInit - A handler that can add/remove things to the game context after the players have mulliganned.
    • simulationCount

      public static int simulationCount​(int numberOfDecks, int gamesPerMatchup, boolean includeMirrors)
      Calculates the expected number of simulations that will be run given the parameters of the simulation function.
      Parameters:
      numberOfDecks - The number of decks (i.e., decks.size())
      gamesPerMatchup - The number of games to play per unique deck pair.
      includeMirrors - When true, include mirror matches.
      Returns:
    • simulate

      public static void simulate​(java.util.List<GameDeck> deckPair, java.util.List<java.util.function.Supplier<Behaviour>> behaviours, int gamesPerMatchup, boolean reduce, java.util.function.Consumer<SimulationResult> computed) throws java.lang.InterruptedException
      A generator of simulation results. Blocks until all simulations are complete.
      Parameters:
      deckPair - Two decks to test. Specify the same deck twice to perform a mirror match.
      behaviours - The behaviours to use. When an empty list is specified, uses PlayRandomBehaviour.
      gamesPerMatchup - The number of games to play per matchup.
      reduce - When true, merges matches that have the same behaviour and decks.
      computed - The callback that will be fed a simulation result whenever it is computed.
      Throws:
      java.lang.InterruptedException
    • fromDecks

      public static GameContext fromDecks​(java.util.List<GameDeck> decks, Behaviour behaviour1, Behaviour behaviour2)
      Gets a game context that's ready to play from two GameDeck objects.
      Parameters:
      decks - The GameDecks to use for the players.
      Returns:
      A GameContext for which play() will immediately work.
      See Also:
      to get the log of actions that were taken in the game., to actually execute the game.
    • fromDecks

      public static GameContext fromDecks​(java.util.List<GameDeck> decks)
      Gets a game context that's ready to play from two GameDeck objects. Uses the PlayRandomBehaviour for both players.
      Parameters:
      decks - The GameDecks to use for the players.
      Returns:
      A GameContext for which play() will immediately work.
      See Also:
      to get the log of actions that were taken in the game., to actually execute the game.
    • fromDeckLists

      public static GameContext fromDeckLists​(java.util.List<java.lang.String> deckLists)
      Gets a game context that's ready to play from two deck lists encoded in the standard community format. Uses the PlayRandomBehaviour for both players.
      Parameters:
      deckLists - A Hearthstone deck string or a deck list of the format, with newlines:

      Name: Deck Name

      Class: Color Hero Class (e.g., PRIEST) specified in HeroClass.

      Format: Standard, Wild, Custom or others specified in DeckFormat.formats().

      1x Card Name

      2x Card Name

      Returns:
      A game context.
      See Also:
      to get the log of actions that were taken in the game., to actually execute the game.
    • fromDeckLists

      public static GameContext fromDeckLists​(java.util.List<java.lang.String> deckLists, Behaviour behaviour1, Behaviour behaviour2)
      Gets a game context that's ready to play from two deck lists encoded in the standard community format. Uses the specified behaviours.
      Parameters:
      deckLists - A Hearthstone deck string or a deck list of the format, with newlines:

      Name: Deck Name

      Class: Color Hero Class (e.g., PRIEST) specified in HeroClass.

      Format: Standard, Wild, Custom or others specified in DeckFormat.formats().

      1x Card Name

      2x Card Name

      behaviour1 - An implementation of Behaviour for player 1
      behaviour2 - An implementation of Behaviour for player 2
      Returns:
      A game context
    • fromTwoRandomDecks

      public static GameContext fromTwoRandomDecks()
      Creates a new game context with two random decks and random play behaviour.
      Returns:
      A game context
      See Also:
      to actually execute the game.
    • fromTwoRandomDecks

      public static GameContext fromTwoRandomDecks​(long seed)
    • fromDecks

      public static GameContext fromDecks​(long seed, java.util.List<GameDeck> decks)
    • fromTwoRandomDecks

      public static GameContext fromTwoRandomDecks​(DeckFormat format)
      Creates a game with two random decks in the specified format.
      Parameters:
      format -
      Returns:
    • fromState

      public static GameContext fromState​(GameState state)
      Creates a game context from the given state.
      Parameters:
      state - A GameState object.
    • getDeckCombinations

      public static java.util.List<java.lang.String[]> getDeckCombinations​(java.util.List<java.lang.String> decks)
      Creates all the possible combinations of decks given a list of decks
      Parameters:
      decks - An input list of deck names
      Returns:
      A list of 2-tuples of deck names.
    • getDeckCombinations

      public static java.util.List<GameDeck[]> getDeckCombinations​(java.util.List<GameDeck> decks, boolean includeMirrors)
    • getMillisRemaining

      public java.lang.Long getMillisRemaining()
      The number of milliseconds remaining until the active player is automatically changed.
      Returns:
      null if there are no turn/mulligan timers, otherwise the amount of time remaining in milliseconds.
    • getTrace

      public Trace getTrace()
      Retrieves a trace of this game's actions.

      Serialization is not guaranteed to work on later versions of the codebase.

      Returns:
      A Trace containing all the actions that were performed in this game and its initial state.
    • getDeck

      @Suspendable public GameDeck getDeck​(Player player, java.lang.String name)
      Returns null, because by default GameContext are not networked and have no sense of inventory.
      Specified by:
      getDeck in interface Inventory
      Parameters:
      player - The player whose deck collections should be queried.
      name - The name of the deck to retrieve
      Returns:
    • getTriggerHostStack

      public java.util.Deque<EntityReference> getTriggerHostStack()
      Retrieves the stack of hosts of the currently firing trigger.
      Returns:
      A host reference, or null if the trigger didn't have a host.
    • setTargetOverride

      public void setTargetOverride​(EntityReference reference)
    • getLogger

      public org.slf4j.Logger getLogger()
    • setLogger

      public void setLogger​(org.slf4j.Logger logger)
    • resolveSingleTarget

      public <T extends Entity> T resolveSingleTarget​(Player player, Entity source, EntityReference target)
      Resolves a single target that could be a EntityReference.isTargetGroup() that points to exactly one entity, like EntityReference.FRIENDLY_HERO.
      Parameters:
      player - The source player.
      source - The entity from whose point of view this target should be evaluated.
      target - A target key to a specific entity or a named reference ("target group") that returns exactly one entity.
      Returns:
      The entity.
    • getZone

      public <E extends Entity> EntityZone<E> getZone​(int owner, Zones zone)
      Description copied from interface: EntityZoneTable
      Retrieves an EntityZone for the provided owner and zone.
      Specified by:
      getZone in interface EntityZoneTable
      Type Parameters:
      E - The type of entity hosted by this zone.
      Parameters:
      owner - The owner of the zone.
      zone - The Zones key.
      Returns:
      An EntityZone reference.
    • setBehaviours

      public void setBehaviours​(Behaviour[] behaviours)
    • setBehaviour

      public void setBehaviour​(int i, Behaviour behaviour)
    • didCallEndGame

      protected boolean didCallEndGame()
    • getFiber

      public co.paralleluniverse.fibers.Fiber<java.lang.Void> getFiber()
    • setFiber

      protected GameContext setFiber​(co.paralleluniverse.fibers.Fiber<java.lang.Void> fiber)
    • setDeck

      public void setDeck​(int playerId, GameDeck deck)
      Sets the specified player's deck and hero (by implication)
      Parameters:
      playerId -
      deck -
    • compareTo

      public int compareTo​(@NotNull @NotNull GameContext other)
      Returns 0 if the two game contexts have the same meaningful game state.

      Otherwise, returns 1 if other is "further along"

      Specified by:
      compareTo in interface java.lang.Comparable<GameContext>
      Parameters:
      other -
      Returns:
    • setTrace

      protected void setTrace​(Trace trace)
    • getSpanContext

      public io.opentracing.SpanContext getSpanContext()
      Provides context for tracing in this context. This is the OpenTracing span context, typically assigned by the matchmaker or whatever created this instance.
      Returns:
    • setSpanContext

      public GameContext setSpanContext​(io.opentracing.SpanContext spanContext)
    • getVariables

      public java.util.Map<java.lang.String,​java.util.concurrent.atomic.AtomicInteger> getVariables()
      Returns a reference to the variables stored in the game context, used by spells to maintain correct space when a strand currently being executed is cloned.
      Returns:
    • createInt

      public void createInt​(java.lang.String name, int initialValue)
      Creates an integer value in the context's cloneable storage.
      Parameters:
      name -
      initialValue -
    • addAndGetInt

      public int addAndGetInt​(java.lang.String name, int delta)
      Adds the delta value and returns the new value of the named integer from the context's cloneable storage.
      Parameters:
      name -
      delta -
      Returns:
    • getInt

      public int getInt​(java.lang.String name)
      Gets the value of the named integer in the context's cloneable storage.
      Parameters:
      name -
      Returns:
    • removeInt

      public int removeInt​(java.lang.String name)
      Removes the specified integer from the context's cloneable storage.
      Parameters:
      name -
      Returns:
    • setOtherTriggers

      public GameContext setOtherTriggers​(java.util.List<Trigger> otherTriggers)
    • getTriggers

      public java.util.List<Trigger> getTriggers()
    • getDeferredTriggersQueue

      public java.util.Deque<GameLogic.QueuedTrigger> getDeferredTriggersQueue()
    • getProcessingTriggers

      public java.util.Set<Trigger> getProcessingTriggers()
    • getActionStack

      public java.util.Deque<GameAction> getActionStack()
    • setActionStack

      public GameContext setActionStack​(java.util.Deque<GameAction> actionStack)
    • getCurrentAction

      @Nullable public @Nullable GameAction getCurrentAction()
    • onNotificationWillFire

      @Suspendable public void onNotificationWillFire​(Notification event)
    • onNotificationDidFire

      @Suspendable public void onNotificationDidFire​(Notification event)