{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "90759f88",
   "metadata": {},
   "source": [
    "# 23-04 · Отскакивающий мяч (класс)\n",
    "\n",
    "Практика к разделу [«Проект 23-4: Отскакивающий от четырёх стен мяч с Pygame»](../../site/chapters/glava-23/23-04-otskakivayushij-myach.html). Полный файл — `projects/pygame/bouncing-balls-oop/bouncing_balls.py`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0fb1cd29",
   "metadata": {},
   "source": [
    "## Про игровой цикл в этом ноутбуке\n",
    "\n",
    "Как и в главах 20-21: настоящий игровой цикл — `while rabotaet:`. Здесь вместо него используется `for kadr in range(N):` с фиксированным числом кадров — сама физика мяча (`Myach.shag()`) при этом та же, что в настоящей игре."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03a1813e",
   "metadata": {},
   "source": [
    "## Рабочий пример"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a684589a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:48.980685Z",
     "iopub.status.busy": "2026-08-14T20:59:48.980547Z",
     "iopub.status.idle": "2026-08-14T20:59:49.118772Z",
     "shell.execute_reply": "2026-08-14T20:59:49.118159Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pygame-ce 2.5.8 (SDL 2.32.10, Python 3.14.6)\n",
      "Создано мячей: 3\n",
      " - (255, 100, 100) радиус 15\n",
      " - (100, 200, 255) радиус 15\n",
      " - (150, 255, 150) радиус 15\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "sys.path.insert(0, \"../../projects/pygame/bouncing-balls-oop\")\n",
    "import bouncing_balls as bb\n",
    "\n",
    "myachi = bb.sozdat_myachi(3)\n",
    "print(\"Создано мячей:\", len(myachi))\n",
    "for m in myachi:\n",
    "    print(\" -\", m.cvet, \"радиус\", m.radius)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd75a10b",
   "metadata": {},
   "source": [
    "## Проверка результата"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "c27a0bd0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:49.119919Z",
     "iopub.status.busy": "2026-08-14T20:59:49.119718Z",
     "iopub.status.idle": "2026-08-14T20:59:49.122315Z",
     "shell.execute_reply": "2026-08-14T20:59:49.121880Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Верно: три мяча с тремя разными цветами.\n"
     ]
    }
   ],
   "source": [
    "assert len(myachi) == 3\n",
    "assert len({m.cvet for m in myachi}) == 3\n",
    "print(\"Верно: три мяча с тремя разными цветами.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f5086d6",
   "metadata": {},
   "source": [
    "## Эксперимент — 300 кадров: мячи остаются в границах и отскакивают"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "6bb499d5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:49.123216Z",
     "iopub.status.busy": "2026-08-14T20:59:49.123111Z",
     "iopub.status.idle": "2026-08-14T20:59:49.126149Z",
     "shell.execute_reply": "2026-08-14T20:59:49.125714Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Отскоков у каждого мяча: [4, 6, 7]\n",
      "Верно: после 300 кадров все мячи внутри экрана и хотя бы раз отскочили.\n"
     ]
    }
   ],
   "source": [
    "for kadr in range(300):\n",
    "    for myach in myachi:\n",
    "        myach.shag()\n",
    "\n",
    "for myach in myachi:\n",
    "    assert myach.radius <= myach.x <= bb.SHIRINA - myach.radius\n",
    "    assert myach.radius <= myach.y <= bb.VYSOTA - myach.radius\n",
    "    assert myach.otskokov > 0\n",
    "\n",
    "print(\"Отскоков у каждого мяча:\", [m.otskokov for m in myachi])\n",
    "print(\"Верно: после 300 кадров все мячи внутри экрана и хотя бы раз отскочили.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e4e9de6",
   "metadata": {},
   "source": [
    "## Задание ★★ Самостоятельная задача\n",
    "\n",
    "Отрисуйте кадр и убедитесь, что каждый мяч нарисован своим собственным цветом."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "87405c2b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:49.127153Z",
     "iopub.status.busy": "2026-08-14T20:59:49.127026Z",
     "iopub.status.idle": "2026-08-14T20:59:49.164053Z",
     "shell.execute_reply": "2026-08-14T20:59:49.162742Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Верно: каждый мяч нарисован своим цветом.\n"
     ]
    }
   ],
   "source": [
    "bb.narisovat_kadr(myachi)\n",
    "for myach in myachi:\n",
    "    cvet_na_ekrane = bb.screen.get_at((int(myach.x), int(myach.y)))[:3]\n",
    "    assert cvet_na_ekrane == myach.cvet\n",
    "\n",
    "print(\"Верно: каждый мяч нарисован своим цветом.\")\n",
    "bb.pygame.quit()"
   ]
  }
 ],
 "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
}
