Tennis Refactoring

Level: Intermediate 30–60 min

Concepts: 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 ScorePlayer 2 ScoreOutput
00Love-All
11Fifteen-All
22Thirty-All
33Deuce
44Deuce
10Fifteen-Love
01Love-Fifteen
21Thirty-Fifteen
31Forty-Fifteen
43Advantage Player1
34Advantage Player2
54Advantage Player1
53Win for Player1
35Win for Player2

Bonus

  • Refactor to use polymorphism — replace conditionals with a scoring strategy per game state
  • Add a TennisGame class that tracks points via wonPoint(playerName) and reports score via getScore()
  • 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.