Data-driven configuration
Reel strips, paylines, payout values, and bonus awards are loaded from JSON so game balance can change without rewriting the evaluation logic.
C++ collaboration ยท Primary implementation
A data-driven slot machine with five reels, 25 paylines, free spins, deterministic tests, and an SDL3 interface.

In motion
Recorded from the working SDL3 client. The video is presented in full, with selected frames used to make the game readable at a glance.

Overview
This five-reel slot machine is one part of the larger Monte Carlo Platform, developed as a two-person C++ collaboration. It combines a standalone game model with a graphical SDL3 client and shared platform services.
The game builds a three-row screen from five reel strips, evaluates up to 25 paylines, handles wild and scatter symbols, awards free spins, and reports the complete round result including total bet, payout, and net result.
Role
I was the primary programmer for the slot-machine game. I implemented most of the slot-specific code, including the reel and screen model, payline evaluation, paytable loading, free-spin round flow, graphical client, command-line simulator, and automated tests.
The wider platform was collaborative. My slot code needed to fit into shared conventions for requests, responses, randomness, money, and service integration, so I also gained experience building a focused game module inside a larger C++ system.
Design focus
Reel strips, paylines, payout values, and bonus awards are loaded from JSON so game balance can change without rewriting the evaluation logic.
The engine supports fixed reel stops as well as generated results, making winning lines, scatter awards, and edge cases reproducible in tests.
Screen construction, evaluation, round orchestration, data loading, and presentation are kept in separate types with focused responsibilities.
Implementation
Built the reel strips, three-by-five screen, symbols, paylines, paytable, winning-line data, and spin request and response types.
Implemented left-to-right line matching with wild substitutions, scatter counting, payout calculation, and bonus triggering.
Created the base-spin and free-spin orchestration, including payout accumulation, retrigger handling, safety limits, and final round totals.
Developed the SDL3 presentation, a command-line simulator, and deterministic unit tests for slot behaviour and edge cases.
Process
JSON files define reel contents, 25 payline paths, symbol payouts, and free-spin awards. Dedicated loader classes validate and translate that data into the core model.
The normal spin path requests reel stops from the random-result generator, while spinWithStops accepts known values. Both paths use the same screen builder and evaluator.
The round runner tracks pending bonus spins with overflow protection and a maximum-spin cap, while keeping bonus payouts separate from the base bet.
Code samples
Excerpts from systems I contributed to during the project, lightly trimmed for a focused portfolio presentation.
Finds the first non-wild symbol and counts a left-to-right run while allowing wild symbols to substitute.
Symbol SlotEvaluator::determineBaseSymbol(
const std::array<Symbol, 5>& symbols)
{
for (Symbol symbol : symbols)
if (symbol != Symbol::Wild)
return symbol;
return Symbol::Wild;
}
int SlotEvaluator::countMatchesFromLeft(
const std::array<Symbol, 5>& symbols,
Symbol base)
{
int count = 0;
for (Symbol current : symbols) {
if (current == base || current == Symbol::Wild)
++count;
else
break;
}
return count;
}Builds the visible screen from explicit reel stops and sends it through the same evaluator used by generated spins.
SlotScreen screen =
SlotScreenBuilder::buildScreen(reels_, reelStops);
SlotResult result = SlotEvaluator::evaluate(
screen,
paylines_,
paytable_,
reelStops,
request.betPerLine,
request.activeLines,
freeSpinAwards_
);
response.accepted = true;
response.message = "Spin completed.";
response.result = result;Consumes awarded spins, accumulates payouts, records blocked retriggers, and stops safely if the configured round cap is reached.
while (pendingFreeSpins > 0 &&
freeSpinsPlayed < maxFreeSpinsPerRound_) {
--pendingFreeSpins;
++freeSpinsPlayed;
SlotSpinResponse spin =
engine_.spin(freeSpinRequest, SpinMode::FreeSpin);
if (spin.accepted) {
round.totalPayout += spin.result.totalPayout;
if (spin.result.scatterCount >= 3)
++round.blockedRetriggers;
}
round.freeSpins.push_back(spin);
}Reflection
Slot rules look simple from the outside, but combinations of wilds, scatters, active lines, bet multipliers, and bonus spins create many edge cases. Keeping those rules deterministic and testable was a central challenge.
The graphical client also had to present results clearly without mixing rendering concerns into the core payout logic.
Learning
I learned to separate random result generation from deterministic game evaluation, which makes both testing and future service integration much easier.
This project also strengthened my C++ design, JSON configuration, SDL3 interface work, and ability to turn game rules into small cooperating types.
Next steps
I would add statistical simulation reports for return-to-player analysis, expand the automated test matrix, and refine the SDL3 animation and feedback.
Explore