Tennis Refactoring
Level: Intermediate 30–60 minConcepts: RefactoringLegacy CodeStrings
You are given a working tennis scoring function. The code is correct but hard to read. Your job is to refactor it into something clean — without breaking existing behavior.
This is a refactoring kata. Write characterization tests first, then improve the code.
Tennis Scoring Rules
- A game starts at 0-0 (called “Love-All”)
- Scores go: 0 (“Love”), 1 (“Fifteen”), 2 (“Thirty”), 3 (“Forty”)
- If both players have 40, it’s “Deuce”
- If the score is Deuce and a player scores, they have “Advantage”
- If the player with Advantage scores again, they win
- If the other player scores when their opponent has Advantage, it goes back to Deuce
The Legacy Code
function getScore(p1Score, p2Score, p1Name, p2Name) {
var result = "";
if (p1Score == p2Score) {
if (p1Score == 0) result = "Love-All";
else if (p1Score == 1) result = "Fifteen-All";
else if (p1Score == 2) result = "Thirty-All";
else if (p1Score >= 3) result = "Deuce";
} else if (p1Score >= 4 || p2Score >= 4) {
var diff = p1Score - p2Score;
if (diff == 1) result = "Advantage " + p1Name;
else if (diff == -1) result = "Advantage " + p2Name;
else if (diff >= 2) result = "Win for " + p1Name;
else if (diff <= -2) result = "Win for " + p2Name;
} else {
var scores = ["Love", "Fifteen", "Thirty", "Forty"];
result = scores[p1Score] + "-" + scores[p2Score];
}
return result;
}
Your Task
Step 1: Write characterization tests. Cover every scoring combination. Your tests should capture the exact behavior of the current code.
Step 2: Refactor. Improve readability, extract concepts, remove duplication. Keep all tests green throughout.
Test Cases
| Player 1 Score | Player 2 Score | Output |
|---|---|---|
| 0 | 0 | Love-All |
| 1 | 1 | Fifteen-All |
| 2 | 2 | Thirty-All |
| 3 | 3 | Deuce |
| 4 | 4 | Deuce |
| 1 | 0 | Fifteen-Love |
| 0 | 1 | Love-Fifteen |
| 2 | 1 | Thirty-Fifteen |
| 3 | 1 | Forty-Fifteen |
| 4 | 3 | Advantage Player1 |
| 3 | 4 | Advantage Player2 |
| 5 | 4 | Advantage Player1 |
| 5 | 3 | Win for Player1 |
| 3 | 5 | Win for Player2 |
Bonus
- Refactor to use polymorphism — replace conditionals with a scoring strategy per game state
- Add a
TennisGameclass that tracks points viawonPoint(playerName)and reports score viagetScore() - Support tiebreak scoring (numeric, first to 7, win by 2)
Hint
The code has three distinct states: equal scores, endgame (scores ≥ 40), and normal play. Each state has different formatting rules. Extracting these into named methods or separate functions makes the logic immediately clearer.