Глава 19 · Архитектура

Render: модель → Turtle

Один и тот же пул Turtle-сегментов переиспользуется на каждом тике — новые создаются, только когда змейка выросла.

render() не создаёт новые сегменты на каждом тике

Реальное окно: тонкая фиолетовая сетка на поле, подписанные клетки head cell и food cell
Реальное окно: та же сетка из раздела 19.9, но теперь видно, как голова и еда — просто клетки, которые render() превращает в конкретные Turtle-объекты.

Змейка растёт, и напрашивается простое решение: создавать новый turtle.Turtle() на каждое съеденное яблоко — ровно так и делал первый прототип (раздел 19.6). Но объекты Turtle никуда не деваются: после restart() их окажется столько же, сколько было в самой длинной партии, и каждый из них экран продолжит обслуживать. Поэтому вводим пул сегментов: один раз созданные черепашки переиспользуются от кадра к кадру, новые добавляются только когда их действительно не хватает, а лишние прячутся, а не удаляются.

render.py
def render(self):
    self.head.goto(*self.state.snake[0])

    body = self.state.snake[1:]
    self._ensure_segment_pool(len(body))
    for i, segment in enumerate(self._segment_pool):
        if i < len(body):
            segment.showturtle()
            segment.goto(*body[i])
        else:
            segment.hideturtle()

    if self.state.food is not None:
        self.food_turtle.showturtle()
        self.food_turtle.goto(*self.state.food)
    else:
        self.food_turtle.hideturtle()   # WON — свободных клеток не осталось

    self._render_scoreboard()
    self.screen.update()
Проверка food is not None здесь обязательна
Раздел 19.18 обещал, что отрисовка честно обработает случай, когда свободной клетки для еды не осталось, — вот это место. Без проверки self.food_turtle.goto(*self.state.food) при food = None падает с TypeError: turtle.TNavigator.goto() argument after * must be an iterable, not NoneType — ровно в момент победы, в самом редком и самом обидном состоянии игры.
Пул растёт, но никогда не уменьшается сам по себе
_ensure_segment_pool() добавляет новые Turtle-сегменты, только если их не хватает — уже существующие переиспользуются. Когда змейка становится короче (после restart()), лишние сегменты не удаляются, а просто прячутся через hideturtle() — на следующей долгой игре они снова понадобятся, и пересоздавать их не придётся.
Практика: render() и пул сегментов
Модуль turtle открывает нативное окно Python — выполните локально в VS Code, PyCharm или Jupyter
Практика выполняется локально
Открыть практику →