Design summary
AnimalGame
A two-player strategy game on a 7×7 board where every piece is an animal with its own way of moving. Capture your opponent's Pika to win.
The game
diagonal straight Slide blocked by pieces Jump hops over them
Class design
Four classes, each owning one part of the problem. The game coordinates them, but never reaches into another class's data directly.
Tap a concept to see where it shows up in the diagram.
- AnimalGameThe coordinator
- BoardOwns the positions
- PieceKnows its owner and legal moves
- PlayerIdentifies a side
How a move works
- CheckGame still on?
- FindNext possible moves?
- CheckIs it legal?
- DoMove & capture
- Then Pika taken → WinElse → Next turn
Any failed check rejects the move and changes nothing.
Key design decisions
Clear, documented assumptions
Ambiguous rules were pinned down before coding: Tangerine moves first, capturing the Pika is the only way to win, and there is no draw condition.
Pieces calculate their own moves
Movement rules live in the Piece class, not in a big if/else in the game. Adding a new animal means writing one small subclass and changing nothing else (open/closed principle).
Algebraic notation as the board key
Squares are stored by their human-readable name (b2), converting to row and column numbers only for movement maths. The code reads like the game.
Testing: tests first
I wrote the unit tests before implementing the classes, straight from the design, then built the code until they passed. All 8 pass. Each group of tests targets the class that owns that rule:
Movement Piece
- Does each piece move only its valid distance?
- Does it move in the right directions, plus the one-step exception?
- Does blocking work: sliders stop, jumpers hop over?
Captures Board
- Does landing on an enemy capture it?
- Is a friendly piece never captured?
Game flow AnimalGame
- Do turns alternate after each legal move?
- Does the game state update until someone wins?
- Does the win go to whoever captured the Pika, for both sides?
Invalid moves AnimalGame
- Is moving from an empty square rejected?
- Is moving the opponent's piece rejected?
- Is every move after the game ends rejected, with nothing changed?
Web version
The game engine has no idea it runs on the web. A small Flask app wraps it in a JSON API, and the browser renders the board and highlights legal moves:
| Endpoint | What it does |
|---|---|
GET /state | Board, whose turn it is, and the game state |
GET /legal_moves/<square> | Where the piece on that square can move, used to highlight targets |
POST /move | Plays a move and returns the new state |
POST /reset | Starts a new game |
Because all the rules live in the Python classes, the web layer adds no game logic of its own, and the same tested engine powers the live demo.