Tennis Score
Level: Intermediate 30–60 minConcepts: State
Solutions: C# | TypeScript | Python
Create a program to score a tennis match.
Requirements
- Implement tennis scoring rules:
- 0 points = “Love”
- 1 point = “15”
- 2 points = “30”
- 3 points = “40”
- 4+ points = “Game” (if leading by 2)
- Handle deuce scenarios:
- Both players at 40 = “Deuce”
- Player ahead by 1 = “Advantage”
- Player ahead by 2 = “Game”
- Support match scoring:
- Games needed to win a set (6, leading by 2)
- Sets needed to win the match (2)
Tiebreak rules at 6-6 are a bonus and are not part of the reference implementations linked below.
Test Cases
| Scenario | Score | Expected Output |
|---|---|---|
| Start of Game | 0-0 | ”Love-Love” |
| First Point | 1-0 | ”15-Love” |
| Two Points Each | 2-2 | ”30-30” |
| Deuce | 3-3 | ”Deuce” |
| Advantage | 4-3 | ”Advantage Player 1” |
| Game Win | 4-2 | ”Game Player 1” |
| Set Win | 6-4 | ”Set Player 1” |
| Match Win | 6-4, 6-3 | ”Match Player 1” |
Stretch Goals (Not in the Reference)
The reference implementations cover the eight scenarios above and stop. If you want to extend further:
- Tiebreak scenarios (at 6-6 in games)
- Match point detection
- Validation against impossible game states
- Negative-score / invalid-input rejection
Tips
- Start with basic point scoring
- Add deuce handling next
- Then implement game scoring
- Finally add set and match scoring
- Consider using enums for score states
Reference Walkthrough
Full C#, TypeScript, and Python implementations live at tddbuddy-reference-katas/tennis-score — the same eight scenarios across all three languages, walked commit-by-commit through the TDD cycle.
- C# (.NET 8, xUnit, FluentAssertions) — walkthrough
- TypeScript (Node 20, Vitest, strict types) — walkthrough
- Python (3.11, pytest) — walkthrough
This is a Pedagogy mode kata — the walkthroughs step through the TDD cycle commit-by-commit. Watch the gear shift from low (fake-it, per-player if ladders) to middle once the Advantage scenario forces the refactor. The teaching point is the state machine that extracts itself: through Love, 15, 30, 40, Deuce the if/else chain looks fine, but Advantage starts comparing counts against each other instead of against fixed values. That’s the cliff. Lift the count into a seven-state enum (Love | Fifteen | Thirty | Forty | Deuce | Advantage | Game) and the formatter becomes a dispatch — the Game scenario that follows passes on arrival. Sets and match are deliberately not a second state machine; they’re integer tallies with win conditions. See the repo’s Gears section for why middle gear is where the state machine lands.