3.06 Modular Game State Loops, Enum Representations & Transition Matrices
Executive Summary: Building interactive decision trees and win/loss resolution matrices. We model cyclical dominance relationships (Rock beats Scissors, Scissors beats Paper, Paper beats Rock) using compact lookup matrices and clean scoped enums.
💻 1. Annotated Source Code
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int main() { char userMove; char computerMove; srand(time(nullptr)); cout << "Welcome to Rock, Paper, Scissors!" << endl; cout << "Enter your move (R, P, or S): "; cin >> userMove; int randNum = rand() % 3; if (randNum == 0) { computerMove = 'R'; } else if (randNum == 1) { computerMove = 'P'; } else { computerMove = 'S'; } cout << "You played: " << userMove << endl; cout << "Computer played: " << computerMove << endl; if (userMove == computerMove) { cout << "It's a tie!" << endl; } else if ( (userMove == 'R' && computerMove == 'S') || (userMove == 'S' && computerMove == 'P') || (userMove == 'P' && computerMove == 'R') ) { cout << "You win!" << endl; } else { cout << "Computer wins" << endl; } return 0; }
📐 2. Architecture & UML Class Model
<<enum class : uint8_t>>
HandMove
Move Enum
Attributes / Data Members
+ROCK : uint8_t = 0
+PAPER : uint8_t = 1
+SCISSORS : uint8_t = 2
<<compilation-unit>>
RpsGameEngine
Decision Matrix
Attributes / Data Members
-userMove : HandMove
-cpuMove : HandMove
Operations / Methods
+determineWinner(p1: HandMove, p2: HandMove) : int32_t[1: P1, -1: P2, 0: Tie]
+generateCpuMove() : HandMove
🔗 Architectural Relationships & Hierarchy
RpsGameEngine
─ ─ >
switches on
─ ─ >
HandMove
📚 3. Core C++ Concepts Deep-Dive
1. Cyclical Win/Loss Dominance
Rock-Paper-Scissors represents a 3-state cyclical dominance ring. Rather than writing 9 nested if-else branches, the result can be computed via a $3\times 3$ transition lookup matrix.
⚡ 4. Embedded Systems & Hardware Reality
1. Lookup Matrix vs Conditional Branching
A $3\times 3$ matrix stored in Flash ROM resolves the winner in a single array access with 0 conditional branches, demonstrating lookup-table optimization.
💡 5. Production-Ready Embedded Refactoring
Zero-branch matrix lookup for game outcome:
💡 Production-Ready Refactor
#include <cstdint> enum class Move : uint8_t { Rock = 0, Paper = 1, Scissors = 2 }; enum class Outcome : int8_t { Loss = -1, Tie = 0, Win = 1 }; // Stored in Flash ROM (.rodata) constexpr Outcome OUTCOME_MATRIX[3][3] = { // Player: Rock, Paper, Scissors vs CPU: /* Rock */ { Outcome::Tie, Outcome::Loss, Outcome::Win }, /* Paper */ { Outcome::Win, Outcome::Tie, Outcome::Loss }, /* Scissors */ { Outcome::Loss, Outcome::Win, Outcome::Tie } }; constexpr Outcome evaluateGame(Move player, Move cpu) noexcept { return OUTCOME_MATRIX[static_cast<size_t>(player)][static_cast<size_t>(cpu)]; }
📝 Knowledge Verification Quiz
Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.
Q1. What is the advantage of using a 2D lookup table matrix over 9 nested if-else branches to resolve game outcomes?
Detailed Explanation:
Matrix indexing (
table[player][cpu]) executes in $O(1)$ time with zero branch instructions, eliminating branch misprediction penalties.
Q2. Why should scoped enum classes (enum class Move : uint8_t) be used instead of raw unscoped enums?
Detailed Explanation:
Scoped enum classes enforce explicit typing and prevent naming collisions and unsafe implicit promotions.
Q3. How much Flash ROM does a 3x3 lookup matrix of int8_t values consume?
Detailed Explanation:
A $3\times 3$ array of 1-byte integers takes exactly $3 \times 3 \times 1 = 9$ bytes in Flash ROM.
Q4. What is the mathematical modulo formula for cyclical Rock-Paper-Scissors win evaluation (0=Rock, 1=Paper, 2=Scissors)?
Detailed Explanation:
The modular distance
(player - cpu + 3) % 3 yields 0 for Tie, 1 for Player Win, and 2 for CPU Win.