Jelly vs Tower
Level: Advanced 60–90 minConcepts: Business LogicDesign PatternsEdge CasesValidation
Solutions: C# | TypeScript | Python
Build a tower defense combat system inspired by JellyDefense. Towers attack incoming jellies based on color matching and level-based damage tables.
Requirements
Entities
Both Jellies and Towers have:
- A unique identifier
- A color type: Blue, Red, or BlueRed
- A health value
- Alive/dead status (dead when health ≤ 0)
Towers additionally have a level (1–4).
Damage Rules
Damage dealt depends on the tower type, tower level, and jelly color:
| Tower Type | vs Blue Jelly | vs Red Jelly |
|---|---|---|
| Blue Tower | L1: 2–5, L2: 5–9, L3: 9–12, L4: 12–15 | L1: 0, L2: 1, L3: 2, L4: 3 |
| Red Tower | L1: 0, L2: 1, L3: 2, L4: 3 | L1: 2–5, L2: 5–9, L3: 9–12, L4: 12–15 |
| BlueRed Tower | L1: 2, L2: 2–4, L3: 4–6, L4: 6–8 | L1: 2, L2: 2–4, L3: 4–6, L4: 6–8 |
- Damage ranges are random within the specified bounds (accept an injectable random source)
- A BlueRed Jelly takes damage from both the Blue and Red columns (use the higher value)
Combat Flow
Each round:
- Each tower attacks one jelly (closest or first alive)
- Apply damage based on the rules table
- Remove dead jellies
- Report combat log (which tower hit which jelly for how much damage)
Test Cases
| Tower | Level | Jelly Color | Min Damage | Max Damage |
|---|---|---|---|---|
| Blue | 1 | Blue | 2 | 5 |
| Blue | 1 | Red | 0 | 0 |
| Red | 3 | Red | 9 | 12 |
| Red | 2 | Blue | 1 | 1 |
| BlueRed | 4 | Blue | 6 | 8 |
| BlueRed | 4 | Red | 6 | 8 |
Additional cases:
- Jelly dies when health reaches 0
- Dead jellies cannot be attacked
- Tower attacks do nothing if no jellies remain
- BlueRed jelly takes the higher of Blue/Red damage columns
Bonus
- Add tower targeting priority (closest, weakest, strongest)
- Add jelly movement — jellies advance each round, towers only attack jellies in range
- Add tower upgrade mechanics — towers can be upgraded mid-game
- Track kill counts per tower
Hint
Start with a single tower attacking a single jelly with fixed damage. Get the health/death logic working first. Then introduce the damage table lookup. Randomized damage ranges and multiple entities come last.
Reference Walkthrough
Full C#, TypeScript, and Python implementations live at tddbuddy-reference-katas/jelly-vs-tower with the same twenty-five scenarios across all three languages, fluent TowerBuilder and JellyBuilder, an injectable RandomSource for deterministic damage, and an Arena that orchestrates combat rounds.
- C# (.NET 8, xUnit, FluentAssertions) — walkthrough
- TypeScript (Node 20, Vitest, strict types) — walkthrough
- Python (3.11, pytest, dataclasses) — walkthrough
This kata ships in middle gear — a single commit per language with the full domain design. See the repo’s Gears section for why that’s a deliberate teaching choice.
Related reading
- 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. - The Test Pyramid Was an Economic Argument
The test pyramid was not a quality law. It was a cost structure: unit tests were cheap, integration tests were expensive, so you wrote many of the first and few of the second. Agents collapsed the cost of writing tests at every level, and the cheapest test that still tells the truth is the one that pins a seam the agent cannot fake. - Agents Amplify Whatever Vocabulary They Find
Agents do not bring vocabulary to your codebase. They mirror what's already there. Strong vocabulary gets agent contributions that read like the team. Weak vocabulary gets faster mediocrity. The work you did for craft reasons just became leverage.