{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "685be631",
   "metadata": {},
   "source": [
    "# 19-28 · SnakeApp: отделяем модель от визуализации\n",
    "\n",
    "Практика к разделу [«SnakeApp: отделяем модель от визуализации»](../../site/chapters/glava-19/19-28-snakeapp-arhitektura.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "748e3c57",
   "metadata": {},
   "source": [
    "## Цель\n",
    "\n",
    "Собрать мини-объект приложения: state отдельно от Turtle-виджетов."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e249daf",
   "metadata": {},
   "source": [
    "## Настройка (выполнить один раз)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a05809b1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-03T00:54:27.384720Z",
     "iopub.status.busy": "2026-09-03T00:54:27.384548Z",
     "iopub.status.idle": "2026-09-03T00:54:27.522936Z",
     "shell.execute_reply": "2026-09-03T00:54:27.520667Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Экран готов.\n"
     ]
    }
   ],
   "source": [
    "import turtle\n",
    "\n",
    "RAZMER_SHAGA = 20\n",
    "GRANICA = 280\n",
    "\n",
    "screen = turtle.Screen()\n",
    "screen.title(\"Змейка\")\n",
    "screen.bgcolor(\"black\")\n",
    "screen.setup(width=600, height=600)\n",
    "screen.tracer(0)\n",
    "print(\"Экран готов.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a367653b",
   "metadata": {},
   "source": [
    "## Рабочий пример"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "8272d8e3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-03T00:54:27.524290Z",
     "iopub.status.busy": "2026-09-03T00:54:27.524073Z",
     "iopub.status.idle": "2026-09-03T00:54:27.528042Z",
     "shell.execute_reply": "2026-09-03T00:54:27.527483Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "app.state — обычный словарь; app.head — единственный Turtle-объект.\n"
     ]
    }
   ],
   "source": [
    "class MiniSnakeApp:\n",
    "    def __init__(self):\n",
    "        self.state = {\"snake\": [(0, 0)], \"score\": 0}\n",
    "        self.head = turtle.Turtle()\n",
    "        self.head.speed(0)\n",
    "        self.head.shape(\"square\")\n",
    "        self.head.penup()\n",
    "\n",
    "    def render(self):\n",
    "        self.head.goto(*self.state[\"snake\"][0])\n",
    "        screen.update()\n",
    "\n",
    "app = MiniSnakeApp()\n",
    "app.state[\"snake\"] = [(40, 0)]\n",
    "app.render()\n",
    "print(\"app.state — обычный словарь; app.head — единственный Turtle-объект.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e5c3a1b",
   "metadata": {},
   "source": [
    "## Проверка результата"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f5b6cbb3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-03T00:54:27.529238Z",
     "iopub.status.busy": "2026-09-03T00:54:27.529083Z",
     "iopub.status.idle": "2026-09-03T00:54:27.532259Z",
     "shell.execute_reply": "2026-09-03T00:54:27.531438Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Модель (state) и виджет (head) — разные атрибуты, не одно и то же.\n"
     ]
    }
   ],
   "source": [
    "assert app.state[\"snake\"] == [(40, 0)]\n",
    "assert isinstance(app.head, turtle.Turtle)\n",
    "assert app.head.position() == (40.0, 0.0)\n",
    "print(\"Модель (state) и виджет (head) — разные атрибуты, не одно и то же.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c4e67d5f",
   "metadata": {},
   "source": [
    "## Завершение (выполнить один раз, в самом конце)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "795c4b41",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-03T00:54:27.533586Z",
     "iopub.status.busy": "2026-09-03T00:54:27.533305Z",
     "iopub.status.idle": "2026-09-03T00:54:27.538558Z",
     "shell.execute_reply": "2026-09-03T00:54:27.538032Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Окно закрыто.\n"
     ]
    }
   ],
   "source": [
    "screen.bye()\n",
    "print(\"Окно закрыто.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Cartesian Python 3.14",
   "language": "python",
   "name": "cartesian-python314"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
