🍎 Section 05: Add the Food Object
Section Summary
In this section, students create the Food class in food.py. This class is responsible for placing food on valid empty grid cells and respawning food after it is eaten.
By the end of this section, students will understand how composition works in OOP: the game will use separate Snake and Food objects that collaborate through clear interfaces.
✅ Checklist
- [ ] Create
food.py. - [ ] Add imports, type alias, and
Foodclass definition. - [ ] Implement
__init__to place food on a free cell. - [ ] Implement
respawn()to move food to a new free cell. - [ ] Ensure food never appears on occupied snake cells.
- [ ] Run
s05_test.pyto verify food placement rules.
Core Concepts
1. OOP Composition
Composition means one object owns or uses other objects. In this project, Game will manage both Snake and Food. Each class handles its own responsibility:
- Snake manages snake movement and collisions.
- Food manages food position and respawning.
This keeps code modular and easier to maintain.
2. Encapsulation of Spawn Rules
The rule "food must be on an empty tile" is handled inside Food. Other files do not need to re-implement spawn logic. They simply provide occupied cells and trust Food to pick a valid position.
3. Reusing Shared Utilities
Food uses random_empty_cell() from utils.py. Reusing tested helper logic avoids duplicate bugs and keeps behavior consistent across the project.
4. Constructor vs Behavior Method
__init__(occupied)sets the first valid food position.respawn(occupied)applies the same rule later after food is eaten.
This shows how classes separate one-time setup and repeatable behavior.
Code Students Will Type (food.py)
Type this code by hand so you understand how the Food object controls placement.
Detailed Code Review & Key Concepts
Imports and Type Alias
random_empty_cellis imported fromutilsto reuse the shared spawn rule.Coord = Tuple[int, int]keeps position types readable.
Food.__init__
- Takes an
occupiediterable (usually snake body cells). - Immediately chooses one valid empty cell and stores it in
self.pos.
Food.respawn
- Uses the same occupied-cell rule as initialization.
- Updates
self.poswhen new food should appear.
Key idea: the class has one clear job, and both methods enforce the same placement contract.
Test File (s05_test.py)
Use this test file to verify that food placement always avoids occupied cells.
This test file verifies the class contract in three ways:
- test_food_init_picks_only_free_cell() confirms initialization picks a valid free coordinate.
- test_food_respawn_uses_latest_occupied_cells() confirms respawn follows updated occupancy and moves to the correct new free spot.
- test_food_init_raises_when_grid_full() confirms full-grid edge handling by checking for ValueError.
These checks ensure food placement is safe before integrating Food into the full game loop.

