> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/StakeEngine/math-sdk/llms.txt
> Use this file to discover all available pages before exploring further.

# Utilities

> General-purpose helper functions for randomness, game analysis, file verification, and lookup table management.

## `get_random_outcome()`

```python theme={null}
from src.calculations.statistics import get_random_outcome

get_random_outcome(
    distribution: dict,
    totalWeight: float = None,
) -> float | int
```

The primary randomness function used throughout the SDK. Performs a weighted random draw from a dictionary mapping outcomes to weights.

<ParamField path="distribution" type="dict" required>
  A dictionary of `{outcome: weight}` pairs. Weights can be any positive numeric values — they do not need to sum to 1.

  ```python theme={null}
  {"low": 70, "mid": 25, "high": 5}
  ```
</ParamField>

<ParamField path="totalWeight" type="float" default="None">
  Pre-computed sum of all weights. Pass this to avoid recomputing it on every call in tight loops. If `None`, the sum is computed internally.
</ParamField>

**Returns** one outcome key from the distribution, selected with probability proportional to its weight.

### Usage examples

```python theme={null}
# Draw a multiplier value from a game-mode-specific distribution
multiplier = get_random_outcome(
    self.config.multiplier_values[self.gametype]
)

# Select a reelstrip ID from weighted reelsets
reelstrip_id = get_random_outcome(
    self.get_current_distribution_conditions()["reel_weights"][self.gametype]
)

# Draw number of free spins to award
num_spins = get_random_outcome({10: 50, 15: 30, 20: 15, 25: 5})
```

<Note>
  `get_random_outcome()` uses `random.uniform` internally. For reproducible results in testing, seed Python's random module before calling it: `random.seed(42)`.
</Note>

## Statistical helpers

### `get_mean_std_median(dist)`

```python theme={null}
from src.calculations.statistics import get_mean_std_median

get_mean_std_median(dist: dict) -> tuple[float, float, float]
```

Computes descriptive statistics from an ordered win-distribution dictionary.

<ParamField path="dist" type="dict" required>
  A `{win_value: count}` dictionary representing a win distribution (e.g. from a lookup table).
</ParamField>

**Returns** `(mean, std_dev, median)` as a tuple of floats.

### `normalize(distribution)`

```python theme={null}
from src.calculations.statistics import normalize

normalize(distribution: dict) -> None
```

Normalizes all weight values in a distribution in-place so they sum to `1.0`. Modifies the dictionary directly.

## PAR sheet generation — `run_analysis.py`

The `run()` function in `run_analysis.py` generates a `.xlsx` PAR sheet from an optimized lookup table.

```python theme={null}
run(
    lookup_table,         # Optimized win distribution dict
    force_records,        # Force record JSON data
    paytable,             # config.paytable
    custom_search_keys,   # Optional list of additional record keys to analyze
)
```

<ParamField path="lookup_table" type="dict" required>
  An optimized lookup table as generated by the optimization algorithm. Expected format matches the segmented lookup table structure.
</ParamField>

<ParamField path="force_records" type="dict" required>
  Contents of `force_record_<mode>.json`. Each entry must include at minimum `"symbol"` and `"kind"` keys.

  ```json theme={null}
  [
    {"kind": 5, "symbol": "H1", "mult": 1, "gametype": "basegame"},
    {"kind": 3, "symbol": "W",  "mult": 2, "gametype": "basegame"}
  ]
  ```
</ParamField>

<ParamField path="paytable" type="dict" required>
  `config.paytable` dict. Valid symbol names are extracted from this to filter analysis.
</ParamField>

<ParamField path="custom_search_keys" type="list" default="[]">
  Additional `gamestate.record()` keys to include in the analysis output. Allows hit-rate reporting for custom events beyond symbol wins.
</ParamField>

The output `.xlsx` file contains:

* Hit-rates per win range, split by gametype
* RTP contribution per win range
* Simulation counts per win range
* Average payout multiplier per win range

## Swap lookups

The optimization algorithm outputs multiple candidate lookup tables under `<game>/library/optimization_files/`. The swap\_lookups utility provides functions to copy weights from a candidate file into the active `lookUpTable_<mode>_0.csv` file.

```python theme={null}
# Swap in a specific optimization candidate
swap_lookups(source_file="optimization_files/candidate_3.csv", target_mode="basegame")
```

This allows switching between optimization variants without manually editing the lookup table.

## File integrity verification

### `get_file_hash(filepath)`

Prints the SHA-256 hash of a single file to the console. Used to verify a file's contents match the value recorded in `config.json`.

```python theme={null}
get_file_hash("library/lookup_tables/lookUpTable_basegame_0.csv")
# Output: sha256: e3b0c44298fc1c149afb...
```

### Directory hash

A companion function prints SHA-256 hashes for all non-Python files within a specified directory. Use this to verify the integrity of an entire game library folder against recorded hash values in `config.json`.

```python theme={null}
get_directory_hash("library/")
# Output:
# reels/base_reels.csv : sha256: a1b2c3...
# lookup_tables/lookUpTable_basegame_0.csv : sha256: d4e5f6...
```

<Tip>
  Run file hash verification before and after any game file deployment to confirm that reelstrips, lookup tables, and configuration files have not been altered.
</Tip>
