Overview
Every simulation follows a deterministic lifecycle. Thecreate_books() function orchestrates the full batch: it assigns distribution criteria to simulation numbers, then calls run_spin() once per simulation. Each simulation writes its events to the books file and its payout multiplier to the lookup table.
1
Assign criteria to simulation numbers
Before any simulations run,
create_books() reads the BetMode distributions defined in GameConfig and pre-assigns a criteria label (e.g. basegame, freegame, winCap, 0) to each simulation number according to the configured quotas. This is done once per bet mode.2
Seed the RNG
run_spin() calls self.reset_seed(sim), which sets Python’s random seed to sim + 1. Because the seed is derived from the simulation number, every simulation is fully reproducible — re-running simulation 58 will always produce identical results.3
Enter the repeat loop
self.repeat is set to True at the start of run_spin(). The loop continues until the spin satisfies the distribution criteria assigned to this simulation number. Each iteration calls self.reset_book(), which resets all local simulation variables and sets self.repeat = False. If the final result does not meet the criteria, self.check_repeat() sets self.repeat = True again and the loop retries.4
Run the spin
Inside the loop, the three core phases execute: calculate the board state, update the wallet manager, and emit events. If a freespin trigger condition is met,
run_freespin() is called before the final win is evaluated.5
Verify distribution criteria
self.check_repeat() inspects the final payout against any win_criteria defined for this simulation’s assigned distribution, and checks whether a freespin was triggered if force_freegame is set. If either check fails, self.repeat is set back to True.6
Imprint wins
Once
self.repeat remains False after check_repeat(), self.imprint_wins() saves the simulation result: the events are added to the in-memory library, the payout multiplier is recorded, and cumulative win totals are updated for runtime RTP reporting.RNG seeding
Each simulation is seeded with its own simulation number to ensure reproducibility:num_sim_args will produce identical books files. It also makes it straightforward to reproduce any specific result for debugging.
The repeat loop
The repeat mechanism ensures that pre-assigned distribution criteria are honoured. The loop works as follows:run_spin()setsself.repeat = Truebefore the loop begins.reset_book()setsself.repeat = Falseat the start of each iteration, resetting all simulation state.- At the end of the spin,
check_repeat()re-evaluates whether the result satisfies the assigned criteria. If not, it setsself.repeat = Trueand the loop retries with a fresh board.
The run_spin() flow
- Calculate board state — draw symbols from reel strips, evaluate win combinations, determine any special symbol actions.
- Update wallet manager — call
win_manager.update_spinwin()with the current spin win, andwin_manager.update_gametype_wins()once all basegame actions are complete. - Emit events — append JSON event objects to
self.bookfor each state change (board reveal, win info, win counter updates, freespin trigger, etc.).
The run_freespin() flow
run_spin(). The tot_fs counter may be increased by retriggers during the loop. win_manager.update_gametype_wins() is called at the end of each individual freespin so that basegame and freegame win contributions are tracked separately.
Simulation output
At the end of a successful simulation (afterself.repeat remains False), two outputs are written:
- Books — the complete list of events for this simulation is stored in
self.library[sim + 1]. When all simulations in a batch are complete, the library is written tolibrary/books/orlibrary/books_compressed/as a JSONL file. - Lookup table — the
payoutMultiplierfor this simulation is appended to the lookup table CSV with an initial weight of1.
imprint_wins()
imprint_wins() is the final step in every simulation. It:
- Processes all
self.record()calls made during the spin into therecorded_eventsdictionary (used for force files and PAR sheet generation). - Saves the completed book to
self.library. - Appends the payout multiplier to the internal payout list.
- Calls
win_manager.update_end_round_wins()to accumulate running RTP totals printed to the terminal as threads finish.
