Methodology
How We Validated Our Pokémon Pack Simulation Using Expected Value
The simulator looked plausible, but plausible was not enough. Expected Value gave me a result it should reproduce under the same assumptions.
The simulator looked believable, but that was not a test. I wanted a reference point that did not depend on random sampling.
If the direct calculation and the simulator read the same pack model and card values, they should reach the same long-run average by different routes. If they do not, something is wrong.

Analytical EV and simulated EV
Analytical Expected Value is the sum of each outcome value multiplied by its probability, matching the discrete-distribution definition summarized by OpenStax. In compact form:
Simulated EV is simpler to describe. Run the modeled opening repeatedly using a Monte Carlo approach of the kind introduced by Metropolis and Ulam, add every simulated pack value, and divide by the number of openings. Under the shared model assumptions, that sample mean should converge toward the analytical EV as the run grows.
The production result stores both values separately: calculated_expected_value_per_pack for the analytical path and the simulation mean for the Monte Carlo path. Keeping both is useful because one is not copied from the other.
What I actually test
The repository tests the simulation at several levels. Pack-state tests check that probabilities normalize, every state has the required slots, pool tokens resolve, and impossible combinations are rejected. Sampling-integrity tests exercise rarity and state frequencies. Runner tests verify that analytical EV and simulated mean remain distinct published metrics.
There are also targeted regression tests for sets whose pack structures need special handling, including pattern-card exclusions, overlapping pools, god packs, and set-specific state overrides. Those tests are more useful than one universal assertion because a simulator can be correct for a plain pack and wrong for a special one.
I am deliberately not publishing a made-up convergence percentage here. The repository defines the methods and test contracts, but it does not contain a current, public, set-by-set validation table with a calculation date that I can responsibly quote as a universal result.
What matching EV tells me
If the simulated mean settles near the analytical EV under the same input model, that increases confidence that the simulation is sampling the intended probabilities and assigning values consistently. A large persistent gap is a useful alarm. It usually means the calculation and simulation disagree about a pool, a slot, a probability, or which card value applies.
What it does not tell me
Two distributions can have the same mean and completely different medians, break-even rates, and tails. So matching EV does not prove P50, P95, P99, or the top 1% composition is correct. That is why the repository also tests pack states, special paths, pool membership, no-overlap rules, and sampling behavior directly.
It also cannot validate the real-world pull-rate assumption. Analytical EV and simulated EV can agree perfectly while both consume the same wrong probability. This check validates implementation consistency inside the model. It does not turn the model into an official description of Pokémon production.
References
These references support the Expected Value definition and general Monte Carlo method. They do not validate inDex’s Pokémon-specific inputs; the analytical-versus-simulated comparison tests internal model consistency only.
- OpenStax. Introductory Statistics 2e. Chapter 4: Key Terms. Defines expected value as the long-run arithmetic average and gives the discrete probability-distribution formula.
- Metropolis, N. & Ulam, S. (1949). “The Monte Carlo Method.” Journal of the American Statistical Association, 44(247), 335–341. Supports the general Monte Carlo sampling method.
