Class GameContext
- All Implemented Interfaces:
Serializable
,Cloneable
,Comparable<GameContext>
,EntityZoneTable
,Inventory
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 thegetLogic()
trigger manager. - The
DeckFormat
living ingetDeckFormat()
. - The next entity ID that will be returned by
GameLogic.generateId()
, which is stored inGameLogic.getIdFactory()
's values. - The seed of
GameLogic.getSeed()
and the internal serialized state of theGameLogic.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:
- 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. takeActionInTurn()
, which is the core step in the game loop. To get possible play actions, we calledCard.play()
on each card in the hand, which gives usGameAction
objects. Then, we calledBehaviour.requestAction(GameContext, Player, List)
to get which action we wanted the player to take of the possible choices fromgetValidActions()
.GameAction.execute(GameContext, int)
, which actually starts the chain of effects for playing a card.GameLogic.summon(int, Minion, Entity, int, boolean)
, which summons minions.GameLogic.resolveOpeners(int, Actor)
}, which resolves the battlecry written on Novice Engineer.GameLogic.castSpell(int, SpellDesc, EntityReference, EntityReference, TargetSelection, boolean, GameAction)
, which actually evaluates all effects, not just spells. This method will create an instance of aDrawCardSpell
and eventually calls...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:Spell.cast(GameContext, Player, SpellDesc, Entity, List)
, the method that all 200+ spells implement to actually cause effects in game.DrawCardSpell
therefore gets its...DrawCardSpell#onCast(GameContext, Player, SpellDesc, Entity, Entity)
method called. In order to cause a card to be drawn, this method calls...GameLogic.drawCard(int, Entity)
, which is where the actual work of moving a card from thePlayer.getDeck()
Spellsource.ZonesMessage.Zones.DECK
to the hand occurs.
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 GameContext 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. Behaviour#requestAction(GameContext, Player, List).
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 GameContext 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 Summary
Modifier and TypeFieldDescriptionstatic final int
static final int
protected io.opentracing.SpanContext
-
Constructor Summary
ConstructorDescriptionCreates a game context with two empty players and twoPlayRandomBehaviour
behaviours.GameContext
(String... heroClasses) Creates an uninitialized game context (i.e., no cards in the decks of the players or behaviours specified).GameContext
(GameContext fromContext) Creates a game context from another context by copying it. -
Method Summary
Modifier and TypeMethodDescriptionint
addAndGetInt
(String name, int delta) Adds the delta value and returns the new value of the named integer from the context's cloneable storage.void
addTempCard
(Card card) Adds a temporary card.protected void
clone()
Clones the game context, recursively cloning the game state and logic.protected void
close()
Clears state to ensure this context isn't referencing it anymore.int
compareTo
(@NotNull GameContext other) Returns0
if the two game contexts have the same meaningful game state.void
concede
(int playerId) Concedes a game by destroying the specified player's hero and calling end game.void
Creates an integer value in the context's cloneable storage.protected boolean
protected void
endGame()
Ends the game immediately.void
endTurn()
Ends the current player's turn immediately, setting the active player to their opponent.static GameContext
fromDeckLists
(List<String> deckLists) Gets a game context that's ready to play from two deck lists encoded in the standard community format.static GameContext
fromDeckLists
(List<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.static GameContext
static GameContext
Gets a game context that's ready to play from twoGameDeck
objects.static GameContext
Gets a game context that's ready to play from twoGameDeck
objects.static GameContext
Creates a game context from the given state.static GameContext
Creates a game context from a trace.static GameContext
Creates a new game context with two random decks and random play behaviour.static GameContext
fromTwoRandomDecks
(long seed) static GameContext
fromTwoRandomDecks
(DeckFormat format) Creates a game with two random decks in the specified format.int
Gets a reference to the currently active player (the player whose turn it is).int
Gets the integer ID of the player whose current turn it is.getAdjacentMinions
(EntityReference targetReference) Gets the minions adjacent to the given minion.getCardById
(String cardId) Gets a card by ID, checking both the catalogue and the cards ingetTempCards()
.@Nullable GameAction
Retrieves all the damage values that are supposed to be applied.Returnsnull
, because by defaultGameContext
are not networked and have no sense of inventory.getDeckCombinations
(List<String> decks) Creates all the possible combinations of decks given a list of decksgetDeckCombinations
(List<GameDeck> decks, boolean includeMirrors) Gets theDeckFormat
of this context, or the currently legal cards in terms ofCardSet
objects.Gets all the entities in the game, aside from hidden ones, as aStream
.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.Retrieves the stack of event sources.Gets the current event target stack.int
boolean
When true, the game logic doesn't handle an events being raised.int
Gets the value of the named integer in the context's cloneable storage.getLastCardPlayed
(int playerId) getLastCardPlayedBeforeCurrentSequence
(int playerId) getLeftMinions
(EntityReference minionReference) Gets the minions to the left on the battlefield of the given minion.org.slf4j.Logger
getLogic()
Gets a reference to the game logic associated with this context.The number of milliseconds remaining until the active player is automatically changed.int
getMinionCount
(Player player) Gets the number of minions a player has.protected Player
int
getOpponent
(Player player) Gets the opponent from the point of view of the given player.getOppositeMinions
(EntityReference minionReference) Gets theActor
entities geometrically opposite of the givenminionReference
on theSpellsource.ZonesMessage.Zones.BATTLEFIELD
.Gets the current output card.getPlayer
(int index) Gets the player at the given index.Gets the first player.Gets the second player.Each player holds the player'sAbstractBehaviour
and all of theEntity
objects in the game.getRightMinions
(EntityReference minionReference) Gets minions geometrically right of the givenminionReference
on theSpellsource.ZonesMessage.Zones.BATTLEFIELD
that belongs to the specified player.io.opentracing.SpanContext
Provides context for tracing in this context.Returns the spell values calculated so far byMetaSpell
spells.Gets the minions whose summoning is currently being processed.@Nullable Entity
getTargetOverride
(@NotNull Player player, @Nullable Entity source) Retrieves the current target override specified in the environment.int
Gets the total number of minions on both player'sSpellsource.ZonesMessage.Zones.BATTLEFIELD
.getTrace()
Retrieves a trace of this game's actions.Retrieves the stack of hosts of the currently firing trigger.int
getTurn()
Gets the current turn.Gets the currentTurnState
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.int
Gets the winning player's ID or-1
if no player is the winner.<E extends Entity>
EntityZone<E>getZone
(int owner, com.hiddenswitch.spellsource.rpc.Spellsource.ZonesMessage.Zones zone) Retrieves anEntityZone
for the provided owner and zone.boolean
hasPlayer
(int id) void
init()
Initializes a game.void
init
(int startingPlayerId) Initialized the game with the specified starting player.boolean
protected void
void
onDidPerformGameAction
(int playerId, GameAction action) void
onEnchantmentFired
(Enchantment enchantment) Raised when aEnchantment
is fired (i.e., a secret is about to be played or a special effect hosted by a minion/weapon is about to happen).void
void
void
onWillPerformGameAction
(int playerId, GameAction action) void
performAction
(int playerId, GameAction gameAction) Executes the specified game action, typically by callingGameLogic.performGameAction(int, GameAction)
.void
play()
Plays the game.void
play
(boolean fork) int
Removes the specified integer from the context's cloneable storage.<T extends Entity>
TresolveSingleTarget
(Player player, Entity source, EntityReference target) Resolves a single target that could be aEntityReference.isTargetGroup()
that points to exactly one entity, likeEntityReference.FRIENDLY_HERO
.resolveSingleTarget
(EntityReference targetKey) Tries to find the entity references by theEntityReference
.resolveSingleTarget
(EntityReference targetKey, boolean rejectRemovedFromPlay) Resolves a single target given the specification, even if the specification is aEntityReference.isTargetGroup()
resolveTarget
(Player player, Entity source, EntityReference targetKey) InterpretsEntityReference
that specifies a group ofEntity
objects, likeEntityReference.ALL_MINIONS
.void
resume()
Resumes a game, playing it to completion.setActionStack
(Deque<GameAction> actionStack) void
setActionsThisTurn
(int actionsThisTurn) void
setActivePlayerId
(int id) void
setBehaviour
(int i, Behaviour behaviour) void
setBehaviours
(Behaviour[] behaviours) void
Sets the specified player's deck and hero (by implication)setDeckFormat
(DeckFormat deckFormat) void
setEnvironment
(Map<Environment, Object> environment) void
setGameState
(GameState state) void
setIgnoreEvents
(boolean ignoreEvents) void
setLastCardPlayed
(int playerId, EntityReference cardReference) void
setLastCardPlayedBeforeCurrentSequence
(int playerId, EntityReference cardReference) void
setLastSpellPlayedThisTurn
(int playerId, EntityReference cardReference) void
setLogger
(org.slf4j.Logger logger) void
setOtherTriggers
(List<Trigger> otherTriggers) void
setPlayer1
(Player player1) void
setPlayer2
(Player player2) setSpanContext
(io.opentracing.SpanContext spanContext) void
setStatus
(GameStatus result) void
setTargetLogic
(TargetLogic targetLogic) void
setTargetOverride
(EntityReference reference) void
setTempCards
(CardList tempCards) protected GameContext
protected void
void
setTurn
(int turn) void
setTurnState
(TurnState turnState) void
static SimulationResult
simulate
(List<GameDeck> decks, Supplier<Behaviour> player1, Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, boolean includeMirrors) Runs a simulation of the decks with the specified AIs.static SimulationResult
simulate
(List<GameDeck> decks, Supplier<Behaviour> player1, Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, boolean includeMirrors, AtomicInteger matchCounter, Consumer<GameContext> mutateConstructedGameContext, Consumer<GameContext> afterGameContextInit) Runs a simulation of the decks with the specified AIs.static SimulationResult
simulate
(List<GameDeck> decks, Supplier<Behaviour> player1, Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, AtomicInteger matchCounter) Runs a simulation of the decks with the specified AIs.static void
simulate
(List<GameDeck> deckPair, List<Supplier<Behaviour>> behaviours, int gamesPerMatchup, boolean reduce, Consumer<SimulationResult> computed) A generator of simulation results.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.protected void
Fire the start game events here insteadprotected void
Ensures that the game state is traced / recordedvoid
startTurn
(int playerId) Starts the turn for a player.boolean
Requests an action from a player and takes it in the turn.toString()
protected void
traceMulligans
(List<Card> mulligansActive, List<Card> mulligansNonActive) @Nullable Entity
tryFind
(EntityReference targetKey) Tries to find an entity given the reference.@Nullable Entity
tryFind
(EntityReference targetKey, boolean rejectRemovedFromPlay) Tries to find an entity given the reference.boolean
Determines whether the game is over (decided).
-
Field Details
-
PLAYER_1
public static final int PLAYER_1- See Also:
-
PLAYER_2
public static final int PLAYER_2- See Also:
-
spanContext
protected transient io.opentracing.SpanContext spanContext
-
-
Constructor Details
-
GameContext
public GameContext()Creates a game context with two empty players and twoPlayRandomBehaviour
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
Creates a game context from another context by copying it.- Parameters:
fromContext
- The other context to copy.
-
GameContext
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
Creates a game context from a trace.- Parameters:
trace
-- Returns:
-
addTempCard
Adds a temporary card. A temporary card is a card that exists only in this instance and not in theCardCatalogue
.- Parameters:
card
- The card to add, typically made with code.
-
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.
-
close
protected void close()Clears state to ensure this context isn't referencing it anymore. -
endGame
protected void endGame()Ends the game immediately. -
notifyPlayersGameOver
protected void notifyPlayersGameOver() -
calculateStatistics
protected void calculateStatistics() -
endTurn
public void endTurn()Ends the current player's turn immediately, setting the active player to their opponent. -
updateAndGetGameOver
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
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
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
Gets a card by ID, checking both the catalogue and the cards ingetTempCards()
.- Parameters:
cardId
- The string card ID.- Returns:
- A clone of the
Card
.
-
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
Gets theDeckFormat
of this context, or the currently legal cards in terms ofCardSet
objects.- Returns:
- A
DeckFormat
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:
-
getOutputCard
Gets the current output card.- Returns:
- The event card.
- See Also:
-
getEventTargetStack
Gets the current event target stack.- Returns:
- A stack of targets.
- See Also:
-
getLeftMinions
Gets the minions to the left on the battlefield of the given minion.- Parameters:
minionReference
- AnEntityReference
pointing to the minion.- Returns:
- A list of entities to the left of the provided minion.
-
getLogic
Gets a reference to the game logic associated with this context. -
getMinionCount
Gets the number of minions a player has.- Parameters:
player
- The player to query.- Returns:
- The count of minions.
-
getOpponent
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
Gets theActor
entities geometrically opposite of the givenminionReference
on theSpellsource.ZonesMessage.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 byminionReference
.
-
getPlayer
Gets the player at the given index. -
hasPlayer
public boolean hasPlayer(int id) -
getPlayer1
Gets the first player.- Returns:
- A player object.
-
getPlayer2
Gets the second player.- Returns:
- A player object.
-
getPlayers
Each player holds the player'sAbstractBehaviour
and all of theEntity
objects in the game.- Returns:
- A read only list of
Player
objects.
-
getBehaviours
-
getRightMinions
Gets minions geometrically right of the givenminionReference
on theSpellsource.ZonesMessage.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 theminionReference
.
-
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'sSpellsource.ZonesMessage.Zones.BATTLEFIELD
.- Returns:
- A total.
-
getTurn
public int getTurn()Gets the current turn.- Returns:
- The turn. 0 is the first turn.
-
getTurnState
Gets the currentTurnState
- Returns:
- The turn state of this context.
-
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
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
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
-
startTrace
protected void startTrace()Ensures that the game state is traced / recorded -
performAction
Executes the specified game action, typically by callingGameLogic.performGameAction(int, GameAction)
.- Parameters:
playerId
- The player who's performing the action.gameAction
- The action to perform.- See Also:
-
play
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 theGameLogic
, which executes the effects of that action until the next action needs to be requested.- See Also:
-
play
public void play(boolean fork) -
takeActionInTurn
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 callsperformAction(int, GameAction)
with the returnedGameAction
.- Returns:
false
if the player selected anEndTurnAction
, indicating the player would like to end their turn.
-
resolveSingleTarget
Tries to find the entity references by theEntityReference
.- Parameters:
targetKey
- The reference to find.- Returns:
- The
Entity
pointed to by theEntityReference
, ornull
if the provided entity reference wasnull
orEntityReference.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 aEntityReference.isTargetGroup()
- Parameters:
targetKey
-rejectRemovedFromPlay
-- Returns:
- Throws:
TargetNotFoundException
-
resolveTarget
InterpretsEntityReference
that specifies a group ofEntity
objects, likeEntityReference.ALL_MINIONS
.- Parameters:
player
- The player from whose point of view this method interprets theEntityReference
.source
- The entity from whose point of view this method interprets theEntityReference
.targetKey
- TheEntityReference
.- Returns:
- A potentially empty list of entities.
- See Also:
-
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
ornull
if no override is specified.
-
startGame
protected void startGame()Fire the start game events here instead -
getNonActivePlayerId
public int getNonActivePlayerId() -
startTurn
public void startTurn(int playerId) Starts the turn for a player.- Parameters:
playerId
- The player whose turn should be started.
-
toString
-
tryFind
Tries to find an entity given the reference.- Parameters:
targetKey
- The reference to the entity.- Returns:
- The found
Entity
, ornull
if no entity was found.
-
tryFind
Tries to find an entity given the reference.- Parameters:
targetKey
- The reference to the entity.rejectRemovedFromPlay
-- Returns:
- The found
Entity
, ornull
if no entity was found.
-
setLogic
-
setDeckFormat
-
setEnvironment
-
getWinner
-
setWinner
-
getStatus
-
setStatus
-
setTurnState
-
setTurn
public void setTurn(int turn) -
getActionsThisTurn
public int getActionsThisTurn() -
setActionsThisTurn
public void setActionsThisTurn(int actionsThisTurn) -
setPlayer1
-
setPlayer2
-
setPlayer
-
setActivePlayerId
public void setActivePlayerId(int id) -
getTargetLogic
-
setTargetLogic
-
getTempCards
-
setTempCards
-
isDisposed
public boolean isDisposed() -
getGameId
-
getEntities
Gets all the entities in the game, aside from hidden ones, as aStream
.- Returns:
- The
Stream
of game entities.
-
onWillPerformGameAction
-
onDidPerformGameAction
-
getGameState
-
getGameStateCopy
-
concede
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
Raised when aEnchantment
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
Returns the spell values calculated so far byMetaSpell
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
-
getSpellTargetStack
-
getOutputStack
-
getAttackerReferenceStack
-
getLastCardPlayedMap
-
setLastCardPlayed
-
getLastCardPlayedBeforeCurrentSequenceMap
-
setLastCardPlayedBeforeCurrentSequence
-
getLastCardPlayed
-
getLastCardPlayed
-
getLastSpellPlayedThisTurnMap
-
setLastSpellPlayedThisTurn
-
getLastCardPlayedBeforeCurrentSequence
-
getLastCardPlayedBeforeCurrentSequence
-
getAftermaths
-
getNonActivePlayer
-
resume
public void resume()Resumes a game, playing it to completion.Useful for implementing Monte Carlo Tree Search AI algorithms.
-
getEventSourceStack
Retrieves the stack of event sources.- Returns:
- A stack of event source
EntityReference
objects.
-
simulate
public static SimulationResult simulate(List<GameDeck> decks, Supplier<Behaviour> player1, Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, 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
- ASupplier
(function which returns a new instance) of aBehaviour
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
- ASupplier
(function which returns a new instance) of aBehaviour
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 withsimulationCount(int, int, boolean)
.useJavaParallel
- Whentrue
, uses the Java Streams Parallel interface to parallelize this computation on this JVM instance.matchCounter
- When notnull
, 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(List<GameDeck> decks, Supplier<Behaviour> player1, 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 ifincludeMirrors
istrue
, otherwise at least two.player1
- ASupplier
(function which returns a new instance) of aBehaviour
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
- ASupplier
(function which returns a new instance) of aBehaviour
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 withsimulationCount(int, int, boolean)
.useJavaParallel
- Whentrue
, uses the Java Streams Parallel interface to parallelize this computation on this JVM instance.includeMirrors
- Whentrue
, includes mirror matchups for each deck.
-
simulate
public static SimulationResult simulate(List<GameDeck> decks, Supplier<Behaviour> player1, Supplier<Behaviour> player2, int gamesPerMatchup, boolean useJavaParallel, boolean includeMirrors, AtomicInteger matchCounter, Consumer<GameContext> mutateConstructedGameContext, 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
- ASupplier
(function which returns a new instance) of aBehaviour
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
- ASupplier
(function which returns a new instance) of aBehaviour
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 withsimulationCount(int, int, boolean)
.useJavaParallel
- Whentrue
, uses the Java Streams Parallel interface to parallelize this computation on this JVM instance.includeMirrors
- Whentrue
, includes mirror matchupsmatchCounter
- When notnull
, the simulator will increment this counter each time a match ismutateConstructedGameContext
- A handler that can modify the game context for customization after it was initialized with the specified decks but before mulligans. For example, theGameLogic.getSeed()
canafterGameContextInit
- 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(List<GameDeck> deckPair, List<Supplier<Behaviour>> behaviours, int gamesPerMatchup, boolean reduce, Consumer<SimulationResult> computed) throws 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, usesPlayRandomBehaviour
.gamesPerMatchup
- The number of games to play per matchup.reduce
- Whentrue
, merges matches that have the same behaviour and decks.computed
- The callback that will be fed a simulation result whenever it is computed.- Throws:
InterruptedException
-
fromDecks
public static GameContext fromDecks(List<GameDeck> decks, Behaviour behaviour1, Behaviour behaviour2) Gets a game context that's ready to play from twoGameDeck
objects.- Parameters:
decks
- TheGameDeck
s to use for the players.- Returns:
- A
GameContext
for whichplay()
will immediately work. - See Also:
-
fromDecks
Gets a game context that's ready to play from twoGameDeck
objects. Uses thePlayRandomBehaviour
for both players.- Parameters:
decks
- TheGameDeck
s to use for the players.- Returns:
- A
GameContext
for whichplay()
will immediately work. - See Also:
-
fromDeckLists
Gets a game context that's ready to play from two deck lists encoded in the standard community format. Uses thePlayRandomBehaviour
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:
-
fromDeckLists
public static GameContext fromDeckLists(List<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 ofBehaviour
for player 1behaviour2
- An implementation ofBehaviour
for player 2- Returns:
- A game context
-
fromTwoRandomDecks
Creates a new game context with two random decks and random play behaviour.- Returns:
- A game context
- See Also:
-
fromTwoRandomDecks
-
fromDecks
-
fromTwoRandomDecks
Creates a game with two random decks in the specified format.- Parameters:
format
-- Returns:
-
getDeckCombinations
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
-
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
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
Returnsnull
, because by defaultGameContext
are not networked and have no sense of inventory. -
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
-
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 aEntityReference.isTargetGroup()
that points to exactly one entity, likeEntityReference.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.
-
setBehaviours
-
setBehaviour
-
didCallEndGame
protected boolean didCallEndGame() -
getThread
-
setThread
-
setDeck
Sets the specified player's deck and hero (by implication)- Parameters:
playerId
-deck
-
-
compareTo
Returns0
if the two game contexts have the same meaningful game state.Otherwise, returns
1
ifother
is "further along"- Specified by:
compareTo
in interfaceComparable<GameContext>
- Parameters:
other
-- Returns:
-
setTrace
-
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
-
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
Creates an integer value in the context's cloneable storage.- Parameters:
name
-initialValue
-
-
addAndGetInt
Adds the delta value and returns the new value of the named integer from the context's cloneable storage.- Parameters:
name
-delta
-- Returns:
-
getInt
Gets the value of the named integer in the context's cloneable storage.- Parameters:
name
-- Returns:
-
removeInt
Removes the specified integer from the context's cloneable storage.- Parameters:
name
-- Returns:
-
setOtherTriggers
-
getTriggers
-
getDeferredTriggersQueue
-
getProcessingTriggers
-
getActionStack
-
setActionStack
-
getCurrentAction
-
onNotificationWillFire
-
onNotificationDidFire
-