Rozdział 19 · Architektura
GameState z dataclass
Jedna struktura danych opisuje całą grę, bez żadnego obiektu Turtle środku.
Jedna struktura zamiast ośmiu oddzielnych zmiennych
Zebrać wszystkie pola podzielone na części — węża, kierunek, jedzenie, wynik, status,
Prędkość to jeden. @dataclass, ten sam pomysł co
DrawingState w rozdziale 18:
gamestate.py
@dataclass
class GameState:
snake: list[Position] = field(default_factory=lambda: [(0, 0)])
direction: Direction = Direction.RIGHT
next_direction: Direction = Direction.RIGHT
food: Position | None = (0, 0)
score: int = 0
high_score: int = 0
status: GameStatus = GameStatus.READY
delay_ms: int = BASE_DELAY_MS
Dlaczego food w ogóle można None
Dziewięćdziesiąt dziewięć meczów na sto
food jest zwykłą klatką. Ale sekcja 19.18 pokazuje szczery, skrajny przypadek: jeśli wąż zajmuje dosłownie całe pole, nie będzie wolnej klatki na nowe jedzenie. Rodzaj
Model Position | None sprawia, że ten przypadek jest widoczny w samej sygnaturze, a nie ukryty — kod, który czyta state.foodjest zobowiązany jasno zdecydować, co zrobić, jeśli nie ma jedzenia.Pokusa, aby zapisać tutaj obiekt Turtle- — częsty błąd
Jeśli wpiszesz
head_turtle w środku GameState, testy z rozdziału 19.30 przestaną działać bez prawdziwego okna, a „model” przestanie być modelem — znowu połączy się z wyświetlaniem, jak w pierwszym prototypie. Rozdział 19.31 omawia ten błąd jako osobny Debug Lab.next_direction — oddzielny od direction
pole z jakiegoś powodu: Rozdział 19.31 (Debug Labs 5-6) wyjaśnia, dlaczego klawiatura żąda
kierunek i nie zmienia go bezpośrednio.
Praktyka: projektujemy i porównujemy GameState
Automatyczna weryfikacja — klasa GameState: tworzenie, porównanie i dataclasses.replace()