GameState is the central object that runs a single simulation round. It owns the current board, win data, event book, and all per-spin mutable state. Every game you build subclasses GameState (or its parent chain) and implements run_spin() as the simulation entry point.
Class hierarchy
GameState properties
list[list[Symbol]]
The active board after the most recent
draw_board() call. Indexed as board[reel][row]. Each entry is a Symbol object with a .name attribute and any special properties set by assign_special_sym_function.string
Current game phase. Starts as
config.basegame_type (default "basegame") and switches to config.freegame_type (default "freegame") when reset_fs_spin() is called.bool
Controls the simulation retry loop in
run_spin(). Set to True before the loop begins; reset to False by reset_book(). Set back to True by check_repeat() when distribution criteria are not satisfied.dict
Populated by the win evaluation step each spin. Structure:
WinManager
Tracks cumulative, spin, base-game, and free-game win amounts. Updated via
win_manager.update_spinwin() and win_manager.update_gametype_wins().GameConfig
Reference to the
GameConfig instance passed at construction. Read-only during simulation.int
Current free spin index (0-based). Incremented by
update_freespin() at the start of each free spin.int
Total free spins awarded this round (including retriggers). Set by
update_freespin_amount() and incremented by update_fs_retrigger_amt().Book
Stores all events emitted during the current simulation. Passed to
imprint_wins() at the end of the round to persist it in the library.int
Running global multiplier value, starting at
1. Incremented by update_global_mult().bool
Set to
True by evaluate_wincap() when the running win reaches config.wincap. Prevents further win events from being emitted.string
The distribution criteria label assigned to the current simulation number (e.g.
"basegame", "freegame", "winCap"). Assigned by the simulation runner before run_spin() is called.Key methods
reset_seed(sim)
random module with sim + 1. Call this as the first line of run_spin() so that every simulation number is fully reproducible.
reset_book()
Book, zeroes win_data, resets win_manager, sets repeat = False, resets fs, tot_fs, global_multiplier, and wincap_triggered. Call this at the start of each retry loop iteration.
check_repeat()
win_criteria and force_freegame constraints. Sets self.repeat = True if any constraint fails. Call this at the end of the spin loop, after evaluate_finalwin().
imprint_wins()
self.library and flushes temp_wins (recorded events) to self.recorded_events. Call this once after the retry loop exits.
update_final_win()
wincap), splits it into base-game and free-game portions, and writes values onto self.book. Raises AssertionError if base + free game wins do not match the total. Called inside evaluate_finalwin().
record(description)
temp_wins for tracking distributions. Typically called when a free spin trigger or other trackable event occurs:
force/ output files and consumed by the optimization algorithm to identify which simulations belong to which event type.
run_spin() — simulation entry point
run_spin(sim, simulation_seed=None) is an abstract method in GeneralGameState that you must implement in your GameState class. The simulation runner calls it once per simulation number.
gamestate.py
while self.repeat loop is a complete spin attempt. reset_book() resets repeat to False; check_repeat() sets it back to True only if a constraint is violated. The loop continues until the spin satisfies all distribution criteria.
run_freespin()
Also abstract. Implement alongsiderun_spin() for games with free spin features:
gamestate.py
create_books()
src/state/run_sims.py
GameState
Instantiated
GameState object.GameConfig
The game configuration object.
dict
Maps bet mode names to simulation counts:
{"base": 1000000, "bonus": 100000}.int
Number of simulations per thread batch. Typical value:
50000.int
Number of parallel worker processes.
bool
When
True, output books are written as .jsonl.zst (Zstandard compressed). When False, plain .jsonl files are written — useful during development.bool
When
True, runs a single-threaded cProfile pass and generates a flame graph. threads must equal 1 when profiling.num_sim_args values must satisfy n % (threads × batch_size) == 0 when n > batch_size². Set any mode’s value to 0 to skip it during a run.generate_configs()
src/write_data/write_configs.py
Call
generate_configs() once after create_books() completes:
run.py
