Back to projects

C++ collaboration ยท Primary implementation

Five-Reel Slot Machine

A data-driven slot machine with five reels, 25 paylines, free spins, deterministic tests, and an SDL3 interface.

  • C++20
  • SDL3
  • JSON
  • Testing
  • Game systems
Five-reel slot machine showing a completed winning payline and payout.
RolePrimary Slot Programmer
Team2-person collaboration
LanguageC++20
FocusRules, UI, and testing

In motion

Gameplay and systems

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

Complete slot demonstrationThe full recording shows manual spins, autoplay, paylines, changing stakes, wins, and the live credit balance.
Slot machine screen with a green winning payline and a win of 70 credits.
Winning paylineA completed spin with the evaluated line drawn across the five-reel screen and the payout reported in the interface.

Overview

Project concept

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

What I worked on

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

Core pillars

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.

Deterministic evaluation

The engine supports fixed reel stops as well as generated results, making winning lines, scatter awards, and edge cases reproducible in tests.

Separated responsibilities

Screen construction, evaluation, round orchestration, data loading, and presentation are kept in separate types with focused responsibilities.

Implementation

Technical contributions

Core slot model

Built the reel strips, three-by-five screen, symbols, paylines, paytable, winning-line data, and spin request and response types.

Payout evaluation

Implemented left-to-right line matching with wild substitutions, scatter counting, payout calculation, and bonus triggering.

Round and bonus flow

Created the base-spin and free-spin orchestration, including payout accumulation, retrigger handling, safety limits, and final round totals.

Client and verification

Developed the SDL3 presentation, a command-line simulator, and deterministic unit tests for slot behaviour and edge cases.

Process

Implementation notes

Configuration pipeline

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.

Testable spin path

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.

Free-spin safety

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

Selected C++ systems

Excerpts from systems I contributed to during the project, lightly trimmed for a focused portfolio presentation.

SlotEvaluator.cpp

Wild-aware line matching

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;
}
SlotEngine.cpp

One evaluation path for tests and play

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;
SlotRoundRunner.cpp

Bounded free-spin rounds

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

Challenges

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

What I learned

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

Future iterations

I would add statistical simulation reports for return-to-player analysis, expand the automated test matrix, and refine the SDL3 animation and feedback.