Leap Year Calculator
Level: Beginner 15–30 minConcepts: Validation
Solutions: C# | TypeScript | Python
Create a program to determine if a given year is a leap year.
Requirements
- Implement leap year rules:
- A year is a leap year if it is divisible by 4
- However, if the year is divisible by 100, it is not a leap year
- Unless the year is also divisible by 400, then it is a leap year
- Handle input validation:
- Input must be a positive integer
- Input must be a valid year (e.g., not negative)
- Return appropriate results:
- Boolean indicating if the year is a leap year
- Error message for invalid inputs
Test Cases
| Year | Is Leap Year? | Reason |
|---|---|---|
| 2000 | Yes | Divisible by 400 |
| 2004 | Yes | Divisible by 4, not by 100 |
| 2100 | No | Divisible by 100, not by 400 |
| 2001 | No | Not divisible by 4 |
| 0 | Error | Invalid year |
| -1 | Error | Invalid year |
Edge Cases to Consider
- Year 0
- Negative years
- Non-integer inputs
- Very large years
- Null or undefined inputs
Tips
- Start with the basic divisible by 4 rule
- Add the divisible by 100 exception
- Finally add the divisible by 400 rule
- Consider using a separate method for input validation
- Use descriptive variable names for the rules
Reference Walkthrough
Reference implementations in C#, TypeScript, and Python live at tddbuddy-reference-katas/leap-year. Eight scenarios cover the full rule cascade — typical leap years (2020, 2024), century non-leap years (1900, 2100), four-hundred-divisible leaps (2000, 1600), and plain non-leap years (2001, 2023) — shared across all three languages, each a single pure function int → bool. Input validation concerns listed above (zero, negative years, non-integer inputs) are not implemented in the reference — the Gregorian rule cascade alone is sufficient to demonstrate the shape.
- C# (.NET 8, xUnit, FluentAssertions 6.12.0) — walkthrough
- TypeScript (Node 20, Vitest 1.6, TS 5 strict) — walkthrough
- Python (3.11, pytest) — walkthrough
This kata ships in Agent Full-Bake mode at high gear (F1 tier): the algorithm is small enough to land as one commit per language, with a brief walkthrough noting there are no builders because the algorithm’s inputs and outputs are the domain. No aggregates to construct, no value types to introduce, no collaborators to inject — just isLeapYear(year). See the repo’s Gears section for when high gear is the right call.
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.