01 · Problem
What is it for?
Reel sampling, win detection, credits and terminal interaction must be independently testable.
02 · Mental model
How should you think about it?
The engine consumes a wager and random values, produces a grid, evaluates paylines and returns a state transition.
Simulates weighted reels, horizontal and diagonal payouts, credits and free spins. The engine is an educational deterministic simulation. UI, real-money accounting and regulatory requirements are outside its contract.
03 · Control flow
What happens in which order?
- Validate wager and available credits.
- Sample each reel from normalized weights.
- Build a row-by-column grid.
- Evaluate horizontal paylines and special symbols.
- Apply payout and free-spin transitions.
04 · Building blocks
The important contracts
FruitSlotMachine.betAndSpinApply wagers, paylines and free-spin state.Reel / FruitReelSample weighted symbols using injectable randomness.getCredit / getFreeSpinsRead explicit simulation state.05 · Build it yourself
Implement a small core
Start with this small independent implementation, then use the steps below to make its contract explicit.
- Validate wager and available credits.
- Sample each reel from normalized weights.
- Build a row-by-column grid.
- Evaluate horizontal paylines and special symbols.
- Apply payout and free-spin transitions.
type Weighted<T> = { value: T; weight: number };
function pick<T>(items: Weighted<T>[], random: () => number) {
const total = items.reduce((sum, item) => sum + item.weight, 0);
let cursor = random() * total;
for (const item of items) {
cursor -= item.weight;
if (cursor < 0) return item.value;
}
throw new Error("No selectable symbol");
}
const middleLine = [[0, 1], [1, 1], [2, 1]] as const;06 · Verify
What should you test?
- Inject randomness for known reel results.
- Check horizontal lines across reels.
- Reject invalid wagers and verify credits never become negative.
Try it yourself
Turn the first verification claim into a failing test, implement the smallest fix, then add a boundary case.
Inject randomness for known reel results.
Compare your approach
Your check should fail when the stated invariant is deliberately broken, and pass again after the fix. Keep setup deterministic and assert an observable result.
07 · Limits
Trade-offs and failure modes
- A simulation is not a real-money gambling system.
- Keep rendering and input adapters separate.
- The existing package slug remains unchanged.
The engine is an educational deterministic simulation. UI, real-money accounting and regulatory requirements are outside its contract.
08 · Keep exploring
Source code and related ideas
yarn tsx packages/slot-mashine/examples/basic.ts