Kelick Tech Hub

Build, learn & keep up — tech, Linux & sports news included.

C++ Rock Paper Scissors Game Project

Beginner•1–2 hours•enums, random numbers, game logic

Face the computer in the classic hand game, with a running score.

Share on X

What you will build

Pick rock, paper, or scissors; the computer picks its own; the winner takes the round. Tiny as it is, this project teaches enum types, clean win-condition logic, and how to make a game feel alive with a scoreboard and rematch loop.

What you will learn

Feature checklist

Starter code

#include <iostream>
#include <random>

enum class Move { Rock, Paper, Scissors };

// returns 1 if a beats b, -1 if b beats a, 0 for draw
int outcome(Move a, Move b) {
    if (a == b) return 0;
    bool aWins = (a == Move::Rock     && b == Move::Scissors) ||
                 (a == Move::Paper    && b == Move::Rock) ||
                 (a == Move::Scissors && b == Move::Paper);
    return aWins ? 1 : -1;
}

int main() {
    std::mt19937 rng(std::random_device{}());
    std::uniform_int_distribution<int> dist(0, 2);
    char c;
    std::cout << "Pick (R)ock, (P)aper, (S)cissors, (Q)uit: ";
    while (std::cin >> c && c != 'Q' && c != 'q') {
        Move you = (c == 'R' || c == 'r') ? Move::Rock
                 : (c == 'P' || c == 'p') ? Move::Paper : Move::Scissors;
        Move cpu = static_cast<Move>(dist(rng));
        int r = outcome(you, cpu);
        std::cout << (r > 0 ? "You win!\n" : r < 0 ? "CPU wins!\n" : "Draw!\n");
        std::cout << "Pick again: ";
    }
}

Full walkthrough

Step 1: Model the moves with an enum class

enum class Move { Rock, Paper, Scissors } turns three magic numbers into named values the compiler can type-check — you cannot accidentally compare a Move to 7. The starter converts the player's char into a Move with a ternary chain, and draws the computer's move by casting a random 0–2 to Move.

Step 2: Write outcome() as a pure rules function

outcome(Move a, Move b) returns 1 if a wins, -1 if b wins, 0 for a draw. The trick is one boolean, aWins, with three OR'd conditions: Rock crushes Scissors, Paper covers Rock, Scissors cut Paper. Every other unequal pairing is a loss, so there is no fourth case to write — and no way for the rules to contradict themselves.

int outcome(Move a, Move b) {
    if (a == b) return 0;
    bool aWins = (a == Move::Rock     && b == Move::Scissors) ||
                 (a == Move::Paper    && b == Move::Rock) ||
                 (a == Move::Scissors && b == Move::Paper);
    return aWins ? 1 : -1;
}

Step 3: Set up the random opponent

Use std::mt19937 seeded from std::random_device and std::uniform_int_distribution<int> dist(0, 2), exactly like the guessing game. Seed ONCE before the loop: reseeding every round from a fast clock can repeat the same 'random' move several rounds in a row.

Step 4: Build the round loop

main() prints the prompt 'Pick (R)ock, (P)aper, (S)cissors, (Q)uit: ' and loops while (std::cin >> c && c != 'Q' && c != 'q'). Each round: convert c to your Move, draw the CPU's Move, call outcome(), and print the verdict. The loop condition handles quitting, so the body never checks for Q.

Step 5: Announce the moves and the reason, not just the winner

'You win!' alone feels empty; the checklist wants the story: 'Rock crushes Scissors'. Print both moves by name (a small nameOf(Move) helper returning strings) and pick the reason phrase from the winning pairing. This is presentation code, and it is what separates a game people replay from a logic exercise.

Step 6: Keep score across rounds

Three counters — you, cpu, draws — incremented from outcome()'s return value, printed after each round and once more as a final tally when the player quits. Score is just state carried across loop iterations; declaring the counters INSIDE the loop would reset them every round, the classic bug here.

Step 7: Test all nine pairings

There are only 3 × 3 = 9 combinations: force each one (temporarily rig the CPU move if needed) and verify outcome() against the real rules, especially the three draws. Nine cases is small enough to test exhaustively — a luxury most programs do not give you, so take it.

Common mistakes

Compile and run

g++ -std=c++17 -o rps rps.cpp

Sample run

$ ./rps
Pick (R)ock, (P)aper, (S)cissors, (Q)uit:
> R
You: Rock  |  CPU: Scissors — Rock crushes Scissors. You win!
Score: you 1 · cpu 0 · draws 0
Pick again:
> P
You: Paper  |  CPU: Scissors — Scissors cut Paper. CPU wins!
Score: you 1 · cpu 1 · draws 0
Pick again:
> S
You: Scissors  |  CPU: Scissors — same move. Draw!
Score: you 1 · cpu 1 · draws 1
Pick again:
> R
You: Rock  |  CPU: Paper — Paper covers Rock. CPU wins!
Score: you 1 · cpu 2 · draws 1
Pick again:
> Q
Final score: you 1 · cpu 2 · draws 1. Thanks for playing!

Try it in your browser

This project has a browser demo in the classic site. The demo is a browser re-implementation of the same logic, not the compiled C++ program: Rock crushes scissors, scissors cut paper, paper covers rock. First to bragging rights.

Open the browser demo in the classic site →

Related Beginner projects

← All 60 projects · Classic site (Learn & Sandbox)

Download Fake GPS