Standard Game Setup Requirements
Without diving into specific functions, this section is intended to walkthrough how a new slot game would generally be setup. In practice it is recommended to start with one of the sample games which closest resemble the game being made, or otherwise starting from the template.
Configuration file
Game parameters should all be set in the GameConfig
__init__()
function. This is where to set the name name, RTP, board dimensions, payouts, reels and various special symbol actions. All required fields are listed in the Config
class and should be filed out explicitly for each new game.
Next the BetMode
classes are defined. Generally there would be at a minimum a (default) base
game and a freegame
, which is usually purchased.
class GameConfig(Config):
def __init__(self):
super().__init__()
self.game_id = ""
self.provider_number = 0
self.working_name = ""
self.wincap = 0
self.win_type = "lines"
self.rtp = 0
self.num_reels = 0
self.num_rows = [0] * self.num_reels
self.paytable = {
(kind, symbol): payout,
}
self.include_padding = True
self.special_symbols = {"property": ["sym_name"],...}
self.freespin_triggers = {
}
self.reels = {}
self.bet_modes = []
Each BetMode
should likewise be set explicitly, defining the cost, rtp maximum win amounts and various gametype flags. We would like to define different win criteria within each betmode. In the sample games we define distinct criteria for any game-aspects where we would like to control either the hit-rate and/or RTP allocation. In this example we would like to control the basegame hit-rate, max-win hit-rate and freegame hit-rate. Therefore we need to specify unique Distribution
criteria for each of these special conditions. Further information about purpose of Distribution conditions can be found here and here
BetMode(
name="base",
cost=1.0,
rtp=self.rtp,
max_win=self.wincap,
auto_close_disabled=False,
is_feature=True,
is_buybonus=False,
distributions=[
Distribution(
criteria="winCap",
quota=0.001,
win_criteria=self.wincap,
conditions={
"reel_weights": {
self.basegame_type: {"BR0": 1},
self.freegame_type: {"FR0": 1},
},
"force_wincap": True,
"force_freegame": True,
},
),
Distribution(
criteria="freegame",
quota=0.1,
conditions={
"reel_weights": {
self.basegame_type: {"BR0": 1},
self.freegame_type: {"FR0": 1},
},
"force_wincap": False,
"force_freegame": True,
},
),
Distribution(
criteria="0",
quota=0.4,
win_criteria=0.0,
conditions={
"reel_weights": {self.basegame_type: {"BR0": 1}},
},
),
Distribution(
criteria="basegame",
quota=0.5,
conditions={
"reel_weights": {self.basegame_type: {"BR0": 1}},
},
),
],
)
Gamestate file
When any simulation is run, the entry point will be the run_spin()
function, which lives in the GameState
class. GameExecutables
and GameCalculations
are child classes of GameState
and also deal with game specific logic.
The generic structure would follow the format:
def run_spin(self, sim):
self.reset_seed(sim) #seed the RNG with the simulation number
self.repeat = True
while self.repeat:
self.reset_book() #reset local variables
self.draw_board() #rraw board from reelstrips
#evaluate win_data
#update win_manager
#emit relevant events
self.win_manager.update_gametype_wins(self.gametype) #update cumulative basegame wins
if self.check_fs_condition(): #check scatter conditions
self.run_freespin_from_base() #run freegame
self.evaluate_finalwin()
self.check_repeat() #Verify betmode distribution conditions are satisfied
self.imprint_wins() #save simulation result
For reproducibility the RNG is seeded with the simulation number. Betmode distribution criteria are preassigned to each simulation number, requiring the self.repeat
condition to be initially set until the spin has completed and it can be checked that any criteria-specific conditions or win amounts are satisfied. Note that self.repeat = False
is set in the self.reset_book()
function. This function will reset all relevant GameState
properties to default values.
Generally the first steps will be to use the reelstrips provided in the configuration file to draw a board from randomly chosen reelstop positions. Wins are evaluated from one of the provided win-types for the active board, and the wallet manager is updated. After this game-logic is completed the relevant events (such as reveal
and winInfo
) are emitted. All sample games follow these three steps:
1. Calculate current state of the board
2. Update wallet manager
3. Emit events
To keep track of which gametype wins are allocated, the wallet manger is again invoked once all basegame actions are complete. If the game have a freegame mode and the triggering conditions are satisfied the run_freespin()
function is invoked. This mode will have a similar structure:
def run_freespin(self):
self.reset_fs_spin() #reset freegame variables
while self.fs < self.tot_fs: #account for multiple freegame spins
self.update_freespin() #update spin number and emit event
self.draw_board() #draw a new board using freegame reelstrips
#evaluate win_data
#update win_manager
#emit relevant events
if self.check_fs_condition(): #check retrigger conditions
self.update_fs_retrigger_amt()
self.win_manager.update_gametype_wins(self.gametype) #update cumulative freegame win amounts
self.end_freespin() #emit event to indicate end of freegame
While it is possible to perform all game actions within these functions, for clarity functions from GameExecutables
and GameCalculations
are typically invoked and should be created on a game-by-game basis depending on requirements.
Runfile
Finally to produce simulations, the run.py
file is used to create simulation outputs and config files containing game and simulation details.
if __name__ == "__main__":
num_threads = 1
rust_threaeds = 20
batching_size = 50000
compression = False
profiling = False
num_sim_args = {
"base": int(10),
"bonus": int(10),
}
config = GameConfig()
gamestate = GameState(config)
create_books(
gamestate,
config,
num_sim_args,
batching_size,
num_threads,
compression,
profiling,
)
generate_configs(gamestate)
The create_books
function handles the allocation of win criteria to simulation numbers, output file format and multi-threading parameters.
Outputs
Simulation outputs are placed in the game/library/
folder. books/books_compressed
is the primary data-file containing all events and payout multipliers. lookup_tables
hold the summary simulation-payout values in .csv
format which is consumed by the optimization algorithm. Additionally for game analysis, lookup table mapping of which simulations belong to which win criteria and which gametype wins arise from are produced. force/
file outputs contain all information used by the .record()
function, which is again useful for analyzing the frequency and average win amounts for specific events. The optimization algorithm also uses the recorded force
data to identify which simulations correspond to specific win criteria. Finally config/
files contain information required by the frontend such as symbol and betmode information, backend information such as file hash values and a configuration file for the optimization algorithm.
The optimization algorithm consumes the lookup table and outputs a copy of the file, but with modified weights. To assist with setting optimization parameters, there are two other files with the prefix lookUpTableIdToCriteria
and lookUpTableSegmented
. These files are used to identify which bet-mode sub-type that specific simulation number belongs to (such as max-wins, 0-wins, freegame entry etc..), and what gametype (usually basegame or freegame) contributes to the final payout multiplier.