Implement stuck snake mechanics, persistent colors, and length display

Major gameplay changes:
- Snakes no longer die from collisions
- When blocked, snakes get "stuck" - head stays in place, tail shrinks by 1 per tick
- Snakes auto-unstick when obstacle clears (other snakes move/shrink away)
- Minimum snake length is 1 (head-only)
- Game runs continuously without rounds or game-over state

Color system:
- Each player gets a persistent color for their entire connection
- Colors assigned on join, rotate through available colors
- Color follows player even after disconnect/reconnect
- Works for both desktop and web clients

Display improvements:
- Show snake length instead of score
- Length accurately reflects current snake size
- Updates in real-time as snakes grow/shrink

Server fixes:
- Fixed HTTP server initialization issues
- Changed default host to 0.0.0.0 for network multiplayer
- Improved file serving with proper routing

Testing:
- Updated all collision tests for stuck mechanics
- Added tests for stuck/unstick behavior
- Added tests for color persistence
- All 12 tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vladyslav Doloman
2025-10-04 16:39:30 +03:00
parent ec8e9cd5fb
commit 84a58038f7
10 changed files with 271 additions and 133 deletions

View File

@@ -32,6 +32,8 @@ class Snake:
direction: Tuple[int, int] = (1, 0) # Default: moving right
alive: bool = True
score: int = 0
stuck: bool = False # True when snake is blocked and shrinking
color_index: int = 0 # Index in COLOR_SNAKES array for persistent color
def get_head(self) -> Position:
"""Get the head position of the snake."""
@@ -45,6 +47,8 @@ class Snake:
"direction": self.direction,
"alive": self.alive,
"score": self.score,
"stuck": self.stuck,
"color_index": self.color_index,
}
@classmethod
@@ -55,6 +59,8 @@ class Snake:
snake.direction = tuple(data["direction"])
snake.alive = data["alive"]
snake.score = data["score"]
snake.stuck = data.get("stuck", False) # Default to False for backward compatibility
snake.color_index = data.get("color_index", 0) # Default to 0 for backward compatibility
return snake