Complete bet vocabulary
The model represents the common European roulette bets and maps them to the numbers, odds, and payout rules they cover.
C++ collaboration
A European roulette game with a graphical SDL3 table, multiple bet types, provably fair results, and wallet-backed rounds.

In motion
Recorded from the working SDL3 client. The video shows the complete round loop, while the selected frame highlights the table interaction clearly.

Overview
The roulette game is another part of the Monte Carlo Platform. It models a European wheel and supports inside and outside bets, including straight, split, street, corner, six-line, basket, colour, parity, low and high, dozens, columns, and neighbour-style selections.
The SDL3 client connects table interaction to round logic, result generation, payout calculation, and wallet operations so a bet can move through a complete reserve, play, and settlement cycle.
Role
I contributed to the roulette game and its integration with the wider platform while working closely with my teammate. Some implementation work was completed together and appears under the teammate's source-control history, so I describe this page as a collaborative contribution rather than claiming sole ownership.
My work involved understanding and working with the game flow, wallet connection, testing, and debugging across the client and supporting systems. This gave me practical experience entering a larger C++ codebase and tracing behaviour across module boundaries.
Design focus
The model represents the common European roulette bets and maps them to the numbers, odds, and payout rules they cover.
The client translates pointer positions into table selections so chips, highlighted cells, and underlying bet objects remain synchronized.
Random results, recorded round data, wallet reservations, settlement, and cancellation form one traceable lifecycle.
Implementation
Participated in building and reviewing the roulette flow from placing a bet through displaying and resolving a result.
Worked with the connection between player bets, round state, shared wallet behaviour, and the surrounding C++ platform.
Helped test gameplay paths, investigate integration problems, and verify that user actions produced consistent results.
Learned to follow data across UI, game rules, randomness, persistence, and service boundaries in a larger shared project.
Process
Bet types are represented with number masks and payout rules, allowing the game to evaluate many table selections through a shared calculation path.
The SDL3 interface uses a projected table layout and hit testing to translate screen positions into valid roulette selections.
The system uses cryptographic randomness and stores proof-related data for reproducible verification and high-volume result testing.
Code samples
Selected excerpts from the shared two-person codebase. I worked with these systems during game implementation, integration, testing, and debugging; they are shown to explain the architecture, not to claim sole authorship.
Maps each roulette bet to a compact number mask, allowing inside and outside bets to use the same winner-checking path.
std::array<uint32_t, 2> BetManager::getMaskForBet(
const PackedBet& bet)
{
const uint8_t type = bet.getType();
const uint8_t anchor = bet.getAnchor();
const uint8_t neighbor = bet.getNeighbor();
std::array<uint32_t, 2> mask = { 0, 0 };
switch (static_cast<BetType>(type)) {
case BetType::Red: return M_RED;
case BetType::Black: return M_BLACK;
case BetType::Split:
setBit(anchor, mask);
setBit(neighbor, mask);
return mask;
case BetType::Street:
for (int i = 0; i < 3; ++i)
setBit(anchor + i, mask);
return mask;
default:
return mask;
}
}Checks every active bet against the winning-number mask and returns the original stake together with the profit.
Money BetManager::calculatePayout(uint8_t winningNumber)
{
int64_t totalCents = 0;
const auto winMask = makeWinningMask(winningNumber);
for (const auto& bet : activeBets) {
const auto betMask = getMaskForBet(bet);
if (!maskOverlaps(betMask, winMask))
continue;
const int64_t amount = bet.getAmount();
const int64_t multiplier =
getMultiplier(bet.getType());
totalCents += amount + amount * multiplier;
}
return Money(totalCents);
}Totals the placed chips, reserves the stake through the wallet, and only advances the round after a successful response.
const int64_t totalStake = std::accumulate(
betManager->getActiveBets().begin(),
betManager->getActiveBets().end(),
int64_t{ 0 },
[](int64_t total, const PackedBet& bet) {
return total + bet.amount;
});
const auto reserveResult = WalletClient::ReserveBet(
roundId,
roundId + "-reserve",
totalStake);
if (!reserveResult.success) {
setRoundPhase(RoundPhase::Failed);
refreshBalanceFromWallet();
return;
}
playerBalance = Money(reserveResult.balance_after);
setRoundPhase(RoundPhase::Reserved);Reflection
The main challenge was the number of systems involved in a single round. Input, chip placement, bet validation, random results, payouts, visual feedback, wallet state, and persistence all have to agree.
Collaborative ownership also made communication important: a change in a shared type or transaction flow could affect both games and several services.
Learning
I gained a better understanding of how to integrate game code with services and how to debug a result that crosses several layers instead of living in one class.
I also learned the value of precise ownership language. This page focuses on the parts I participated in while still explaining the full system needed to understand the work.
Next steps
I would add more automated end-to-end round tests, improve accessibility and feedback in the table interface, and document module boundaries more thoroughly.
Explore