Game Theory
Artificial Intelligence
Scalability
Algorithm Design
Machine Learning

Scalable solution for Rock-Paper-Scissor

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A scalable Rock-Paper-Scissors solution is not really about the game logic itself. The winner calculation is tiny. The scalability question is about how you model moves, players, and match resolution so the design still works when you add more rounds, more players, new gestures, or server-side concurrency.

The cleanest approach is to separate the domain model from the outcome rules. Then you can change the rules or the scale of the system without rewriting the whole program.

Start with a Data-Driven Rule Model

Hard-coding nested if statements works for three gestures, but it becomes awkward the moment you add variants such as Rock-Paper-Scissors-Lizard-Spock.

A better design is to store which move defeats which.

python
1beats = {
2    "rock": {"scissors"},
3    "paper": {"rock"},
4    "scissors": {"paper"},
5}
6
7def winner(a: str, b: str) -> int:
8    if a == b:
9        return 0
10    if b in beats[a]:
11        return 1
12    return -1
13
14print(winner("rock", "scissors"))
15print(winner("paper", "paper"))

This is already more scalable because the resolution logic does not need to change when you add new gestures. You only update the rule table.

Extend to More Gestures Naturally

Once the rules are data-driven, extending the game is straightforward.

python
1beats = {
2    "rock": {"scissors", "lizard"},
3    "paper": {"rock", "spock"},
4    "scissors": {"paper", "lizard"},
5    "lizard": {"spock", "paper"},
6    "spock": {"scissors", "rock"},
7}

The winner function stays the same.

That is the main architectural win: complexity moves out of control flow and into configuration-like data.

Model Matches and Tournaments Separately

If the system must handle many games, treat a single match as one concern and tournament orchestration as another.

python
1from dataclasses import dataclass
2
3@dataclass
4class Match:
5    player_a: str
6    move_a: str
7    player_b: str
8    move_b: str
9
10    def resolve(self):
11        result = winner(self.move_a, self.move_b)
12        if result == 0:
13            return "draw"
14        return self.player_a if result == 1 else self.player_b

This keeps game resolution deterministic and easy to test, while larger systems can schedule, persist, or parallelize many matches independently.

Scaling in a Service or Multiplayer System

If Rock-Paper-Scissors is part of a web app or game backend, scalability usually means:

  • many simultaneous players
  • match state persistence
  • fair move submission timing
  • replay or audit capability

At that point, you care more about event handling than about game theory.

A common pattern is:

  1. store player choices
  2. lock or seal a round when both moves arrive
  3. resolve once
  4. publish the result

Because the winner function is pure and tiny, it scales well. The real engineering work is idempotency, persistence, and concurrency control.

AI and Strategy Are a Different Problem

If the question is about an AI that plays well, the scalable solution is still to keep the outcome engine separate from the prediction engine.

The rules engine decides winners. An optional AI component predicts likely next moves from history.

That way, the game remains correct even if the strategy model changes or is removed.

Common Pitfalls

The biggest mistake is writing a giant branching function for every move combination. That becomes hard to extend and easy to break.

Another common issue is mixing game resolution with transport or UI code. Winner calculation should be a pure function so it can be tested independently.

People also use random move generation and call the system scalable when the hard part is actually concurrent match management, not choosing a gesture.

Finally, if you plan to add gestures later, do not lock yourself into a three-case enum with resolution logic scattered everywhere.

Summary

  • The winner logic is simple; the scalable part is the system design around it.
  • Use a data-driven rule table instead of nested conditionals.
  • Keep move resolution pure and separate from match orchestration.
  • Extending the game becomes easy when the rules live in data.
  • In server systems, concurrency and persistence matter more than the winner function itself.
  • Treat AI strategy as a separate concern from the outcome engine.

Course illustration
Course illustration

All Rights Reserved.