Code Breaker

Level: Intermediate 30–60 min

Concepts: AlgorithmsStringsValidationEdge Cases

Solutions: C# | TypeScript | Python


Build the scoring engine for a Mastermind-style code-breaking game. Given a secret code and a guess, return feedback indicating exact matches and partial matches.

Requirements

The secret code and guess are both 4-digit strings using digits 1–6.

Feedback Rules

  • Exact match (+) — correct digit in the correct position
  • Partial match (-) — correct digit but in the wrong position
  • No match — digit not in the secret code

Priority

  • Exact matches are evaluated first
  • A digit consumed by an exact match cannot also count as a partial match
  • Feedback string lists all + symbols before - symbols

Output

Return a feedback string:

  • "++" means 2 exact matches
  • "+-" means 1 exact match and 1 partial match
  • "" means no matches at all

Test Cases

SecretGuessFeedbackExplanation
"1234""5678"""No matches
"1234""1578""+"1 exact (position 1)
"1234""1234""++++"All exact
"1234""4321""----"All partial, none exact
"1234""1243""++-"Wait — see below
"1234""1243""++--"Positions 1,2 exact; 3,4 partial
"1234""2135""+--"Position 2 exact; 1,3 partial
"1124""5167""+"Position 2 exact; only one 1 available
"1122""2211""----"All partial, none in correct position
"1111""1112""+++"3 exact; 2 is not a 1
"1111""2111""+++"Positions 2,3,4 exact; 2 not in code

The Tricky Case

Secret "1124", Guess "5167":

  • Position 1: 5 vs 1 → no match
  • Position 2: 1 vs 1 → exact match (+)
  • Position 3: 6 vs 2 → no match
  • Position 4: 7 vs 4 → no match

The 1 in position 1 of the guess might seem like a partial match, but the secret’s 1 at position 2 is already consumed by the exact match. Result: "+"

Bonus

  • Support configurable code length (4, 5, or 6 digits)
  • Support configurable digit range (1–6, 1–8, etc.)
  • Build a full game loop: generate random secret, accept guesses, track attempt count
  • Add a isWon() check when feedback is all +

Hint

Process exact matches first in a separate pass. Mark matched positions as “consumed” in both the secret and guess. Then do a second pass for partial matches, only considering unconsumed positions. This two-pass approach handles all the tricky duplicate-digit cases cleanly.

Reference Walkthrough

Reference implementations in C#, TypeScript, and Python live at tddbuddy-reference-katas/code-breaker. This is an F2 (light builder) kata: two primary entities (Secret, Guess) each get a small test-folder builder so four-peg codes read as a single fluent line, a typed Peg enum closes the 1–6 domain at compile time, and Feedback carries both the structured counts (exactMatches, colorMatches) and the canonical "+"/"-" string.

Scope note — feedback engine only. The reference is scoped to scoring a guess against a secret. Random secret generation, the full game loop with attempt tracking, configurable code length, and a configurable peg range are all out of scope for this reference and listed as stretch goals in the repo README. Those responsibilities introduce a SecretGenerator collaborator and a Game aggregate — F3 territory, not F2.

This kata ships in Agent Full-Bake mode at middle gear, the F2 (light builder) tier. See the repo’s Gears section for why middle gear is the deliberate choice.


  • Examples Pin Intent. Properties Pin the Invariants.
    Example-based tests anchor scenarios in the team's vocabulary. Property-based tests anchor invariants across the input space. The agent needs both axes, and most suites only carry one.
  • Katas Are Rehearsal, Not Performance
    You don't practice TDD on production code. You practice on katas and bring the muscle memory to production. The gap between knowing TDD and doing TDD is reps.
  • Test Deletion Is a Privileged Operation
    The cheapest way for an agent to make a failing test pass is to delete it. That is logical for the agent and catastrophic for the codebase. Tests are append-only by default. Deletion needs a human author, a separate commit, and a separate review.