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

@@ -229,8 +229,8 @@ class GameClient {
// Draw snakes
if (this.gameState.snakes) {
this.gameState.snakes.forEach((snake, index) => {
const color = this.COLOR_SNAKES[index % this.COLOR_SNAKES.length];
this.gameState.snakes.forEach((snake) => {
const color = this.COLOR_SNAKES[snake.color_index % this.COLOR_SNAKES.length];
if (snake.body && snake.alive) {
// Draw body
@@ -314,10 +314,10 @@ class GameClient {
this.playersList.innerHTML = '';
this.gameState.snakes.forEach((snake, index) => {
this.gameState.snakes.forEach((snake) => {
const playerItem = document.createElement('div');
playerItem.className = `player-item ${snake.alive ? 'alive' : 'dead'}`;
playerItem.style.borderLeftColor = this.COLOR_SNAKES[index % this.COLOR_SNAKES.length];
playerItem.style.borderLeftColor = this.COLOR_SNAKES[snake.color_index % this.COLOR_SNAKES.length];
const nameSpan = document.createElement('span');
nameSpan.className = 'player-name';
@@ -327,7 +327,7 @@ class GameClient {
const scoreSpan = document.createElement('span');
scoreSpan.className = 'player-score';
scoreSpan.textContent = snake.score;
scoreSpan.textContent = snake.body.length;
playerItem.appendChild(nameSpan);
playerItem.appendChild(scoreSpan);