from __future__ import annotations from dataclasses import dataclass, field from typing import Deque, Dict, List, Optional, Tuple from collections import deque from .protocol import Direction Coord = Tuple[int, int] @dataclass class Snake: snake_id: int head: Coord direction: Direction body: Deque[Coord] = field(default_factory=deque) # includes head at index 0 input_buf: Deque[Direction] = field(default_factory=deque) blocked: bool = False @property def length(self) -> int: return len(self.body) def enqueue_direction(self, new_dir: Direction, capacity: int = 3) -> None: """Apply input buffer rules: size<=capacity, replace last on overflow/opposite, drop duplicates.""" last_dir = self.input_buf[-1] if self.input_buf else self.direction # Drop duplicates if int(new_dir) == int(last_dir): return # Opposite of last? replace last if (int(new_dir) ^ int(last_dir)) == 2: # 0^2,1^3,2^0,3^1 are opposites if self.input_buf: self.input_buf[-1] = new_dir else: # No buffered inputs; just add new_dir (consumption will handle 180° rule) self.input_buf.append(new_dir) return # Normal append with overflow replacement if len(self.input_buf) >= capacity: self.input_buf[-1] = new_dir else: self.input_buf.append(new_dir) @dataclass class PlayerSession: player_id: int name: str color_id: int peer: object # transport-specific handle input_seq: int = 0 @dataclass class GameState: width: int height: int snakes: Dict[int, Snake] = field(default_factory=dict) apples: List[Coord] = field(default_factory=list) tick: int = 0 occupancy: Dict[Coord, Tuple[int, int]] = field(default_factory=dict) # cell -> (snake_id, index) def in_bounds(self, x: int, y: int) -> bool: return 0 <= x < self.width and 0 <= y < self.height def cell_free(self, x: int, y: int) -> bool: return (x, y) not in self.occupancy def occupy_snake(self, snake: Snake) -> None: for idx, (cx, cy) in enumerate(snake.body): self.occupancy[(cx, cy)] = (snake.snake_id, idx) def clear_snake(self, snake: Snake) -> None: for (cx, cy) in list(snake.body): self.occupancy.pop((cx, cy), None)