This kata complements Clean Code: Fundamentals, Ep. 5 - Form.
In bowling, a player rolls a ball down a lane and tries to knock down as many pins as possible. The game consists of ten frames, and in each frame, the player has two opportunities (called rolls) to knock down as many pins as possible.
If, after two rolls, at least one pin is still standing, it’s called an open frame. The score for the frame is the total number of pins knocked down, plus bonus points awarded for strikes or spares.
A spare is when the player knocks down all the pins in two rolls. If the player gets a spare, the score for the frame is ten, plus the number of pins knocked down on their next roll. If a spare is thrown in the tenth frame, the player is awarded one more roll.
A strike is when the player knocks down all the pins in one roll. If the player gets a strike, their score for the frame is ten, plus the number of pins knocked down on their next two rolls. If a strike is thrown in the tenth frame, the player is awarded two more rolls.
The final score is the total of all frame scores.
In this kata, you will write a class BowlingGame that calculates the score of
a ten-pin bowling game with two methods:
roll(pins)is called each time the player rolls a ball, withpinsrepresenting the number of pins knocked down in the current roll;score()returns the score calculated using the above rules.
Here is an example of a game where the player gets a bonus after rolling a spare:
game.roll(7)
game.roll(3) # Spare: 7 + 3 + 6 (bonus) = 16
game.roll(6)
game.roll(2) # Open frame: 6 + 2 = 8
assert game.score() == 24In this example, the player got a spare, which is ten plus the next roll. The next roll (from the second frame) was a 6, so the value of the first frame is 16. The second frame is worth exactly the number of pins the player knocked down. Added to 16, it gives a total of 24.
Here is an example of a game where the player gets the maximum score:
for _ in range(12):
game.roll(10)
assert game.score() == 300In this example, the player gets 12 strikes in a row, the maximum number of strikes possible in a game. Each strike is worth 10 points, plus the pins were knocked down on the next two rolls, resulting in 300 points.
Required:
Optional:
- GNU Make, for shorter commands. Every required task also
has a direct
uvcommand.
You do not need to install Python or pytest separately. uv installs a compatible Python version
and the locked project dependencies when needed.
-
Clone the repository:
git clone https://github.com/Coding-Cuddles/bowling-python-kata.git -
Enter the repository directory:
cd bowling-python-kata -
Run the starter test. Use Make when it is installed:
make testOtherwise, run pytest through
uvdirectly:uv run pytest test_*.pyThe first run may install Python and the project dependencies. Setup is complete when pytest reports
1 passed.If the command fails with
uv: command not found, install uv and repeat this step.
-
Start with a bowling behavior in
test_bowling.pyand implement it inbowling.py. -
Run the tests after each change. Use Make when it is installed:
make testOtherwise, run pytest through
uvdirectly:uv run pytest test_*.pyContinue when the test run passes.
Make is optional. Run make or make help to list these commands in the terminal.
| Command | Result |
|---|---|
make all |
Run the test suite |
make help |
Show the command reference |
make test |
Run the test suite |
make format |
Format tracked Python files |
make format-check |
Check formatting without changing files |
make clean |
Remove generated caches |