This guide walks you through debugging the Snake game using VS Code breakpoints and GitHub Copilot. You'll learn how to find a bug where the snake passes over food without eating it.
The snake can move around, but when it reaches the red food dot, nothing happens:
- The food doesn't disappear
- The score doesn't increase
- The snake doesn't grow
Your mission: Use breakpoints to find why the food collision isn't working.
Everything is pre-configured in the Dev Container! Just:
- Open in VS Code
- Click "Reopen in Container" when prompted
- All extensions and settings are ready
Included Extensions:
- GitHub Copilot & Copilot Chat
- Python & Python Debugger
- Debug MCP Extension
- Press
F5and select "🤖 Snake: Auto-Player" - Watch the snake move toward the red food
- Notice: The snake passes right through the food!
- The score stays at 0, food never moves
- Press
F5and select "🐍 Snake: Manual Mode" - Use arrow keys to move the snake to the food
- Same problem: Snake goes over food, nothing happens
The bug: Food collision detection isn't working correctly.
Open src/snake.py - this contains the SnakeGame class with all game logic.
Look for the update() method (around line 130). This is where the game:
- Moves the snake
- Checks for collisions
- Handles food eating
Find this section (around line 184):
# Check food collision
if (new_head[0], new_head[1]) == (self.food_pos[1], self.food_pos[0]):
self.score += 1
self._spawn_food()- Click in the left gutter on the line with
if (new_head[0], new_head[1]) == - A red dot appears - this is your breakpoint
- Press
F5and select "🐛 Debug: Step Through Auto-Player"
When the debugger pauses at your breakpoint:
-
Look at the Variables panel in the Debug sidebar
-
Find these variables:
new_head- Where the snake IS NOW (tuple like(5, 3))self.food_pos- Where the food is (tuple like(5, 3))
-
The Aha Moment: Notice that:
new_headequalsfood_pos✅ (e.g., both are(5, 3))- But the code compares
new_headwith(food_pos[1], food_pos[0])=(3, 5)❌ - The X and Y are swapped!
In the Watch panel, add these expressions to see the bug clearly:
new_head
self.food_pos
(self.food_pos[1], self.food_pos[0])
new_head == self.food_pos
(new_head[0], new_head[1]) == (self.food_pos[1], self.food_pos[0])
Press F5 (Continue) and watch - new_head == self.food_pos is True but the buggy comparison is False!
The code checks:
if (new_head[0], new_head[1]) == (self.food_pos[1], self.food_pos[0]): # ❌ WRONG - x/y swapped!But it should check:
if new_head == self.food_pos: # ✅ RIGHT - direct comparisonThe bug compares:
new_head[0](snake's X) withfood_pos[1](food's Y)new_head[1](snake's Y) withfood_pos[0](food's X)
This is a classic copy-paste bug where X and Y coordinates got swapped!
Snake at (5, 3) Food at (5, 3)
Bug checks: (5, 3) == (3, 5)? ❌ NO - coordinates swapped!
Should be: (5, 3) == (5, 3)? ✅ YES - direct match
The only time the snake "eats" food is when food happens to spawn at a position where X equals Y (like 5,5 or 3,3) - which is rare!
Open Copilot Chat (Ctrl+Shift+I or Cmd+Shift+I) and try these prompts:
"Explain the update() method in snake.py. What is the difference between head and new_head?"
"In snake.py, the food collision check uses 'head' instead of 'new_head'. Why is this wrong?"
"How do I fix the food collision bug in snake.py?"
"I'm at a breakpoint where new_head equals food_pos but head doesn't. Why isn't the food being eaten?"
Change line ~184 in src/snake.py:
Before (buggy):
if (new_head[0], new_head[1]) == (self.food_pos[1], self.food_pos[0]):After (fixed):
if new_head == self.food_pos:- Make the change
- Press
F5and select "🤖 Snake: Auto-Player" - Watch the snake eat food and grow!
- Score increases, food respawns ✅
| Lesson | Explanation |
|---|---|
| Check your coordinates | X and Y swaps are a classic bug |
| Compare the right values | (x,y) == (y,x) is NOT the same as (x,y) == (x,y) |
| Breakpoints reveal truth | See exactly what values are being compared |
| Copilot helps debug | Ask about coordinate comparisons and find swapped values |
Now that you've found this bug, try these:
- Set conditional breakpoints - Only pause when
new_head == self.food_pos - Add debug logging - Print head, new_head, and food_pos each frame
- Find edge cases - What happens if food spawns on the snake?
| Action | Keyboard | Description |
|---|---|---|
| Continue | F5 |
Run to next breakpoint |
| Step Over | F10 |
Execute line, skip functions |
| Step Into | F11 |
Enter function calls |
| Step Out | Shift+F11 |
Exit current function |
| Stop | Shift+F5 |
End debug session |
| File | Purpose |
|---|---|
| src/snake.py | Game logic (contains the bug) |
| src/main.py | Entry point and game loop |
| src/auto_player.py | AI pathfinding |
Happy Debugging! 🐛🔍