diff --git a/MusinAA/.gitignore b/MusinAA/.gitignore new file mode 100644 index 00000000..cb48c0c2 --- /dev/null +++ b/MusinAA/.gitignore @@ -0,0 +1,2 @@ +.vscode/ +*/tests/ \ No newline at end of file diff --git a/MusinAA/docs/Report 1.ipynb b/MusinAA/docs/Report 1.ipynb new file mode 100644 index 00000000..10258740 --- /dev/null +++ b/MusinAA/docs/Report 1.ipynb @@ -0,0 +1,349 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2acfa743", + "metadata": {}, + "source": [ + "# 0. Подготовим окружение" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "4689b73e", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "sys.path.insert(0, os.path.abspath( '../task1'))\n", + "sys.path.insert(0, os.path.abspath( '../'))" + ] + }, + { + "cell_type": "markdown", + "id": "37cc11a5", + "metadata": {}, + "source": [ + "# 1. Генерация тестовых данных\n", + "\n", + "Создадим список records из N=10000 элементов. Каждый элемент — кортеж (name, phone). \n", + "Имена возъмём случайные из небольшого набора (чтобы были повторения и коллизии). \n", + "Для проверки влияния порядка подготовим два варианта: \n", + "\n", + "_records_shuffled_ — случайный порядок. \n", + "_records_sorted_ — отсортированный по имени (по алфавиту)." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "a3b5c31b", + "metadata": {}, + "outputs": [], + "source": [ + "from util.randomNames import generate_test_data\n", + "from util.timeTester import test\n", + "\n", + "records_shuffled = generate_test_data(N=10000)\n", + "records_sorted = generate_test_data(N=10000, _sorted=True)" + ] + }, + { + "cell_type": "markdown", + "id": "c2f4989c", + "metadata": {}, + "source": [ + "# 2. Проведение замеров" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "df12d41d", + "metadata": {}, + "outputs": [], + "source": [ + "# Подготовим функции СД, которые будем тестировать\n", + "from structures.LinkedList import *\n", + "from structures.HashTable import *\n", + "from structures.BinaryTree import *\n", + "\n", + "func_list = {\"Связанный список\" : (ll_insert, ll_find, ll_delete),\n", + " \"Хэш-таблица\" : (ht_insert, ht_find, ht_delete),\n", + " \"Бинарное дерево\" : (bst_insert, bst_find, bst_delete)}" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "cc8d0436", + "metadata": {}, + "outputs": [], + "source": [ + "# Проведём замеры\n", + "report = [[\"Структура\", \"Режим\", \"Вставка\", \"Поиск\", \"Удаление\"]]\n", + "records = {\"Cлучайный\" : records_shuffled, \"Отсортированный\" : records_sorted}\n", + "\n", + "TEST_ITERATIONS_NUM = 5\n", + "\n", + "for _ in range(TEST_ITERATIONS_NUM):\n", + " for mode, data in records.items():\n", + " for struct_name, fns in func_list.items():\n", + " result = test(data, *fns)\n", + " row = [struct_name, mode,\n", + " result[\"insert_time\"],\n", + " result[\"find_time\"],\n", + " result[\"delete_time\"]]\n", + " report.append(row)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "2eedf056", + "metadata": {}, + "outputs": [], + "source": [ + "# Сохраним данные в csv\n", + "import csv\n", + "with open(\"data/task1/results.csv\", \"w\", newline=\"\") as f:\n", + " writer = csv.writer(f)\n", + " writer.writerows(report)" + ] + }, + { + "cell_type": "markdown", + "id": "94335af1", + "metadata": {}, + "source": [ + "# 3. Построение графиков и их анализ" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "cad64d2f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABdEAAAHqCAYAAADrpwd3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAACcZElEQVR4nOzde1xVZfr///eWo2migoEUIFqjkKUF5YDiYUwMyzx+pCysPBSDpUJpovLJLCPLbOcokqUxTqXMZ0jtwCQ4o6RJNiDYNFGaoZjBGFqSppx/f/hl/9zuvREU3IKv5+OxHtO+17Xu+157kGvti3uvZaitra0VAAAAAAAAAACw0MbeEwAAAAAAAAAA4EpFER0AAAAAAAAAABsoogMAAAAAAAAAYANFdAAAAAAAAAAAbKCIDgAAAAAAAACADRTRAQAAAAAAAACwgSI6AAAAAAAAAAA2UEQHAAAAAAAAAMAGiugAAAAAAAAAANhAER1owVJSUmQwGMy2Ll26aPDgwfroo4/sPT0AANCErOX987du3brZe5oAAABAq0MRHWgF3n77bWVnZ2vXrl1avXq1HBwcNHLkSH344Yf2nhoAAGhidXn//K1///72nhoAAK3eyy+/LIPBoA8++MBiX0lJiZydnTV69OjLPzEAzcrR3hMAcOl69+6t4OBg0+u7775bnTp10vr16zVy5Eg7zgwAADS18/N+nY4dO+qHH36ww4wAALh6TJ06VQsXLtSf/vQn3XfffWb7Vq1apcrKSj355JN2mh2A5sJKdKAVcnV1lbOzs5ycnExt5eXlWrRokQICAuTq6ip3d3cNGTJEu3btkqQLfj188ODBkqQzZ87oqaeeUt++feXm5qbOnTsrJCREmzdvtpjHucc7ODjI29tbDz/8sP773/+aYg4ePCiDwaCUlBRTW2lpqW699VYFBASopKTE1L5y5UoNHDhQ1113ndq1a6dbbrlFL7/8siorK5v4HQQAoOU7c+aM4uPj5e/vL2dnZ11//fWaPn26fvnlF7O4bt266ZFHHjFr+8tf/mL19jAXup6Qzub/hQsXml6fPn1aQ4cOVdeuXfXNN9808VkCAHB5de7cWQ8++KC2bt2qgoICU3tFRYXeeOMN3XzzzRo6dKgdZwigOVBEB1qB6upqVVVVqbKyUj/88INmzZqlU6dOaeLEiZKkqqoqRURE6Pnnn9e9996rjRs3KiUlRaGhoSoqKpIks6+DL1iwQJL0/vvvm9qSkpIknf3wfPz4cT399NPatGmT1q9frwEDBmjs2LFat26dxdymTJmi7OxsZWVlafbs2UpNTdWjjz5q81xKS0v1hz/8QZWVldq2bZu8vLxM+w4cOKCJEyfqL3/5iz766CNNmTJFr7zyih5//PEmey8BAGgNamtrNXr0aC1dulRRUVH6+OOPFRcXpz//+c/6wx/+oPLycpvHlpWVac6cOXJwcDBrb8j1xPlOnz6te++9V19//bW2bdumXr16Nel5AgBgD3Urzf/0pz+Z2lJTU/Xf//7XYhX6I488YnWh2vl/wE5NTVV4eLi6du2qtm3bKiAgQHPnztWpU6eszsHWAriDBw+aYmpra5WUlKS+ffuqbdu26tSpk8aPH6/vv//erK/Bgwerd+/eFmMsXbrUos/G/PG9oqJCL7zwgnr16iUXFxd16dJFjz76qH766Ser5wRcybidC9AK/P73vzd77eLiohUrVmj48OGSpPXr12vbtm168803NXXqVFPcubd6ObePulVit912m0USdHNz09tvv216XV1draFDh+rnn3+W0WjUpEmTzOJvuOEGU98DBgzQp59+arZa7VylpaUaOnSo1QK6JC1btsz03zU1NQoLC5O7u7seffRRvfrqq+rUqZP1NwgAgKtMRkaGtmzZopdfflmzZ8+WJA0bNkw+Pj6KjIzUunXrNG3aNKvHPvvss3JwcNDo0aOVk5Njam/I9cS5Tp8+rZEjR1JABwC0OrfeeqsGDhyodevWKTExUW5ubvrTn/6kTp06KSoqyiK+bdu2+uc//2l6/Yc//MEiZv/+/RoxYoRmzZqldu3a6ZtvvtGSJUv0xRdfmB17rilTpphy8scff6wXXnjBbP/jjz+ulJQUzZgxQ0uWLNHx48e1aNEihYaGau/evfL09LyUt0GS7T++19TUaNSoUdqxY4fmzJmj0NBQHTp0SM8++6wGDx6snJwctW3b9pLHBy4XiuhAK7Bu3ToFBARIOluI3rhxo6ZPn67q6mo98cQT+vvf/y5XV1dNnjy5Scb7v//7PxmNRu3du9fsr+Kurq4WsTU1NaqqqlJ1dbW++OIL7dy5U8OGDbOIO3bsmIYOHaovv/xS//nPfywK6JKUl5enZ599Vp999pmOHz9utm/fvn3q169fE5wdAAAtX92H7fNXiv3P//yPJk+erH/84x9Wi+hfffWVVqxYoXfeeUd///vfzfY15nri9OnTuu+++/SPf/xDH3/8MQV0AECr8+STT+p//ud/9Pbbb6tfv37617/+paefflrXXHONWVx5ebmcnJzMFq61aWN5Y4i6b4RLZ1eQ9+/fXwEBARo0aJC+/PJL3Xrrrab9FRUVks6uCq/r9/xbpn3++ed688039eqrryouLs7UHhYWpt/97ndatmyZlixZcgnvwFm2/vj+17/+VZ988onS0tI0duxYU3ufPn10xx13KCUlRX/84x8veXzgcuF2LkArEBAQoODgYAUHB+vuu+/WG2+8ofDwcM2ZM0e//PKLfvrpJ3l7e1tN1I31/vvva8KECbr++uv1zjvvKDs7W//61780efJknTlzxiL++eefl5OTk1xdXTVw4EDdeOONMhqNFnHz5s1TRUWFvLy8lJCQYLG/qKhIYWFhOnLkiF5//XXt2LFD//rXv7Ry5UpJZz+sAwCAs44dOyZHR0d16dLFrN1gMMjLy0vHjh2zetz06dMVFhamyMhIi32NuZ4wGo366quv1KtXLy1atEhVVVUXdyIAAFyhRo8eLR8fH61YsUJGo1EODg6aPn26RdzJkyctCuvWfP/995o4caK8vLzk4OAgJycnDRo0SJLM7r0u/f+ff60tZKvz0UcfyWAw6KGHHlJVVZVp8/LyUp8+fbR9+3aLY86Nq6qqUk1NTb1zrvvj+6uvvqr27dtbjN+xY0eNHDnSrM++ffvKy8vL6vjAlYyV6EArdeutt2rLli3at2+funTpop07d6qmpuaSC+nvvPOO/P39lZqaKoPBYGq3dW/VadOm6bHHHlNtba1+/PFHvfjiiwoJCVF+fr6uvfZaU1z37t21bds27d27VxEREVqzZo2mTJli2r9p0yadOnVK77//vvz8/Ezt+fn5l3Q+AAC0Ru7u7qqqqtJPP/1kVkivra1VSUmJ7rjjDotj3n33XWVnZ9vMrY25nujcubO2bdumiooK3XnnnXruuef0/PPPX9I5AQBwJXF0dNQf//hHzZs3TwcOHNDo0aMtbocqSUeOHJG3t3e9fZ08eVJhYWFydXXVCy+8oN/97ne65pprdPjwYY0dO9Zi0VhpaakkycPDw2af//3vf1VbW2vzli3du3c3e/2f//xHTk5O9c7zfOf+8f38b7D997//1S+//CJnZ2erx9adA9BSUEQHWqm6D8BdunRRRESE1q9fr5SUlEu+pYvBYJCzs7NZAb2kpESbN2+2Gu/t7a3g4GDT69raWo0ZM0bZ2dkKDw83tT/zzDPy8vKSl5eXnnzySc2cOdP0NbO6caWz93s/t68333zzks4HAIDWaOjQoXr55Zf1zjvvKDY21tSelpamU6dOaejQoWbxv/76q2bPnq2ZM2cqMDDQap+NuZ54/PHHTbdwSUxM1NNPP63w8HCFhYVd4pkBAHDlmDZtmhYtWqQzZ85oxowZFvsrKytVUFBg9Rte5/rnP/+pH3/8Udu3bzetPpekX375xWr8/v37JUk33nijzT49PDxkMBi0Y8cOs8/Rdc5v69GjhzZs2GDW9s477+j111+32v+F/vju4eEhd3d3ffLJJ1b3n7uoDmgJKKIDrcBXX31l+pr0sWPH9P777yszM1NjxoyRv7+/fHx89Pbbbys6OlrffvuthgwZopqaGu3evVsBAQG6//77GzzWvffeq/fff18xMTEaP368Dh8+rOeff15du3Y1JfJz/fDDD/r8889NK9ETExPl4uJiuoe7NUuWLNE///lPPfjgg9q1a5ecnJw0bNgwOTs764EHHtCcOXN05swZrVq1Sj///HPj3zAAAFq5YcOGafjw4XrmmWdUVlam/v3768svv9Szzz6r2267zeKhZ5s3b5anp6eeffZZm30+8MADF3U9MWvWLP3973/XQw89pL1796pjx45NeaoAANhNhw4d1L59e910000aMmSIxf6MjAydOXPG5kO461hbNCZJb7zxhtX4TZs2qV27dgoKCrLZ57333quXXnpJR44c0YQJEy50KnJ1dTVbACfJ5i1XGvLH93vvvVcbNmxQdXU1zy9Dq0ARHWgFHn30UdN/u7m5yd/fX8uWLVNMTIyks18zS09PV2JiotavXy+j0ahrr71Wffr00d13393osY4ePark5GStXbtW3bt319y5c/XDDz/oueees4hfs2aN1qxZI4PBoM6dO6tPnz76+9//Lh8fH5tjuLq66t1339Wdd96phIQEvfTSS+rVq5fS0tK0YMECjR07Vu7u7po4caLi4uIUERHRqHMAAKC1MxgM2rRpkxYuXKi3335bixcvloeHh6KiovTiiy9afEivrq62ej/Tc13s9YTBYFBK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1Pb222/rf/7nf0z/4F1dXXX69Gmb/ffp00ePP/64brnlFt1000164YUX1L17d33wwQdW4//85z/rzJkzGjVqVENP95Lt27dPa9euVWxs7GUbEwAAAJcP18eNw/UxAOBKRU5vHHL6xaGIfpWora2VdPZrJxdSVlZm9S93daZOnaq3335bknT06FF9/PHHmjx5smn/zTffrL/97W+qrKy0evypU6c0Z84cBQYGqmPHjmrfvr2++eYbq3+V++2337RgwQK98sorcnS0vIV/UlKS2rdvb9pefPFFi5iPPvpI7du3V8eOHXXLLbdo5cqVF3wP5syZo8cff1zdu3e/YCwAAABaHq6PuT4GALQO5HRy+uVAEf0qcdNNN8lgMKigoOCCsT/++KO8vb1t7p80aZK+//57ZWdn65133lG3bt0UFhZm2v/aa6/p008/Vbt27dS+fXtFR0ebHT979mylpaVp8eLF2rFjh/Lz83XLLbeooqLCYqxXXnlFPXv21MiRI63O5cEHH1R+fr5pO38sSRoyZIjy8/P1+eefKzo6WjNmzNA//vEPm+eXlZWlHTt2aMGCBTZjAAAA0LJxfcz1MQCgdSCnk9MvB8s/c6BV6ty5s4YPH66VK1dqxowZFn91++WXX9SxY0edOnVKBQUFio+Pt9mXu7u7Ro8erbffflvZ2dl69NFHzfaHhYWppKRERUVFqq6u1vvvv2/217IdO3bokUce0ZgxYySdvV/UwYMHLcYpLi7WqlWrtH37dptzcXNz04033mh2nudr166dKaZXr1567bXXlJeXZ/WvfLW1tXrqqaeUkJCgTp062RwX51noZu8ZXJqFJ+w9AwAArgwXk9Pb+0j9X5WOnpYcL7wCrNn8mCd539bgcK6PuT4GgFatsTn9SsnnEjn9/yGnX1nsvhI9KSlJ/v7+cnV1VVBQkHbs2GEztri4WBMnTlTPnj3Vpk0bi6fU1vnll180ffp0de3aVa6urgoICFB6enoznUHLkZSUpOrqat15551KS0vT/v37VVBQoOXLlyskJETffPONHnjgAXXs2FERERH19jV16lT9+c9/VkFBgR5++GGL/Q4ODvL399eNN96o6667zmzfjTfeqPfff1/5+fnau3evJk6cqJqaGos+Vq5cqTFjxuj222+/pPOuqanRmTNndPLkSX3wwQc6dOiQbrnlFqux//jHP3TixAnFxMRc0pgAAAC48nF9zPUxAKB1IKeT05ubXVeip6amatasWUpKSlL//v31xhtvKCIiQl9//bV8fX0t4svLy9WlSxfNnz9fr732mtU+KyoqNGzYMF133XX629/+phtuuEGHDx/Wtdde29ync8Xz9/fXnj17tHjxYj311FMqLi5Wly5dFBQUpFWrVmnhwoWqqqrS1q1bL/hU4Lvuuktdu3bVzTffXO/XYKx57bXXNHnyZIWGhsrDw0PPPPOMysrKLOJqamq0ePHiRvVtzYcffqi2bdvK0dFRvr6+SkxM1PDhw61+zefUqVN66aWXzB4sAQAAgNaJ62OujwEArQM5nZze3Ay1dXfft4N+/frp9ttv16pVq0xtAQEBGj16tBITE+s9dvDgwerbt6+MRqNZe3Jysl555RV98803cnJyuqh5lZWVyc3NTSdOnFCHDh3M9p05c0aFhYWm1fNXq99++03e3t5au3atxo4da+/poIlc9M83t3MBGqS+/ILmwXsONNJF5PQz7X1U2P9V+V/fRa72/vp3I7763dS4Pm596rs2Jr9cfrznQCM1MqdfUflcIqejSTVFTrfb7VwqKiqUm5ur8PBws/bw8HDt2rXrovv94IMPFBISounTp8vT01O9e/fWiy++qOrq6kudMnT2L2U//vijEhIS5Obmpvvuu8/eUwIAAADshutjAABaB3I66mO327mUlpaqurpanp6eZu2enp4qKSm56H6///57/fOf/9SDDz6o9PR07d+/X9OnT1dVVZX+93//1+ox5eXlKi8vN7229jULnFVUVCR/f3/dcMMNSklJsfqgAgAAAOBqwfUxAACtAzkd9bH7T4PBYP4VkdraWou2xqipqdF1112n1atXy8HBQUFBQfrxxx/1yiuv2CyiJyYm6rnnnrvoMa8m3bp1kx3vAAQAAABcUbg+BgCgdSCnoz52u52Lh4eHHBwcLFadHz161GJ1emN07dpVv/vd7+Tg4GBqCwgIUElJiSoqKqweEx8frxMnTpi2w4cPX/T4AAAAAAAAAIDWw25FdGdnZwUFBSkzM9OsPTMzU6GhoRfdb//+/fXdd9+ppqbG1LZv3z517drV5tNnXVxc1KFDB7MNAAAAAAAAAAC7FdElKS4uTm+99ZbWrl2rgoICxcbGqqioSNHR0ZLOrhCfNGmS2TH5+fnKz8/XyZMn9dNPPyk/P19ff/21af8f//hHHTt2TDNnztS+ffv08ccf68UXX9T06dMv67kBAAAAAAAAAFo+u94TPTIyUseOHdOiRYtUXFys3r17Kz09XX5+fpKk4uJiFRUVmR1z2223mf47NzdX7733nvz8/HTw4EFJko+PjzIyMhQbG6tbb71V119/vWbOnKlnnnnmsp0XAAAAAAAAAKB1sPuDRWNiYhQTE2N1X0pKikVbQ27wHxISos8///xSpwYAAAAAAAAAuMrZ9XYuAAAAAAAAAABcySiiA63YjTfeqP/+97/6+eefdcMNN+jXX3+195QAAAAAu+H6GACA1uFy53S7386lVVnodpnHO9HoQw4fPqyFCxfq73//u0pLS9W1a1eNHj1a//u//yt3d/dmmCTsKTo6WjfccINqamo0c+ZMXXvttfaeEgAAuFqsHnx5x3ts+0UdxvXx1YXrYwC4COR0XIEud05nJfpV5Pvvv1dwcLD27dun9evX67vvvlNycrL+8Y9/KCQkRMePH7f3FNHEnn76aR07dkw//fSTli1bZu/pAAAAXFG4Pr76cH0MAK0TOf3qc7lzOkX0q8j06dPl7OysjIwMDRo0SL6+voqIiNDWrVt15MgRzZ8/X4MHD5bBYLC6LVy4UJJUXl6uOXPmyMfHRy4uLrrpppu0Zs0a0zhZWVm688475eLioq5du2ru3Lmqqqoy7R88eLCeeOIJPfHEE+rYsaPc3d21YMEC00NjGzKHbt26yWg0mvr8xz/+IYPBoNGjRzd4HEn6+eefNWnSJHXq1EnXXHONIiIitH//ftP+lJQU09gODg7y9vbWM888o5qaGlPMM888o9/97ne65ppr1L17dyUkJKiystK0f+HCherbt6/Z/xfbt2+XwWDQL7/8YhqnY8eOZjEHDx6UwWBQfn6+1WPO9csvv8hgMGj79u0WsR06dFDnzp310EMPyWAwaNOmTRbHAwAAXI24Pub6mOtjAGgdyOnk9ObO6dzO5Spx/PhxbdmyRYsXL1bbtm3N9nl5eenBBx9Uamqq9u/fb/rHMHbsWIWGhurpp5+WJLVv316SNGnSJGVnZ2v58uXq06ePCgsLVVpaKkk6cuSIRowYoUceeUTr1q3TN998o2nTpsnV1dX0y0CS/vznP2vKlCnavXu3cnJy9Nhjj8nPz0/Tpk3T+++/r4qKinrncK6amho99dRTVvfVN44kPfLII9q/f78++OADdejQQc8884xGjBihr7/+Wk5OTpKkDh066Ntvv1V1dbV27typ+++/X4MHD1ZERIQk6dprr1VKSoq8vb3173//W9OmTdO1116rOXPmXNz/Wc0gNzdXH374ob2nAQAAcMXg+pjrY66PAaB1IKeT0y9HTqeIfpXYv3+/amtrFRAQYHV/QECAfv75Z1VXV8vLy0uS5OzsrPbt25teS9K+ffv017/+VZmZmbrrrrskSd27dzftT0pKko+Pj1asWCGDwaBevXrpxx9/1DPPPKP//d//VZs2Z7/84OPjo9dee00Gg0E9e/bUv//9b7322muaNm2aOnfubOrP2hzO9+c//1lnzpzRqFGjdPLkSbN99Y1T94vks88+U2hoqCTp3XfflY+PjzZt2qT/+Z//kSQZDAbT+P7+/mrTpo3ZX9AWLFhg+u9u3brpqaeeUmpq6hX1CyUuLk6zZ89WQkKCvacCAABwReD6mOtjro/Rol3uZ7I1tYt4xhtgCzmdnH45cjpFdEiS6eseBoOh3rj8/Hw5ODho0KBBVvcXFBQoJCTErJ/+/fvr5MmT+uGHH+Tr6ytJ+v3vf28WExISoldffVXV1dVycHBo8Lx/++03LViwQMnJyUpLS7PYX984BQUFcnR0VL9+/Uz73d3d1bNnTxUUFJjaTpw4ofbt26u6utr0tZ6QkBDT/r/97W8yGo367rvvdPLkSVVVValDhw5m8/j3v/9t9lfD6upqi7nWjVPn3K/gnOuGG26QwWCQu7u7Bg8erKVLl8rR0fY/5U2bNun777/XU089xYcEALja8YEbaDCuj8/i+hgA0NKR088ip18a7ol+lbjxxhtlMBj09ddfW93/zTffqFOnTvLw8Ki3n/O/FnO+2tpai19KDf1ldTFeeeUV9ezZUyNHjmz0sbb+wZ5/Dtdee63y8/P15Zdf6sMPP1RKSopSUlIkSZ9//rnuv/9+RURE6KOPPlJeXp7mz59v+mpOnZ49eyo/P9+0vfXWWxbj1o1Tt6Wnp1ud344dO5SXl6e1a9cqOztbsbGxNs+xsrJSc+bMsfqVJgAAgKsZ18eWuD4GALRE5HRL5PSmRxH9KuHu7q5hw4YpKSlJp0+fNttXUlKid999V5GRkRf8R3/LLbeopqZGWVlZVvcHBgZq165dZv9Yd+3apWuvvVbXX3+9qe3zzz83O+7zzz/XTTfd1Ki/yBUXF+vVV1/V0qVLbcbUN05gYKCqqqq0e/du0/5jx45p3759Zl8BatOmjW688UbddNNNuueee3Tvvfea/gL42Wefyc/PT/Pnz1dwcLBuuukmHTp0yGIezs7OuvHGG03bue/F+ePUbX5+flbPyd/fXzfeeKP+8Ic/KCoqSnl5eTbPf9WqVWrfvr2ioqJsxgCAdParif7+/nJ1dVVQUJB27NhRb3xWVpaCgoLk6uqq7t27Kzk52SImLS1NgYGBcnFxUWBgoDZu3Gi2/9NPP9XIkSPl7e1d70NgCgoKdN9998nNzU3XXnutfv/736uoqOiizxUAJK6PrY3D9TEAoCUip1uOQ05vehTRryIrVqxQeXm5hg8frk8//VSHDx/WJ598omHDhun666/X4sWLL9hHt27d9PDDD2vy5MnatGmTCgsLtX37dv31r3+VJMXExOjw4cN68skn9c0332jz5s169tlnFRcXZ7o3lCQdPnxYcXFx+vbbb7V+/Xr96U9/0syZMxt1PitXrtSYMWN0++2324ypb5ybbrpJo0aN0rRp07Rz507t3btXDz30kK6//nqNGjXK1Edtba1KSkpUXFysHTt26JNPPlGvXr0knf1rZ1FRkTZs2KADBw5o+fLlFkWiplZeXq4zZ85o//792rx5s2655RabsS+//LKWLl3aLH8RBdB6pKamatasWZo/f77y8vIUFhamiIgIm4XqwsJCjRgxQmFhYcrLy9O8efM0Y8YMs68YZmdnKzIyUlFRUdq7d6+ioqI0YcIEs4u4U6dOqU+fPlqxYoXNuR04cEADBgxQr169tH37du3du1cJCQlydXVtujcAwFWL62OujwEArQM5nZze3Lgn+lXkpptuUk5OjhYuXKjIyEgdO3ZMXl5eGj16tJ599lmzhxvUZ9WqVZo3b55iYmJ07Ngx+fr6at68eZKk66+/Xunp6Zo9e7b69Omjzp07a8qUKWYPIpDOPu349OnTuvPOO+Xg4KAnn3xSjz32WKPOp6am5oK/BC80zttvv62ZM2fq3nvvVUVFhQYOHKj09HTTU4olqaysTF27dpXBYFCXLl103333mZ66PGrUKMXGxuqJJ55QeXm57rnnHiUkJJg9lbmp1T3wwd3dXX/4wx9kNBptxg4ZMkR/+MMfmm0uAFqHZcuWacqUKZo6daokyWg0asuWLVq1apUSExMt4pOTk+Xr62v6/RMQEKCcnBwtXbpU48aNM/UxbNgwxcfHS5Li4+OVlZUlo9Go9evXS5IiIiJMT323Zf78+RoxYoRefvllU9u5D/cBgEvB9THXxwCA1oGcTk5vboZaWzfJuYqVlZXJzc1NJ06csLhZ/pkzZ1RYWGj6yjsab/Dgwerbt2+9/xBa0jityUX/fPOgOqBB6ssv9lJRUaFrrrlG//d//6cxY8aY2mfOnKn8/HyrX2UcOHCgbrvtNr3++uumto0bN2rChAn67bff5OTkJF9fX8XGxprdw+61116T0Wi0+hVAg8GgjRs3avTo0aa2mpoaubm5ac6cOdq5c6fy8vLk7++v+Ph4s7hzlZeXq7y83PS6rKxMPj4+V9R7blf8vsaFXMTPyJn2Pirs/6r8r+8iV0c7r+71vs2+418kro+vTPVdG1+JOb214z0/DzkdF9LIn5ErKp9L5PQrZJzWoilyOrdzAQDgKlZaWqrq6mp5enqatXt6eqqkpMTqMSUlJVbjq6qqVFpaWm+MrT6tOXr0qE6ePKmXXnpJd999tzIyMjRmzBiNHTvW5n0KExMT5ebmZtp8fHwaPB4AAAAAANZQRAcAAFafMl/fveUa8lT6xvZ5vpqaGkn//9cI+/btq7lz5+ree++1+iBT6extY06cOGHaDh8+3ODxAAAAAACwhnui47Lbvn17qxoHAFoyDw8POTg4WKwQP3r0qMVK8jpeXl5W4x0dHeXu7l5vjK0+bc3N0dFRgYGBZu0BAQHauXOn1WNcXFzk4uLS4DEA4ErA9TEAAK0DOb31YiU6AABXMWdnZwUFBSkzM9OsPTMzU6GhoVaPCQkJsYjPyMhQcHCw6SE1tmJs9WlrbnfccYe+/fZbs/Z9+/bJz8+vwf0AAAAAAHApWIkOAMBVLi4uTlFRUQoODlZISIhWr16toqIiRUdHSzp7i5QjR45o3bp1kqTo6GitWLFCcXFxmjZtmrKzs7VmzRqtX7/e1OfMmTM1cOBALVmyRKNGjdLmzZu1detWsxXkJ0+e1HfffWd6XVhYqPz8fHXu3Fm+vr6SpNmzZysyMlIDBw7UkCFD9Mknn+jDDz9k5QUAAAAA4LKhiH6R6u7TCrQm/FwDV6fIyEgdO3ZMixYtUnFxsXr37q309HTTau/i4mIVFRWZ4v39/ZWenq7Y2FitXLlS3t7eWr58ucaNG2eKCQ0N1YYNG7RgwQIlJCSoR48eSk1NVb9+/UwxOTk5GjJkiOl1XFycJOnhhx9WSkqKJGnMmDFKTk5WYmKiZsyYoZ49eyotLU0DBgxozrcEQGP8v2ci/L//AVoNro0BXFVqayTVqoZ8jlaoKXI6RfRGcnZ2Vps2bfTjjz+qS5cucnZ2btRD0oArUW1trSoqKvTTTz+pTZs2cnZ2tveUAFxmMTExiomJsbqvrqB9rkGDBmnPnj319jl+/HiNHz/e5v7BgwebHkhan8mTJ2vy5MkXjANgH05nSmUoL9NPpzqrSzsH2fXS+MwZOw6O1oJrYwBXI+ff/qs2p4/rx587qIubq5zbiJyOFq8pczpF9EZq06aN/P39VVxcrB9//NHe0wGa1DXXXCNfX1+1acPjEgAAQMM4VJ/RDfmv6oe+T+mgSwf7TuZUoX3HR6vCtTGAq0mb2ir5f5Gg4l6T9WOXvlIbO5cMyeloQk2R0ymiXwRnZ2f5+vqqqqpK1dXV9p4O0CQcHBzk6OjINysAAECjtf+lQDfteEKVrh72Xbb2RI79xkarwrUxgKuR85lS+ea/oirnDqp2upacjlahqXI6RfSLZDAY5OTkJCcnJ3tPBQAAALA7h+ozcjj1g30n4epq3/EBAGjhDKqVU8UJOVWcsO9EyOm4wvC9NAAAAAAAAAAAbKCIDgAAAAAAAACADRTRAQAAAAAAAACwgSI6AAAAAAAAAAA2UEQHAAAAAAAAAMAGiugAAAAAAAAAANhAER0AAAAAAAAAABsoogMAAAAAAAAAYANFdAAAAAAAAAAAbKCIDgAAAAAAAACADRTRAQAAAAAAAACwgSI6AAAAAACtRFJSkvz9/eXq6qqgoCDt2LGj3visrCwFBQXJ1dVV3bt3V3JyskVMWlqaAgMD5eLiosDAQG3cuLHR4548eVJPPPGEbrjhBrVt21YBAQFatWrVpZ0sAACXCUV0AAAAAABagdTUVM2aNUvz589XXl6ewsLCFBERoaKiIqvxhYWFGjFihMLCwpSXl6d58+ZpxowZSktLM8VkZ2crMjJSUVFR2rt3r6KiojRhwgTt3r27UePGxsbqk08+0TvvvKOCggLFxsbqySef1ObNm5vvDQEAoIlQRAcAAAAAoBVYtmyZpkyZoqlTpyogIEBGo1E+Pj42V3wnJyfL19dXRqNRAQEBmjp1qiZPnqylS5eaYoxGo4YNG6b4+Hj16tVL8fHxGjp0qIxGY6PGzc7O1sMPP6zBgwerW7dueuyxx9SnTx/l5OQ02/sBAEBToYgOAAAAAEALV1FRodzcXIWHh5u1h4eHa9euXVaPyc7OtogfPny4cnJyVFlZWW9MXZ8NHXfAgAH64IMPdOTIEdXW1mrbtm3at2+fhg8fbnVu5eXlKisrM9sAALAXiugAAAAAALRwpaWlqq6ulqenp1m7p6enSkpKrB5TUlJiNb6qqkqlpaX1xtT12dBxly9frsDAQN1www1ydnbW3XffraSkJA0YMMDq3BITE+Xm5mbafHx8GvAuAADQPOxeRG/MQ0+Ki4s1ceJE9ezZU23atNGsWbPq7XvDhg0yGAwaPXp0004aAAAAAIArkMFgMHtdW1tr0Xah+PPbG9LnhWKWL1+uzz//XB988IFyc3P16quvKiYmRlu3brU6r/j4eJ04ccK0HT582OY5AADQ3BztOXjdw0eSkpLUv39/vfHGG4qIiNDXX38tX19fi/jy8nJ16dJF8+fP12uvvVZv34cOHdLTTz+tsLCw5po+AAAAAABXBA8PDzk4OFisOj969KjFKvE6Xl5eVuMdHR3l7u5eb0xdnw0Z9/Tp05o3b542btyoe+65R5J06623Kj8/X0uXLtVdd91lMTcXFxe5uLg09PQBAGhWdl2J3tiHnnTr1k2vv/66Jk2aJDc3N5v9VldX68EHH9Rzzz2n7t27N9f0AQAAAAC4Ijg7OysoKEiZmZlm7ZmZmQoNDbV6TEhIiEV8RkaGgoOD5eTkVG9MXZ8NGbeyslKVlZVq08a8BOHg4KCamppGnikAAJef3Vai1z18ZO7cuWbt9T30pKEWLVqkLl26aMqUKfXeHgYAAAAAgNYiLi5OUVFRCg4OVkhIiFavXq2ioiJFR0dLOnuLlCNHjmjdunWSpOjoaK1YsUJxcXGaNm2asrOztWbNGq1fv97U58yZMzVw4EAtWbJEo0aN0ubNm7V161bt3LmzweN26NBBgwYN0uzZs9W2bVv5+fkpKytL69at07Jlyy7jOwQAwMWxWxH9Yh560hCfffaZ1qxZo/z8/AYfU15ervLyctNrnvoNAAAAAGhpIiMjdezYMS1atEjFxcXq3bu30tPT5efnJ+nsc8aKiopM8f7+/kpPT1dsbKxWrlwpb29vLV++XOPGjTPFhIaGasOGDVqwYIESEhLUo0cPpaamql+/fg0eVzr7zLL4+Hg9+OCDOn78uPz8/LR48WJToR0AgCuZXe+JLjX+oSf1+fXXX/XQQw/pzTfflIeHR4OPS0xM1HPPPXdRYwIAAAAAcKWIiYlRTEyM1X0pKSkWbYMGDdKePXvq7XP8+PEaP378RY8rnb23+ttvv11vHwAAXKnsVkS/mIeeXMiBAwd08OBBjRw50tRWd381R0dHffvtt+rRo4fFcfHx8YqLizO9Lisrk4+Pz0XNAQAAAAAAAADQetitiH7uw0fGjBljas/MzNSoUaMuqs9evXrp3//+t1nbggUL9Ouvv+r111+3WRjnqd8AAAAAAAAAAGvsejuXxj70RJLpXucnT57UTz/9pPz8fDk7OyswMFCurq7q3bu32RgdO3aUJIt2AAAAAAAAAAAuxK5F9MY+9ESSbrvtNtN/5+bm6r333pOfn58OHjx4OacOAAAAAAAAALgK2P3Boo196EltbW2j+rfWBwAAAAAAAAAADdHG3hMAAAAAAAAAAOBKRREdAAAAAAAAAAAbKKIDAAAAAAAAAGADRXQAAAAAAAAAAGygiA4AAAAAAAAAgA0U0QEAAAAAAAAAsIEiOgAAUFJSkvz9/eXq6qqgoCDt2LGj3visrCwFBQXJ1dVV3bt3V3JyskVMWlqaAgMD5eLiosDAQG3cuNFs/6effqqRI0fK29tbBoNBmzZtqnfMxx9/XAaDQUajsbGnBwAAAADARaOIDgDAVS41NVWzZs3S/PnzlZeXp7CwMEVERKioqMhqfGFhoUaMGKGwsDDl5eVp3rx5mjFjhtLS0kwx2dnZioyMVFRUlPbu3auoqChNmDBBu3fvNsWcOnVKffr00YoVKy44x02bNmn37t3y9va+9BMGAAAAAKARKKIDAHCVW7ZsmaZMmaKpU6cqICBARqNRPj4+WrVqldX45ORk+fr6ymg0KiAgQFOnTtXkyZO1dOlSU4zRaNSwYcMUHx+vXr16KT4+XkOHDjVbRR4REaEXXnhBY8eOrXd+R44c0RNPPKF3331XTk5OTXLOAAAAAAA0FEV0AACuYhUVFcrNzVV4eLhZe3h4uHbt2mX1mOzsbIv44cOHKycnR5WVlfXG2OrTlpqaGkVFRWn27Nm6+eabG3UsAAAAAABNwdHeEwAAAPZTWlqq6upqeXp6mrV7enqqpKTE6jElJSVW46uqqlRaWqquXbvajLHVpy1LliyRo6OjZsyY0aD48vJylZeXm16XlZU1ajwAAAAAAM7HSnQAACCDwWD2ura21qLtQvHntze2z/Pl5ubq9ddfV0pKSoOPS0xMlJubm2nz8fFp8HgAAAAAAFhDER0AgKuYh4eHHBwcLFaIHz161GIleR0vLy+r8Y6OjnJ3d683xlaf1uzYsUNHjx6Vr6+vHB0d5ejoqEOHDumpp55St27drB4THx+vEydOmLbDhw83eDwAAAAAAKyhiA4AwFXM2dlZQUFByszMNGvPzMxUaGio1WNCQkIs4jMyMhQcHGx68KetGFt9WhMVFaUvv/xS+fn5ps3b21uzZ8/Wli1brB7j4uKiDh06mG0AAAAAAFwK7okOAMBVLi4uTlFRUQoODlZISIhWr16toqIiRUdHSzq7uvvIkSNat26dJCk6OlorVqxQXFycpk2bpuzsbK1Zs0br16839Tlz5kwNHDhQS5Ys0ahRo7R582Zt3bpVO3fuNMWcPHlS3333nel1YWGh8vPz1blzZ/n6+srd3d20sr2Ok5OTvLy81LNnz+Z8SwAAAAAAMKGIDgDAVS4yMlLHjh3TokWLVFxcrN69eys9PV1+fn6SpOLiYhUVFZni/f39lZ6ertjYWK1cuVLe3t5avny5xo0bZ4oJDQ3Vhg0btGDBAiUkJKhHjx5KTU1Vv379TDE5OTkaMmSI6XVcXJwk6eGHH1ZKSkoznzUAAAAAAA1DER0AACgmJkYxMTFW91kraA8aNEh79uypt8/x48dr/PjxNvcPHjzY9EDShjp48GCj4gEAAAAAuFTcEx0AAAAAAAAAABsoogMAAAAAAAAAYANFdAAAAAAAAAAAbKCIDgAAAAAAAACADRTRAQAAAAAAAACwgSI6AAAAAAAAAAA2UEQHAAAAAAAAAMAGiugAAAAAAAAAANhAER0AAAAAAAAAABsoogMAAAAAAAAAYANFdAAAAAAAAAAAbKCIDgAAAAAAAACADRTRAQAAAAAAAACwgSI6AAAAAAAAAAA2UEQHAAAAAAAAAMAGiugAAAAAAAAAANhAER0AAAAAAAAAABsoogMAAAAAAAAAYANFdAAAAAAAAAAAbKCIDgAAAAAAAACADRTRAQAAAAAAAACwwdHeE0ALsNDN3jO4NAtP2HsGAAAAAAAAAFoou69ET0pKkr+/v1xdXRUUFKQdO3bYjC0uLtbEiRPVs2dPtWnTRrNmzbKIefPNNxUWFqZOnTqpU6dOuuuuu/TFF1804xkAAAAAAAAAAForuxbRU1NTNWvWLM2fP195eXkKCwtTRESEioqKrMaXl5erS5cumj9/vvr06WM1Zvv27XrggQe0bds2ZWdny9fXV+Hh4Tpy5EhzngoAAAAAAAAAoBWyaxF92bJlmjJliqZOnaqAgAAZjUb5+Pho1apVVuO7deum119/XZMmTZKbm/VbjLz77ruKiYlR37591atXL7355puqqanRP/7xj+Y8FQAAAAAAAABAK2S3InpFRYVyc3MVHh5u1h4eHq5du3Y12Ti//fabKisr1blz5ybrEwAAAAAAAABwdbDbg0VLS0tVXV0tT09Ps3ZPT0+VlJQ02Thz587V9ddfr7vuustmTHl5ucrLy02vy8rKmmx8AAAAAAAAAEDLZfcHixoMBrPXtbW1Fm0X6+WXX9b69ev1/vvvy9XV1WZcYmKi3NzcTJuPj0+TjA8AAAAAAAAAaNnsVkT38PCQg4ODxarzo0ePWqxOvxhLly7Viy++qIyMDN166631xsbHx+vEiROm7fDhw5c8PgAAAAAAAACg5bNbEd3Z2VlBQUHKzMw0a8/MzFRoaOgl9f3KK6/o+eef1yeffKLg4OALxru4uKhDhw5mGwAAAAAAAAAAdrsnuiTFxcUpKipKwcHBCgkJ0erVq1VUVKTo6GhJZ1eIHzlyROvWrTMdk5+fL0k6efKkfvrpJ+Xn58vZ2VmBgYGSzt7CJSEhQe+99566detmWunevn17tW/f/vKeIAAAAAAAAACgRbNrET0yMlLHjh3TokWLVFxcrN69eys9PV1+fn6SpOLiYhUVFZkdc9ttt5n+Ozc3V++99578/Px08OBBSVJSUpIqKio0fvx4s+OeffZZLVy4sFnPBwAAAAAAAADQuti1iC5JMTExiomJsbovJSXFoq22trbe/uqK6QAAAAAAAAAAXCq73RMdAAAAAAAAAIArHUV0AAAAAAAAAABsoIgOAAAAAAAAAIANFNEBAAAAAAAAALCBIjoAAFBSUpL8/f3l6uqqoKAg7dixo974rKwsBQUFydXVVd27d1dycrJFTFpamgIDA+Xi4qLAwEBt3LjRbP+nn36qkSNHytvbWwaDQZs2bTLbX1lZqWeeeUa33HKL2rVrJ29vb02aNEk//vjjJZ8vAAAAAAANRREdAICrXGpqqmbNmqX58+crLy9PYWFhioiIUFFRkdX4wsJCjRgxQmFhYcrLy9O8efM0Y8YMpaWlmWKys7MVGRmpqKgo7d27V1FRUZowYYJ2795tijl16pT69OmjFStWWB3nt99+0549e5SQkKA9e/bo/fff1759+3Tfffc17RsAAAAAAEA9HO09AQAAYF/Lli3TlClTNHXqVEmS0WjUli1btGrVKiUmJlrEJycny9fXV0ajUZIUEBCgnJwcLV26VOPGjTP1MWzYMMXHx0uS4uPjlZWVJaPRqPXr10uSIiIiFBERYXNebm5uyszMNGv705/+pDvvvFNFRUXy9fW95HMHAAAAAOBCWIkOAMBVrKKiQrm5uQoPDzdrDw8P165du6wek52dbRE/fPhw5eTkqLKyst4YW3021IkTJ2QwGNSxY0er+8vLy1VWVma2AQAAAABwKSiiAwBwFSstLVV1dbU8PT3N2j09PVVSUmL1mJKSEqvxVVVVKi0trTfGVp8NcebMGc2dO1cTJ05Uhw4drMYkJibKzc3NtPn4+Fz0eAAAAAAASBTRAQCAJIPBYPa6trbWou1C8ee3N7bP+lRWVur+++9XTU2NkpKSbMbFx8frxIkTpu3w4cMXNR4AAAAAAHW4JzoAAFcxDw8POTg4WKwQP3r0qMVK8jpeXl5W4x0dHeXu7l5vjK0+61NZWakJEyaosLBQ//znP22uQpckFxcXubi4NHoMAAAAAABsYSU6AABXMWdnZwUFBVk8wDMzM1OhoaFWjwkJCbGIz8jIUHBwsJycnOqNsdWnLXUF9P3792vr1q2mIj0AAAAAAJcLK9EBALjKxcXFKSoqSsHBwQoJCdHq1atVVFSk6OhoSWdvkXLkyBGtW7dOkhQdHa0VK1YoLi5O06ZNU3Z2ttasWaP169eb+pw5c6YGDhyoJUuWaNSoUdq8ebO2bt2qnTt3mmJOnjyp7777zvS6sLBQ+fn56ty5s3x9fVVVVaXx48drz549+uijj1RdXW1a3d65c2c5OztfjrcHAAAAAHCVo4gOAMBVLjIyUseOHdOiRYtUXFys3r17Kz09XX5+fpKk4uJiFRUVmeL9/f2Vnp6u2NhYrVy5Ut7e3lq+fLnGjRtnigkNDdWGDRu0YMECJSQkqEePHkpNTVW/fv1MMTk5ORoyZIjpdVxcnCTp4YcfVkpKin744Qd98MEHkqS+ffuazXnbtm0aPHhwU78VAAAAAABYoIgOAAAUExOjmJgYq/tSUlIs2gYNGqQ9e/bU2+f48eM1fvx4m/sHDx5seiCpNd26dat3PwAAAAAAlwP3RAcAAAAAAAAAwAaK6AAAAAAAAAAA2EARHQAAAAAAAAAAGyiiAwAAAAAAAABgA0V0AAAAAAAAAABsoIgOAAAAAAAAAIANFNEBAAAAAAAAALCBIjoAAAAAAAAAADZQRAcAAAAAoJVISkqSv7+/XF1dFRQUpB07dtQbn5WVpaCgILm6uqp79+5KTk62iElLS1NgYKBcXFwUGBiojRs3XtS4BQUFuu++++Tm5qZrr71Wv//971VUVHTxJwsAwGVCER0AAAAAgFYgNTVVs2bN0vz585WXl6ewsDBFRETYLFQXFhZqxIgRCgsLU15enubNm6cZM2YoLS3NFJOdna3IyEhFRUVp7969ioqK0oQJE7R79+5GjXvgwAENGDBAvXr10vbt27V3714lJCTI1dW1+d4QAACaiKG2trbW3pO40pSVlcnNzU0nTpxQhw4d7D0d+1voZu8ZXJqFJ+w9g9aPnxGgQcgvlx/v+Xn4fY0L4WcEaJArNb/069dPt99+u1atWmVqCwgI0OjRo5WYmGgR/8wzz+iDDz5QQUGBqS06Olp79+5Vdna2JCkyMlJlZWX6+9//boq5++671alTJ61fv77B495///1ycnLSX/7yl4s6tyv1Pbcbfl83u25zP7b3FC7JQdeJ9p7CpWkBPyNoHRqaX1iJDgAAAABAC1dRUaHc3FyFh4ebtYeHh2vXrl1Wj8nOzraIHz58uHJyclRZWVlvTF2fDRm3pqZGH3/8sX73u99p+PDhuu6669SvXz9t2rTJ5vmUl5errKzMbAMAwF4oogMAAAAA0MKVlpaqurpanp6eZu2enp4qKSmxekxJSYnV+KqqKpWWltYbU9dnQ8Y9evSoTp48qZdeekl33323MjIyNGbMGI0dO1ZZWVlW55aYmCg3NzfT5uPj08B3AgCApkcRHQAAAACAVsJgMJi9rq2ttWi7UPz57Q3ps76YmpoaSdKoUaMUGxurvn37au7cubr33nutPshUkuLj43XixAnTdvjwYZvnAABAc3O09wQAAAAAAMCl8fDwkIODg8Wq86NHj1qsEq/j5eVlNd7R0VHu7u71xtT12ZBxPTw85OjoqMDAQLOYgIAA7dy50+rcXFxc5OLiUt8pAwBw2bASHQAAAACAFs7Z2VlBQUHKzMw0a8/MzFRoaKjVY0JCQiziMzIyFBwcLCcnp3pj6vpsyLjOzs6644479O2335rF7Nu3T35+fo08UwAALj9WogMAAAAA0ArExcUpKipKwcHBCgkJ0erVq1VUVKTo6GhJZ2+RcuTIEa1bt06SFB0drRUrViguLk7Tpk1Tdna21qxZo/Xr15v6nDlzpgYOHKglS5Zo1KhR2rx5s7Zu3Wq2gvxC40rS7NmzFRkZqYEDB2rIkCH65JNP9OGHH2r79u2X580BAOASUEQHAAAAAKAViIyM1LFjx7Ro0SIVFxerd+/eSk9PN632Li4uVlFRkSne399f6enpio2N1cqVK+Xt7a3ly5dr3LhxppjQ0FBt2LBBCxYsUEJCgnr06KHU1FT169evweNK0pgxY5ScnKzExETNmDFDPXv2VFpamgYMGHAZ3hkAAC6NobbuqSEwKSsrk5ubm06cOKEOHTrYezr2t9DN3jO4NAtP2HsGrR8/I0CDkF8uP97z8/D7GhfCzwjQIOSXy4/3/Dz8vm523eZ+bO8pXJKDrhPtPYVL0wJ+RtA6NDS/cE90AAAAAAAAAABsoIgOAAAAAAAAAIANFNEBAAAAAAAAALCBIjoAAAAAAAAAADZQRAcAAAAAAAAAwAbHxh5w8OBB7dixQwcPHtRvv/2mLl266LbbblNISIhcXV0bPYGkpCS98sorKi4u1s033yyj0aiwsDCrscXFxXrqqaeUm5ur/fv3a8aMGTIajRZxaWlpSkhI0IEDB9SjRw8tXrxYY8aMafTcAAC4EjV1LgYAAPZBTgcAoGVocBH9vffe0/Lly/XFF1/ouuuu0/XXX6+2bdvq+PHjOnDggFxdXfXggw/qmWeekZ+fX4P6TE1N1axZs5SUlKT+/fvrjTfeUEREhL7++mv5+vpaxJeXl6tLly6aP3++XnvtNat9ZmdnKzIyUs8//7zGjBmjjRs3asKECdq5c6f69evX0NMFAOCK0xy5GAAAXH7kdAAAWpYG3c7l9ttv17Jly/TQQw/p4MGDKikpUW5urnbu3Kmvv/5aZWVl2rx5s2pqahQcHKz/+7//a9Dgy5Yt05QpUzR16lQFBATIaDTKx8dHq1atshrfrVs3vf7665o0aZLc3NysxhiNRg0bNkzx8fHq1auX4uPjNXToUKsr1gEAaCmaKxcDAIDLi5wOAEDL06CV6M8//7zuuecem/tdXFw0ePBgDR48WC+88IIKCwsv2GdFRYVyc3M1d+5cs/bw8HDt2rWrIdOyKjs7W7GxsWZtw4cPp4gOAGjRmiMXAwCAy4+cDgBAy9OgInp9Cf58Hh4e8vDwuGBcaWmpqqur5enpadbu6empkpKSBo93vpKSkkb3WV5ervLyctPrsrKyix4fAIDm0By5GAAAXH7kdAAAWp4G3c7lXIcOHbLaXllZabGqvCEMBoPZ69raWou25u4zMTFRbm5ups3Hx+eSxgcAoDk1dS4GAAD2QU4HAKBlaHQRfcCAAfr222/N2nJyctS3b1999NFHDe7Hw8NDDg4OFivEjx49arGSvDG8vLwa3Wd8fLxOnDhh2g4fPnzR4wMA0NyaKhcDAAD7IqcDANAyNLqIPnnyZIWFhSkvL0+VlZWKj49XWFiY7rvvPu3Zs6fB/Tg7OysoKEiZmZlm7ZmZmQoNDW3stExCQkIs+szIyKi3TxcXF3Xo0MFsAwDgStVUuRgAANgXOR0AgJahQfdEP9dzzz2njh07asiQIbr++utlMBj06aef6o477mj04HFxcYqKilJwcLBCQkK0evVqFRUVKTo6WtLZFeJHjhzRunXrTMfk5+dLkk6ePKmffvpJ+fn5cnZ2VmBgoCRp5syZGjhwoJYsWaJRo0Zp8+bN2rp1q3bu3Nno+QEAcCVqylwMAADsh5wOAEDL0OgiuiTFxsaqQ4cOio6OVmpq6kUn+MjISB07dkyLFi1ScXGxevfurfT0dPn5+UmSiouLVVRUZHbMbbfdZvrv3Nxcvffee/Lz89PBgwclSaGhodqwYYMWLFighIQE9ejRQ6mpqerXr99FzREAgCtRU+ViAABgX+R0AACufI0uoi9fvtz03wMHDtTEiRMVHx+vTp06SZJmzJjRqP5iYmIUExNjdV9KSopFW21t7QX7HD9+vMaPH9+oeQAA0FI0dS4GAAD2QU4HAKBlaHQR/bXXXjN73bVrV1Ox22AwkOQBAGhm5GIAAFoHcjoAAC1Dox8sWlhYaHP7/vvvm2OOAADgHM2Ri5OSkuTv7y9XV1cFBQVpx44d9cZnZWUpKChIrq6u6t69u5KTky1i0tLSFBgYKBcXFwUGBmrjxo1m+z/99FONHDlS3t7eMhgM2rRpk0UftbW1Wrhwoby9vdW2bVsNHjxY//nPfy7qHAEAuNLw+RoAgJah0UX0OhUVFfr2229VVVXVlPMBAAAN1FS5ODU1VbNmzdL8+fOVl5ensLAwRUREWDyXpE5hYaFGjBihsLAw5eXlad68eZoxY4bS0tJMMdnZ2YqMjFRUVJT27t2rqKgoTZgwQbt37zbFnDp1Sn369NGKFStszu3ll1/WsmXLtGLFCv3rX/+Sl5eXhg0bpl9//fWSzhkAgCsJn68BALiyNbqI/ttvv2nKlCm65pprdPPNN5s+YM+YMUMvvfRSk08QAACYa+pcvGzZMk2ZMkVTp05VQECAjEajfHx8tGrVKqvxycnJ8vX1ldFoVEBAgKZOnarJkydr6dKlphij0ahhw4YpPj5evXr1Unx8vIYOHSqj0WiKiYiI0AsvvKCxY8daHae2tlZGo1Hz58/X2LFj1bt3b/35z3/Wb7/9pvfee6/R5wkAwJWGz9cAALQMjS6ix8fHa+/evdq+fbtcXV1N7XfddZdSU1ObdHIAAMBSU+biiooK5ebmKjw83Kw9PDxcu3btsnpMdna2Rfzw4cOVk5OjysrKemNs9WlNYWGhSkpKzPpxcXHRoEGDGtUPAABXKj5fAwDQMjT6waKbNm1Samqqfv/738tgMJjaAwMDdeDAgSadHAAAsNSUubi0tFTV1dXy9PQ0a/f09FRJSYnVY0pKSqzGV1VVqbS0VF27drUZY6tPW+PUHXd+P4cOHbJ6THl5ucrLy02vy8rKGjweAACXG5+vAQBoGRq9Ev2nn37SddddZ9F+6tQps6QPAACaR3Pk4vOPq62trbcva/Hntze2z6aYW2Jiotzc3Eybj49Po8cDAOBy4fM1AAAtQ6OL6HfccYc+/vhj0+u6xP7mm28qJCSk6WYGAACsaspc7OHhIQcHB4sV4kePHrVYAV7Hy8vLaryjo6Pc3d3rjbHVp61xJDWqn/j4eJ04ccK0HT58uMHjAQBwufH5GgCAlqHRt3NJTEzU3Xffra+//lpVVVV6/fXX9Z///EfZ2dnKyspqjjkCAIBzNGUudnZ2VlBQkDIzMzVmzBhTe2ZmpkaNGmX1mJCQEH344YdmbRkZGQoODpaTk5MpJjMzU7GxsWYxoaGhDZ6bv7+/vLy8lJmZqdtuu03S2Xu4Z2VlacmSJVaPcXFxkYuLS4PHAADAnvh8DQBAy9DoleihoaH67LPP9Ntvv6lHjx7KyMiQp6ensrOzFRQU1BxzBAAA52jqXBwXF6e33npLa9euVUFBgWJjY1VUVKTo6GhJZ1d3T5o0yRQfHR2tQ4cOKS4uTgUFBVq7dq3WrFmjp59+2hQzc+ZMZWRkaMmSJfrmm2+0ZMkSbd26VbNmzTLFnDx5Uvn5+crPz5d09kGi+fn5KioqknR2Nd6sWbP04osvauPGjfrqq6/0yCOP6JprrtHEiRMv4p0DAODKwudrAABahkavRJekW265RX/+85+bei4AAKCBmjIXR0ZG6tixY1q0aJGKi4vVu3dvpaeny8/PT5JUXFxsKmxLZ1eIp6enKzY2VitXrpS3t7eWL1+ucePGmWJCQ0O1YcMGLViwQAkJCerRo4dSU1PVr18/U0xOTo6GDBlieh0XFydJevjhh5WSkiJJmjNnjk6fPq2YmBj9/PPP6tevnzIyMnTttdc2ybkDAGBvfL4GAODK1+gienp6uhwcHDR8+HCz9i1btqimpkYRERFNNjkAAGCpOXJxTEyMYmJirO6rK2ifa9CgQdqzZ0+9fY4fP17jx4+3uX/w4MGmB5LaYjAYtHDhQi1cuLDeOAAAWiI+XwMA0DI0+nYuc+fOVXV1tUV7bW2t5s6d2ySTAgAAtpGLAQBoHcjpAAC0DI0uou/fv1+BgYEW7b169dJ3333XJJMCAAC2kYsBAGgdyOkAALQMjS6iu7m56fvvv7do/+6779SuXbsmmRQAALCNXAwAQOtATgcAoGVodBH9vvvu06xZs3TgwAFT23fffaennnpK9913X5NODgAAWCIXAwDQOpDTAQBoGRpdRH/llVfUrl079erVS/7+/vL391dAQIDc3d21dOnS5pgjAAA4B7kYAIDWgZwOAEDL4NjYA9zc3LRr1y5lZmZq7969atu2rW699VYNHDiwOeYHAADOQy4GAKB1IKcDANAyNLqILkkGg0Hh4eEKDw9v6vkAV6Vucz+29xQuyUFXe88AuPqQiwEAaB3I6QAAXPkadDuXDRs2NLjDw4cP67PPPrvoCQEAAEvkYgAAWgdyOgAALU+DiuirVq1Sr169tGTJEhUUFFjsP3HihNLT0zVx4kQFBQXp+PHjTT5RAACuZuRiAABaB3I6AAAtT4Nu55KVlaWPPvpIf/rTnzRv3jy1a9dOnp6ecnV11c8//6ySkhJ16dJFjz76qL766itdd911zT1vAACuKuRiAABaB3I6AAAtT4PviX7vvffq3nvv1bFjx7Rz504dPHhQp0+floeHh2677TbddtttatOmQQvbAQDARSAXAwDQOpDTAQBoWRr9YFF3d3eNGjWqOeYCAAAagFwMAEDrQE4HAKBl4E/bAAAAAAAAAADYQBEdAAAAAAAAAAAbKKIDAAAAAAAAAGADRXQAAAAAAAAAAGygiA4AAAAAAAAAgA2OjT1g7Nix9e5///33L3oyAADgwsjFAAC0DuR0AABahkavRN+0aZOcnZ3l5uYmNzc3ffzxx2rTpo3pNQAAaF7kYgAAWgdyOgAALUOjV6JL0vLly3XddddJkv72t7/p5ZdfVvfu3Zt0YgAAwDZyMXBl6jb3Y3tP4ZIcdLX3DICrDzkdAIArX6NXoru6uurMmTOSpNraWlVUVOj1119XdXV1k08OAABYIhcDANA6kNMBAGgZGl1E/93vfiej0aiSkhIZjUZ16NBBeXl5GjJkiP773/82xxwBAMA5yMUAALQO5HQAAFqGRhfRX3jhBa1evVrXX3+95s6dqyVLlmjbtm267bbbdNtttzXHHAEAwDnIxQAAtA7kdAAAWoZG3xP93nvv1ZEjR7Rv3z75+PjIy8tLkvT6668rNDS0yScIAADMkYsBAGgdyOkAALQMF/VgUTc3N91xxx0W7ZGRkZc8IQAAcGHkYgAAWgdyOgAAV75GF9E//fTTevcPHDjwoicDAAAujFwMAEDrQE4HAKBlaHQRffDgwTIYDJLOPj38XAaDgaeIAwDQzMjFAAC0DuR0AABahkY/WLRPnz7y9vZWQkKCDhw4oJ9//tm0HT9+vNETSEpKkr+/v1xdXRUUFKQdO3bUG5+VlaWgoCC5urqqe/fuSk5OtogxGo3q2bOn2rZtKx8fH8XGxurMmTONnhsAAFeips7FAADAPsjpAAC0DI0uoufl5en999/XkSNHdOeddyomJkb5+flyc3OTm5tbo/pKTU3VrFmzNH/+fOXl5SksLEwREREqKiqyGl9YWKgRI0YoLCxMeXl5mjdvnmbMmKG0tDRTzLvvvqu5c+fq2WefVUFBgdasWaPU1FTFx8c39lQBALgiNWUuBgAA9kNOBwCgZWh0EV2S7rjjDr355psqLCxUaGioRo0apddee63R/SxbtkxTpkzR1KlTFRAQIKPRKB8fH61atcpqfHJysnx9fWU0GhUQEKCpU6dq8uTJWrp0qSkmOztb/fv318SJE9WtWzeFh4frgQceUE5OzsWcKgAAV6SmysUAAMC+yOkAAFz5LqqILkmHDx/WK6+8opdeekm33367wsLCGnV8RUWFcnNzFR4ebtYeHh6uXbt2WT0mOzvbIn748OHKyclRZWWlJGnAgAHKzc3VF198IUn6/vvvlZ6ernvuuadR8wMA4Ep3qbkYAABcGcjpAABc2Rr9YNFNmzZp9erVysvLU1RUlP75z3/qpptuavTApaWlqq6ulqenp1m7p6enSkpKrB5TUlJiNb6qqkqlpaXq2rWr7r//fv30008aMGCAamtrVVVVpT/+8Y+aO3euzbmUl5ervLzc9LqsrKzR5wMAwOXSVLkYAADYFzkdAICWodFF9LFjx+qGG27QuHHjVFVVZXHrlWXLljWqv7onkdepra21aLtQ/Lnt27dv1+LFi5WUlKR+/frpu+++08yZM9W1a1clJCRY7TMxMVHPPfdco+YNAIC9NHUuBgAA9kFOBwCgZWh0EX3gwIEyGAz6z3/+Y7GvvuL3+Tw8POTg4GCx6vzo0aMWq83reHl5WY13dHSUu7u7JCkhIUFRUVGaOnWqJOmWW27RqVOn9Nhjj2n+/Plq08byDjbx8fGKi4szvS4rK5OPj0+DzwUAgMupqXIxAACwL3I6AAAtQ6OL6Nu3b2+SgZ2dnRUUFKTMzEyNGTPG1J6ZmalRo0ZZPSYkJEQffvihWVtGRoaCg4Pl5OQkSfrtt98sCuUODg6qra01rVo/n4uLi1xcXC7ldAAAuGyaKhcDAAD7IqcDANAyXPSDRb/77jtt2bJFp0+fliSbBer6xMXF6a233tLatWtVUFCg2NhYFRUVKTo6WtLZFeKTJk0yxUdHR+vQoUOKi4tTQUGB1q5dqzVr1ujpp582xYwcOVKrVq3Shg0bVFhYqMzMTCUkJOi+++6Tg4PDxZ4uAABXnKbIxQAAwP7I6QAAXNkavRL92LFjmjBhgrZt2yaDwaD9+/ere/fumjp1qjp27KhXX321wX1FRkbq2LFjWrRokYqLi9W7d2+lp6fLz89PklRcXKyioiJTvL+/v9LT0xUbG6uVK1fK29tby5cv17hx40wxCxYskMFg0IIFC3TkyBF16dJFI0eO1OLFixt7qgAAXJGaMhcDAAD7IacDANAyNHolemxsrJycnFRUVKRrrrnG1B4ZGalPPvmk0ROIiYnRwYMHVV5ertzcXA0cONC0LyUlxeLrbYMGDdKePXtUXl6uwsJC06r1Oo6Ojnr22Wf13Xff6fTp0yoqKtLKlSvVsWPHRs8NAIArUVPnYklKSkqSv7+/XF1dFRQUpB07dtQbn5WVpaCgILm6uqp79+5KTk62iElLS1NgYKBcXFwUGBiojRs3NnrckydP6oknntANN9ygtm3bKiAgwOKhawAAtFTNkdMBAEDTa3QRPSMjQ0uWLNENN9xg1n7TTTfp0KFDTTYxAABgXVPn4tTUVM2aNUvz589XXl6ewsLCFBERYfZtsHMVFhZqxIgRCgsLU15enubNm6cZM2YoLS3NFJOdna3IyEhFRUVp7969ioqK0oQJE7R79+5GjRsbG6tPPvlE77zzjunWb08++aQ2b97c6PMEAOBKw+drAABahkYX0U+dOmX2F/I6paWlPJwTAIDLoKlz8bJlyzRlyhRNnTpVAQEBMhqN8vHxsbniOzk5Wb6+vjIajQoICNDUqVM1efJkLV261BRjNBo1bNgwxcfHq1evXoqPj9fQoUNlNBobNW52drYefvhhDR48WN26ddNjjz2mPn36KCcnp9HnCQDAlYbP1wAAtAyNLqIPHDhQ69atM702GAyqqanRK6+8oiFDhjTp5AAAgKWmzMUVFRXKzc1VeHi4WXt4eLh27dpl9Zjs7GyL+OHDhysnJ0eVlZX1xtT12dBxBwwYoA8++EBHjhxRbW2ttm3bpn379mn48OFW51ZeXq6ysjKzDQCAKxWfrwEAaBka/WDRV155RYMHD1ZOTo4qKio0Z84c/ec//9Hx48f12WefNcccAQDAOZoyF5eWlqq6ulqenp5m7Z6eniopKbF6TElJidX4qqoqlZaWqmvXrjZj6vps6LjLly/XtGnTdMMNN8jR0VFt2rTRW2+9pQEDBlidW2Jiop577rmGnTwAAHbG52sAAFqGRq9EDwwM1Jdffqk777xTw4YN06lTpzR27Fjl5eWpR48ezTFHAABwjubIxQaDwex1bW2tRduF4s9vb0ifF4pZvny5Pv/8c33wwQfKzc3Vq6++qpiYGG3dutXqvOLj43XixAnTdvjwYZvnAACAvfH5GgCAlqHRK9ElycvLi1VeAADYUVPlYg8PDzk4OFisOj969KjFKvFzx7YW7+joKHd393pj6vpsyLinT5/WvHnztHHjRt1zzz2SpFtvvVX5+flaunSp7rrrLou5ubi4cA9ZAECLwudrAACufBdVRP/555+1Zs0aFRQUyGAwKCAgQI8++qg6d+7c1PMDAABWNFUudnZ2VlBQkDIzMzVmzBhTe2ZmpkaNGmX1mJCQEH344YdmbRkZGQoODpaTk5MpJjMzU7GxsWYxoaGhDR63srJSlZWVatPG/ItzDg4OqqmpadR5AgBwpeLzNQAAV75G384lKytL/v7+Wr58uX7++WcdP35cy5cvl7+/v7KysppjjgAA4BxNnYvj4uL01ltvae3atSooKFBsbKyKiooUHR0t6ewtUiZNmmSKj46O1qFDhxQXF6eCggKtXbtWa9as0dNPP22KmTlzpjIyMrRkyRJ98803WrJkibZu3apZs2Y1eNwOHTpo0KBBmj17trZv367CwkKlpKRo3bp1ZoV3AABaKj5fAwDQMjR6Jfr06dM1YcIErVq1Sg4ODpKk6upqxcTEaPr06frqq6+afJIAAOD/19S5ODIyUseOHdOiRYtUXFys3r17Kz09XX5+fpKk4uJiFRUVmeL9/f2Vnp6u2NhYrVy5Ut7e3lq+fLnGjRtnigkNDdWGDRu0YMECJSQkqEePHkpNTVW/fv0aPK4kbdiwQfHx8XrwwQd1/Phx+fn5afHixaZCOwAALRmfrwEAaBkMtXVPAmugtm3bKj8/Xz179jRr//bbb9W3b1+dPn26SSdoD2VlZXJzc9OJEyfUoUMHe0/H/ha62XsGl2bhCXvP4IK6zf3Y3lO4JAddJ9p7CpemBfyMoHVoqvxyNeTipkJOPw85vdmR0+2sBfyMoHUgp19+5PTzkNObHTndzlrAzwhah4bml0bfzuX2229XQUGBRXtBQYH69u3b2O4AAEAjkYsBAGgdyOkAALQMjS6iz5gxQzNnztTSpUu1c+dO7dy5U0uXLlVsbKxmzZqlL7/80rQBAICmRy4GAKB1aI6cnpSUJH9/f7m6uiooKEg7duyoNz4rK0tBQUFydXVV9+7dlZycbBGTlpamwMBAubi4KDAwUBs3brykcR9//HEZDAYZjcYGnxcAAPbU6HuiP/DAA5KkOXPmWN1nMBhUW1srg8Gg6urqS58hAAAwQy4GAKB1aOqcnpqaqlmzZikpKUn9+/fXG2+8oYiICH399dfy9fW1iC8sLNSIESM0bdo0vfPOO/rss88UExOjLl26mJ51kp2drcjISD3//PMaM2aMNm7cqAkTJmjnzp2mZ500ZtxNmzZp9+7d8vb2bvT7BQCAvTS6iF5YWNgc8wAAAA1ELgYAoHVo6py+bNkyTZkyRVOnTpUkGY1GbdmyRatWrVJiYqJFfHJysnx9fU0rwgMCApSTk6OlS5eaiuhGo1HDhg1TfHy8JCk+Pl5ZWVkyGo1av359o8Y9cuSInnjiCW3ZskX33HNPk547AADNqdFFdD8/v+aYBwAAaCByMQAArUNT5vSKigrl5uZq7ty5Zu3h4eHatWuX1WOys7MVHh5u1jZ8+HCtWbNGlZWVcnJyUnZ2tmJjYy1i6grvDR23pqZGUVFRmj17tm6++eaLPU0AAOyi0UX0Y8eOyd3dXZJ0+PBhvfnmmzp9+rTuu+8+hYWFNfkEAQCAOXIxAACtQ1Pm9NLSUlVXV8vT09Os3dPTUyUlJVaPKSkpsRpfVVWl0tJSde3a1WZMXZ8NHXfJkiVydHTUjBkzGnQ+5eXlKi8vN70uKytr0HEAADSHBj9Y9N///re6deum6667Tr169VJ+fr7uuOMOvfbaa1q9erWGDBmiTZs2NeNUAQC4upGLAQBoHZozpxsMBrPXdfdUb0z8+e0N6bO+mNzcXL3++utKSUmpdy7nSkxMlJubm2nz8fFp0HEAADSHBhfR58yZo1tuuUVZWVkaPHiw7r33Xo0YMUInTpzQzz//rMcff1wvvfRSc84VAICrGrkYAIDWoTlyuoeHhxwcHCxWnR89etRilXgdLy8vq/GOjo6mFfK2Yur6bMi4O3bs0NGjR+Xr6ytHR0c5Ojrq0KFDeuqpp9StWzerc4uPj9eJEydM2+HDhxv2RgAA0AwaXET/17/+pcWLF2vAgAFaunSpfvzxR8XExKhNmzZq06aNnnzySX3zzTfNOVcAAK5q5GIAAFqH5sjpzs7OCgoKUmZmpll7ZmamQkNDrR4TEhJiEZ+RkaHg4GA5OTnVG1PXZ0PGjYqK0pdffqn8/HzT5u3trdmzZ2vLli1W5+bi4qIOHTqYbQAA2EuD74l+/PhxeXl5SZLat2+vdu3aqXPnzqb9nTp10q+//tr0MwQAAJLIxQAAtBbNldPj4uIUFRWl4OBghYSEaPXq1SoqKlJ0dLSks6u7jxw5onXr1kmSoqOjtWLFCsXFxWnatGnKzs7WmjVrtH79elOfM2fO1MCBA7VkyRKNGjVKmzdv1tatW7Vz584Gj+vu7m5a2V7HyclJXl5e6tmzZ6PPEwCAy61RDxa90D3PAABA8yIXAwDQOjRHTo+MjNSxY8e0aNEiFRcXq3fv3kpPT5efn58kqbi4WEVFRaZ4f39/paenKzY2VitXrpS3t7eWL1+ucePGmWJCQ0O1YcMGLViwQAkJCerRo4dSU1PVr1+/Bo8LAEBL16gi+iOPPCIXFxdJ0pkzZxQdHa127dpJktlTswEAQPMgFwMA0Do0V06PiYlRTEyM1X0pKSkWbYMGDdKePXvq7XP8+PEaP378RY9rzcGDBxscCwCAvTW4iP7www+bvX7ooYcsYiZNmnTpMwIAAFaRiwEAaB3I6QAAtCwNLqK//fbbzTkPAABwAeRiAABaB3I6AAAtSxt7TwAAAAAAAAAAgCsVRXQAAAAAAAAAAGygiA4AAAAAAAAAgA0U0QEAAAAAAAAAsIEiOgAAAAAAAAAANlBEBwAAAAAAAADABoroAAAAAAAAAADYQBEdAAAAAAAAAAAbKKIDAAAAAAAAAGADRXQAAAAAAAAAAGygiA4AAAAAAAAAgA0U0QEAAAAAAAAAsIEiOgAAAAAAAAAANlBEBwAAAAAAAADABoroAAAAAAAAAADYYPcielJSkvz9/eXq6qqgoCDt2LGj3visrCwFBQXJ1dVV3bt3V3JyskXML7/8ounTp6tr165ydXVVQECA0tPTm+sUAAAAAAAAAACtlF2L6KmpqZo1a5bmz5+vvLw8hYWFKSIiQkVFRVbjCwsLNWLECIWFhSkvL0/z5s3TjBkzlJaWZoqpqKjQsGHDdPDgQf3tb3/Tt99+qzfffFPXX3/95TotAAAAAAAAAEAr4WjPwZctW6YpU6Zo6tSpkiSj0agtW7Zo1apVSkxMtIhPTk6Wr6+vjEajJCkgIEA5OTlaunSpxo0bJ0lau3atjh8/rl27dsnJyUmS5Ofnd3lOCAAAAAAAAADQqthtJXpFRYVyc3MVHh5u1h4eHq5du3ZZPSY7O9sifvjw4crJyVFlZaUk6YMPPlBISIimT58uT09P9e7dWy+++KKqq6ttzqW8vFxlZWVmGwAAAAAAAAAAdiuil5aWqrq6Wp6enmbtnp6eKikpsXpMSUmJ1fiqqiqVlpZKkr7//nv97W9/U3V1tdLT07VgwQK9+uqrWrx4sc25JCYmys3NzbT5+Phc4tkBAAAAAAAAAFoDuz9Y1GAwmL2ura21aLtQ/LntNTU1uu6667R69WoFBQXp/vvv1/z587Vq1SqbfcbHx+vEiROm7fDhwxd7OgAAAAAAAACAVsRu90T38PCQg4ODxarzo0ePWqw2r+Pl5WU13tHRUe7u7pKkrl27ysnJSQ4ODqaYgIAAlZSUqKKiQs7Ozhb9uri4yMXF5VJPCQAAAAAAAADQytitiO7s7KygoCBlZmZqzJgxpvbMzEyNGjXK6jEhISH68MMPzdoyMjIUHBxseoho//799d5776mmpkZt2pxdaL9v3z517drVagEdAABISUlJeuWVV1RcXKybb75ZRqNRYWFhNuOzsrIUFxen//znP/L29tacOXMUHR1tFpOWlqaEhAQdOHBAPXr00OLFi81yfkPHLSgo0DPPPKOsrCzV1NTo5ptv1l//+lf5+vo23RsAAJdJt7kf23sKl+TgS/fYewoAAACXnV1v5xIXF6e33npLa9euVUFBgWJjY1VUVGT6EB4fH69JkyaZ4qOjo3Xo0CHFxcWpoKBAa9eu1Zo1a/T000+bYv74xz/q2LFjmjlzpvbt26ePP/5YL774oqZPn37Zzw8AgJYgNTVVs2bN0vz585WXl6ewsDBFRESoqKjIanxhYaFGjBihsLAw5eXlad68eZoxY4bS0tJMMdnZ2YqMjFRUVJT27t2rqKgoTZgwQbt3727UuAcOHNCAAQPUq1cvbd++XXv37lVCQoJcXV2b7w0BAAAAAOAcdluJLkmRkZE6duyYFi1apOLiYvXu3Vvp6eny8/OTJBUXF5t9kPb391d6erpiY2O1cuVKeXt7a/ny5Ro3bpwpxsfHRxkZGYqNjdWtt96q66+/XjNnztQzzzxz2c8PAICWYNmyZZoyZYqmTp0qSTIajdqyZYtWrVqlxMREi/jk5GT5+vrKaDRKOnvbtJycHC1dutSUk41Go4YNG6b4+HhJZ/8wnpWVJaPRqPXr1zd43Pnz52vEiBF6+eWXTeN37969ed4IAAAAAACssGsRXZJiYmIUExNjdV9KSopF26BBg7Rnz556+wwJCdHnn3/eFNMDAKBVq6ioUG5urubOnWvWHh4erl27dlk9Jjs7W+Hh4WZtw4cP15o1a1RZWSknJydlZ2crNjbWIqau8N6QcWtqavTxxx9rzpw5Gj58uPLy8uTv76/4+HiNHj36Es4aAAAAAC4Nt2i7utj1di4AAMC+SktLVV1dbfFQb09PT4uHedcpKSmxGl9VVaXS0tJ6Y+r6bMi4R48e1cmTJ/XSSy/p7rvvVkZGhsaMGaOxY8cqKyvL6tzKy8tVVlZmtgEAAAAAcCnsvhIdAADYn8FgMHtdW1tr0Xah+PPbG9JnfTE1NTWSpFGjRplWtfft21e7du1ScnKyBg0aZDGvxMREPffcczbnDQAAAABAY7ESHQCAq5iHh4ccHBwsVp0fPXrUYpV4HS8vL6vxjo6Ocnd3rzemrs+GjOvh4SFHR0cFBgaaxQQEBNh86Gl8fLxOnDhh2g4fPlzf6QMAAAAAcEEU0QEAuIo5OzsrKChImZmZZu2ZmZkKDQ21ekxISIhFfEZGhoKDg+Xk5FRvTF2fDRnX2dlZd9xxh7799luzmH379pkeQn4+FxcXdejQwWwDAAAAAOBScDsXAACucnFxcYqKilJwcLBCQkK0evVqFRUVKTo6WtLZ1d1HjhzRunXrJEnR0dFasWKF4uLiNG3aNGVnZ2vNmjVav369qc+ZM2dq4MCBWrJkiUaNGqXNmzdr69at2rlzZ4PHlaTZs2crMjJSAwcO1JAhQ/TJJ5/oww8/1Pbt2y/PmwMAAAAAuOpRRAcA4CoXGRmpY8eOadGiRSouLlbv3r2Vnp5uWu1dXFxsdvsUf39/paenKzY2VitXrpS3t7eWL1+ucePGmWJCQ0O1YcMGLViwQAkJCerRo4dSU1PVr1+/Bo8rSWPGjFFycrISExM1Y8YM9ezZU2lpaRowYMBleGcAAAAAAKCIDgAAJMXExCgmJsbqvpSUFIu2QYMGac+ePfX2OX78eI0fP/6ix60zefJkTZ48ud4YAAAAAACaC/dEBwAAAAAAAADABoroAAAAAAAAAADYQBEdAAAAAAAAAAAbKKIDAAAAAAAAAGADRXQAAAAAAAAAAGygiA4AAAAAAAAAgA0U0QEAAAAAAAAAsIEiOgAAAAAAAAAANlBEBwAAAAAAAADABoroAAAAAAAAAADYQBEdAAAAAAAAAAAbHO09AQAAAABAC7HQzd4zuHQLT9h7BgAAoIVhJToAAAAAAAAAADawEh0AcHm09JVrrFoDAAAAAOCqxEp0AAAAAAAAAABsoIgOAAAAAAAAAIAN3M4FAAAAAAAAAK4m3HK1UViJDgAAAAAAAACADRTRAQAAAAAAAACwgSI6AAAAAAAAAAA2UEQHAAAAAAAAAMAGiugAAAAAAAAAANhAER0AAAAAAAAAABsoogMAAAAAAAAAYIOjvScAALiwbnM/tvcULtlBV3vPAAAAAAAAoPFYiQ4AAAAAAAAAgA0U0QEAAAAAAAAAsIEiOgAAAAAAAAAANlBEBwAAAAAAAADABoroAAAAAAAAAADYQBEdAAAAAAAAAAAbKKIDAAAAAAAAAGCD3YvoSUlJ8vf3l6urq4KCgrRjx45647OyshQUFCRXV1d1795dycnJNmM3bNggg8Gg0aNHN/GsAQAAAAAAAABXA7sW0VNTUzVr1izNnz9feXl5CgsLU0REhIqKiqzGFxYWasSIEQoLC1NeXp7mzZunGTNmKC0tzSL20KFDevrppxUWFtbcpwEAAAAAAAAAaKXsWkRftmyZpkyZoqlTpyogIEBGo1E+Pj5atWqV1fjk5GT5+vrKaDQqICBAU6dO1eTJk7V06VKzuOrqaj344IN67rnn1L1798txKgAAAAAAAACAVshuRfSKigrl5uYqPDzcrD08PFy7du2yekx2drZF/PDhw5WTk6PKykpT26JFi9SlSxdNmTKlQXMpLy9XWVmZ2QYAAAAAAAAAgN2K6KWlpaqurpanp6dZu6enp0pKSqweU1JSYjW+qqpKpaWlkqTPPvtMa9as0ZtvvtnguSQmJsrNzc20+fj4NPJsAAAAAAAAAACtkd0fLGowGMxe19bWWrRdKL6u/ddff9VDDz2kN998Ux4eHg2eQ3x8vE6cOGHaDh8+3IgzAACg5WuOB32npaUpMDBQLi4uCgwM1MaNGy9p3Mcff1wGg0FGo7HR5wcAAAAAwMWyWxHdw8NDDg4OFqvOjx49arHavI6Xl5fVeEdHR7m7u+vAgQM6ePCgRo4cKUdHRzk6OmrdunX64IMP5OjoqAMHDljt18XFRR06dDDbAAC4WjTHg76zs7MVGRmpqKgo7d27V1FRUZowYYJ27959UeNu2rRJu3fvlre3d9O/AQAAAAAA1MNuRXRnZ2cFBQUpMzPTrD0zM1OhoaFWjwkJCbGIz8jIUHBwsJycnNSrVy/9+9//Vn5+vmm77777NGTIEOXn53ObFgAArGiOB30bjUYNGzZM8fHx6tWrl+Lj4zV06FCzVeQNHffIkSN64okn9O6778rJyalZ3gMAAAAAAGyx6+1c4uLi9NZbb2nt2rUqKChQbGysioqKFB0dLensbVYmTZpkio+OjtahQ4cUFxengoICrV27VmvWrNHTTz8tSXJ1dVXv3r3Nto4dO+raa69V79695ezsbJfzBADgStVcD/q2FVPXZ0PHrampUVRUlGbPnq2bb775gufDw8IBAAAAAE3N0Z6DR0ZG6tixY1q0aJGKi4vVu3dvpaeny8/PT5JUXFxs9pVuf39/paenKzY2VitXrpS3t7eWL1+ucePG2esUAABo0ZrjQd9du3a1GVPXZ0PHXbJkiRwdHTVjxowGnU9iYqKee+65BsUCAAAAANAQdi2iS1JMTIxiYmKs7ktJSbFoGzRokPbs2dPg/q31AQAAzDXlg74b02d9Mbm5uXr99de1Z8+eeudyrvj4eMXFxZlel5WVcTs3AAAAAMAlsevtXAAAgH01x4O+64up67Mh4+7YsUNHjx6Vr6+v6YHhhw4d0lNPPaVu3bpZnRsPCwcAXO2SkpLk7+8vV1dXBQUFaceOHfXGZ2VlKSgoSK6ururevbuSk5MtYtLS0hQYGCgXFxcFBgZq48aNjRq3srJSzzzzjG655Ra1a9dO3t7emjRpkn788cdLP2EAAC4DiugAAFzFmuNB3/XF1PXZkHGjoqL05Zdfmj0w3NvbW7Nnz9aWLVsu/qQBAGilUlNTNWvWLM2fP195eXkKCwtTRESE2W1Sz1VYWKgRI0YoLCxMeXl5mjdvnmbMmKG0tDRTTHZ2tiIjIxUVFaW9e/cqKipKEyZM0O7duxs87m+//aY9e/YoISFBe/bs0fvvv699+/bpvvvua943BACAJmL327kAAAD7iouLU1RUlIKDgxUSEqLVq1dbPOj7yJEjWrdunaSzD/pesWKF4uLiNG3aNGVnZ2vNmjVav369qc+ZM2dq4MCBWrJkiUaNGqXNmzdr69at2rlzZ4PHdXd3N61sr+Pk5CQvLy/17Nmzud8WAABanGXLlmnKlCmaOnWqJMloNGrLli1atWqVEhMTLeKTk5Pl6+sro9EoSQoICFBOTo6WLl1qevaY0WjUsGHDFB8fL+nsdUFWVpaMRqMp919oXDc3N4s/nP/pT3/SnXfeqaKiIvn6+jbL+wEAQFNhJToAAFe5yMhIGY1GLVq0SH379tWnn37aoAd9b9++XX379tXzzz9v8aDv0NBQbdiwQW+//bZuvfVWpaSkKDU1Vf369WvwuAAAoOEqKiqUm5ur8PBws/bw8HDt2rXL6jHZ2dkW8cOHD1dOTo4qKyvrjanr82LGlaQTJ07IYDCoY8eODTo/AADsiZXoAACgWR70PX78eI0fP/6ix7Xm4MGDDY4FAOBqUlpaqurqaotnmnh6elo8g6ROSUmJ1fiqqiqVlpaqa9euNmPq+ryYcc+cOaO5c+dq4sSJNp9fUl5ervLyctPrsrIyq3EAAFwOrEQHAAAAAKCVMBgMZq9ra2st2i4Uf357Q/ps6LiVlZW6//77VVNTo6SkJJvzqrsNTN3m4+NjMxYAgOZGER0AAAAAgBbOw8NDDg4OFqu/jx49arFKvI6Xl5fVeEdHR9NzSWzF1PXZmHErKys1YcIEFRYWKjMz0+YqdOnsvddPnDhh2g4fPlzP2QMA0LwoogMAAAAA0MI5OzsrKCjI4gGemZmZCg0NtXpMSEiIRXxGRoaCg4Pl5ORUb0xdnw0dt66Avn//fm3dutXi4eHnc3FxUYcOHcw2AADshXuiAwAAAADQCsTFxSkqKkrBwcEKCQnR6tWrVVRUpOjoaElnV3cfOXJE69atkyRFR0drxYoViouL07Rp05Sdna01a9Zo/fr1pj5nzpypgQMHasmSJRo1apQ2b96srVu3aufOnQ0et6qqSuPHj9eePXv00Ucfqbq62rRyvXPnznJ2dr5cbxEAABeFIjoAAAAAAK1AZGSkjh07pkWLFqm4uFi9e/dWenq6/Pz8JEnFxcUqKioyxfv7+ys9PV2xsbFauXKlvL29tXz5co0bN84UExoaqg0bNmjBggVKSEhQjx49lJqaqn79+jV43B9++EEffPCBJKlv375mc962bZsGDx7cTO8IAABNgyI6AAAAAACtRExMjGJiYqzuS0lJsWgbNGiQ9uzZU2+f48eP1/jx4y963G7dupkeWAoAQEvEPdEBAAAAAAAAALCBIjoAAAAAAAAAADZQRAcAAAAAAAAAwAaK6AAAAAAAAAAA2EARHQAAAAAAAAAAGyiiAwAAAAAAAABgA0V0AAAAAAAAAABsoIgOAAAAAAAAAIANFNEBAAAAAAAAALCBIjoAAAAAAAAAADZQRAcAAAAAAAAAwAaK6AAAAAAAAAAA2EARHQAAAAAAAAAAGyiiAwAAAAAAAABgA0V0AAAAAAAAAABsoIgOAAAAAAAAAIANFNEBAAAAAAAAALCBIjoAAAAAAAAAADZQRAcAAAAAAAAAwAaK6AAAAAAAAAAA2EARHQAAAAAAAAAAGxztPQEAAAAAAIDLqdvcj+09hUty0NXeMwCAqwsr0QEAAAAAAAAAsIEiOgAAAAAAAAAANlBEBwAAAAAAAADABoroAAAAAAAAAADYQBEdAAAAAAAAAAAbKKIDAAAAAAAAAGCD3YvoSUlJ8vf3l6urq4KCgrRjx45647OyshQUFCRXV1d1795dycnJZvvffPNNhYWFqVOnTurUqZPuuusuffHFF815CgAAAAAAAACAVsquRfTU1FTNmjVL8+fPV15ensLCwhQREaGioiKr8YWFhRoxYoTCwsKUl5enefPmacaMGUpLSzPFbN++XQ888IC2bdv2/7V373FVlYn+x7+gbEBBEEsBRSDzmhWpXdAx8lRYnammo6PHGtG0i+k4iWnetaleppZJmpfR8Vbn5KVBy9JjXkbMEg3FSyamFaYZ5GgF3kAuz+8Pf6xhs/eGTYIb9PN+vfZL91rPXs+z1n7W+uqz9lpLqampat68ueLj43XixIkrtVoAAAAAAAAAgKuERwfR33zzTQ0cOFBPPfWU2rZtq6SkJEVERGju3LlOy8+bN0/NmzdXUlKS2rZtq6eeekoDBgzQG2+8YZX53//9Xw0ePFgxMTFq06aNFixYoOLiYm3evPlKrRYAALVOVV8ZJknJyclq166dfH191a5dO61evbpS9RYUFGjUqFG6+eabVb9+fYWHhyshIUE//vjj5a8wAAAAAABu8tgg+sWLF7V7927Fx8fbTY+Pj9f27dudfiY1NdWhfPfu3bVr1y4VFBQ4/cz58+dVUFCgkJAQl23Jz89Xbm6u3QsAgGtFdVwZlpqaqt69e6tv377at2+f+vbtq169emnnzp1u13v+/Hmlp6drwoQJSk9P16pVq3T48GE98sgj1btBAAAAAAAoxWOD6KdOnVJRUZGaNGliN71JkybKzs52+pns7Gyn5QsLC3Xq1Cmnnxk9erSaNm2q++67z2VbXnvtNQUFBVmviIiISq4NAAC1V3VcGZaUlKT7779fY8aMUZs2bTRmzBjde++9SkpKcrveoKAgbdy4Ub169VLr1q111113adasWdq9e7fLAX4AAAAAAKqaxx8s6uXlZffeGOMwraLyzqZL0rRp07Rs2TKtWrVKfn5+Lpc5ZswY5eTkWK/jx49XZhUAAKi1quvKMFdlSpb5W+qVpJycHHl5eSk4ONit9QMAAAAA4HLV9VTF1113nerUqePwq/OTJ086/Nq8RGhoqNPydevWVaNGjeymv/HGG5o8ebI2bdqkW265pdy2+Pr6ytfX9zesBQAAtVt1XBkWFhbmskzJMn9LvXl5eRo9erQef/xxNWjQwGmZ/Px85efnW++5RRsAAAAA4HJ57JfoNptNHTt21MaNG+2mb9y4UZ07d3b6mdjYWIfyGzZsUKdOneTj42NNe/311/XKK69o/fr16tSpU9U3HgCAq0x1XBnmzjLdrbegoED//d//reLiYs2ZM8dlu7hFGwAAAACgqnn0di7Dhw/X3//+dy1atEgZGRlKTEzUsWPHNGjQIEmXbrOSkJBglR80aJC+//57DR8+XBkZGVq0aJEWLlyoESNGWGWmTZum8ePHa9GiRYqKilJ2drays7N19uzZK75+AADUdNV1ZZirMiXLrEy9BQUF6tWrlzIzM7Vx40aXv0KXuEUbAAAAAKDqeXQQvXfv3kpKStLLL7+smJgYffrpp1q3bp0iIyMlSVlZWXYPDouOjta6deuUkpKimJgYvfLKK5o5c6Z69OhhlZkzZ44uXryonj17KiwszHqVftgZAAC4pLquDHNVpmSZ7tZbMoB+5MgRbdq0yeH2bWX5+vqqQYMGdi8AAAAAAC6Hx+6JXmLw4MEaPHiw03lLlixxmBYXF6f09HSXyzt69GgVtQwAgGvD8OHD1bdvX3Xq1EmxsbGaP3++w5VhJ06c0DvvvCPp0pVhb7/9toYPH66nn35aqampWrhwoZYtW2Yt8/nnn9fdd9+tqVOn6tFHH9WHH36oTZs26bPPPnO73sLCQvXs2VPp6en6+OOPVVRUZP1yPSQkRDab7UptIgAAAADANczjg+gAAMCzevfurdOnT+vll19WVlaW2rdv79aVYYmJiZo9e7bCw8Mdrgzr3Lmzli9frvHjx2vChAlq0aKFVqxYoTvvvNPten/44QetWbNGkhQTE2PX5i1btuiee+6ppi0CAAAAAMC/MYgOAACq/MowSerZs6d69uz5m+uNioqyHlgKAAAAAICnePSe6AAAAAAAAAAA1GQMogMAAAAAAAAA4AKD6AAAAAAAAAAAuMAgOgAAAAAAAAAALjCIDgAAAAAAAACACwyiAwAAAAAAAADgQl1PNwAAAKC2iBq91tNNuCxH/TzdAgAAAACoffglOgAAAAAAAAAALjCIDgAAAAAAAACACwyiAwAAAAAAAADgAoPoAAAAAAAAAAC4wCA6AAAAAAAAAAAu1PV0A64FUaPXeroJl+Won6dbAAAAAAAAAACewS/RAQAAAAAAAABwgUF0AAAAAAAAAABcYBAdAAAAAAAAAAAXGEQHAAAAAAAAAMAFBtEBAAAAAAAAAHCBQXQAAAAAAAAAAFxgEB0AAAAAAAAAABcYRAcAAAAAAAAAwAUG0QEAAAAAAAAAcIFBdAAAAAAAAAAAXGAQHQAAAAAAAAAAFxhEBwAAAAAAAADABQbRAQAAAAAAAABwgUF0AAAAAAAAAABcYBAdAAAAAAAAAAAXGEQHAAAAAAAAAMAFBtEBAAAAAAAAAHCBQXQAAAAAAAAAAFxgEB0AAAAAAAAAABcYRAcAAAAAAAAAwAUG0QEAAAAAAAAAcIFBdAAAAAAAAAAAXGAQHQAAAAAAAAAAFxhEBwAAAAAAAADABY8Pos+ZM0fR0dHy8/NTx44dtW3btnLLb926VR07dpSfn59uuOEGzZs3z6FMcnKy2rVrJ19fX7Vr106rV6+uruYDAHBV8FQeV1SvMUYvvfSSwsPD5e/vr3vuuUdfffXV5a0sAABXMTIdAICq59FB9BUrVmjYsGEaN26c9uzZo65du+rBBx/UsWPHnJbPzMzUQw89pK5du2rPnj0aO3as/vKXvyg5Odkqk5qaqt69e6tv377at2+f+vbtq169emnnzp1XarUAAKhVPJXH7tQ7bdo0vfnmm3r77beVlpam0NBQ3X///Tpz5kz1bRAAAGopMh0AgOrhZYwxnqr8zjvvVIcOHTR37lxrWtu2bfWHP/xBr732mkP5UaNGac2aNcrIyLCmDRo0SPv27VNqaqokqXfv3srNzdX//d//WWUeeOABNWzYUMuWLXOrXbm5uQoKClJOTo4aNGjwW1fPEjV67WUvw5OO+j3u6SZcnpdyPN2CCtFHPIw+ckXQT6o+X6qKp/K4onqNMQoPD9ewYcM0atQoSVJ+fr6aNGmiqVOn6tlnn61w3ch0e+yH1Y8+4mH0kWpX6/uIRKaXQqbXXrV+X+R4Xe3oI9WPPuJhVdRH3M2XulVS229w8eJF7d69W6NHj7abHh8fr+3btzv9TGpqquLj4+2mde/eXQsXLlRBQYF8fHyUmpqqxMREhzJJSUku25Kfn6/8/HzrfU7OpS8hNze3MqvkUnH++SpZjqfkennsPEvVqKLvsTrRRzyMPnJF0E/+nSsePH/twFN57E69mZmZys7OtqvL19dXcXFx2r59u9P/cJPp5WM/rH70EQ+jj1S7Wt9HJDK9FDK99qr1+yLH62pHH6l+9BEPq6I+4m6me2wQ/dSpUyoqKlKTJk3spjdp0kTZ2dlOP5Odne20fGFhoU6dOqWwsDCXZVwtU5Jee+01/fWvf3WYHhER4e7qXNWCPN2AyzWl1q9BjVfrtzB95Iqo9Vu5CvvJmTNnFBRUM7aIp/LYnXpL/nRW5vvvv3faNjK9fDWj110GjtfVrtZvYfpItbsqtjCZbiHTa6+a0esuA8fralfrtzB9pNrV+i1cxX2kokz32CB6CS8vL7v3xhiHaRWVLzu9ssscM2aMhg8fbr0vLi7Wzz//rEaNGpX7uWtBbm6uIiIidPz48Rp1mSJqDvoI3EE/ucQYozNnzig8PNzTTXHgqTyuqjIlyHTX2A9REfoIKkIf+TcynUz3JPZFVIQ+gorQR/7N3Uz32CD6ddddpzp16jicET958qTD2ekSoaGhTsvXrVtXjRo1KreMq2VKly4j8/X1tZsWHBzs7qpcExo0aHDN71QoH30E7qCfqMb8Wq2Ep/LYnXpDQ0MlXfr1WlhYmFttI9Mrxn6IitBHUBH6yCVkOpnuaeyLqAh9BBWhj1ziTqZ7X4F2OGWz2dSxY0dt3LjRbvrGjRvVuXNnp5+JjY11KL9hwwZ16tRJPj4+5ZZxtUwAAK5lnspjd+qNjo5WaGioXZmLFy9q69at5DoAAGWQ6QAAVCPjQcuXLzc+Pj5m4cKF5uDBg2bYsGGmfv365ujRo8YYY0aPHm369u1rlf/uu+9MvXr1TGJiojl48KBZuHCh8fHxMf/4xz+sMp9//rmpU6eOmTJlisnIyDBTpkwxdevWNTt27Lji63c1yMnJMZJMTk6Op5uCGoo+AnfQT2o2T+VxRfUaY8yUKVNMUFCQWbVqlfnyyy9Nnz59TFhYmMnNzb0CW+bqwn6IitBHUBH6SM1Hpl8b2BdREfoIKkIfqTyPDqIbY8zs2bNNZGSksdlspkOHDmbr1q3WvH79+pm4uDi78ikpKea2224zNpvNREVFmblz5zos8/333zetW7c2Pj4+pk2bNiY5Obm6V+OqlZeXZyZNmmTy8vI83RTUUPQRuIN+UvN5Ko/Lq9cYY4qLi82kSZNMaGio8fX1NXfffbf58ssvq2alrzHsh6gIfQQVoY/UDmT61Y99ERWhj6Ai9JHK8zLm/z81BAAAAAAAAAAA2PHYPdEBAAAAAAAAAKjpGEQHAAAAAAAAAMAFBtEBADVGYWGhp5sAAACqAJkOAMDVgUy/hEF0ANXmzjvv1MGDB3XhwgV16NBBBw4c8HSTUIMUFhbqzTffVJcuXdS0aVP5+flpwoQJnm4WAMAJMh3lIdMBoPYg01EeMt01BtHd1L9/f3l5eTm8mjVr5ummwYOys7M1dOhQ3XDDDfL19VVERIQefvhhbd682dNNqxESExPVsWNHBQYGKjo6Wu3bt/d0k2q1oqIide7cWT169LCbnpOTo4iICI0fP95DLas8Y4wefvhhLVmyRCNGjNCWLVt04MABTZw40dNNwzWATIczZHr5yPSqRaYDVYNMhzNkevnI9KpFpl87vIwxxtONqA369++vn376SYsXL7abXqdOHV1//fUeahU86ejRo+rSpYuCg4P117/+VbfccosKCgr0ySefaP78+Tp06JCnm1gjnD9/XmfPnlXjxo093ZSrwpEjRxQTE6P58+friSeekCQlJCRo3759SktLk81m83AL3fPuu+9q8uTJSktLU0BAgKebg2sMmY6yyHT3kOlVi0wHLh+ZjrLIdPeQ6VWLTL9GGLilX79+5tFHHy23TGZmppFk9uzZY00bN26ckWRmzJhhTZNkVq9ebffZuLg48/zzz1vv3333XdOxY0cTEBBgmjRpYvr06WN++ukna/6WLVuMJPPxxx+bW265xfj6+po77rjD7N+/3yqzePFiExQUVGEbU1JSzO23325sNpsJDQ01o0aNMgUFBdb84uJiM3XqVBMdHW38/PzMLbfcYt5///1yt0VJ/ZLsXrfeeqtdma+++so8+OCDpn79+qZx48bmT3/6k/nXv/5lt12GDBlihgwZYoKCgkxISIgZN26cKS4utsrk5+ebkSNHmvDwcFOvXj1zxx13mC1btjhth7e3twkLCzMvvviiKSoqssrs37/fdOvWzfj5+ZmQkBDz9NNPmzNnzpS7fg8++KBp2rSpOXv2rMO8X375xfp76fUPDAw09913n/nmm2+s+WfOnDH9+vUzjRs3titb8h2tWLHC3HDDDcbX19eEhISYHj16mJMnT1qfnz59umnfvr2pV6+eadasmXnuuefs2u5OPyjpT6XbXdL2kr7qrO+UFhQUZBYvXuyyrLN9wZmFCxeadu3aWf1xyJAhTrdl6VfpfScyMtKujk2bNhlJdvtvUVGRmTJlimnRooWx2WwmIiLCvPrqq9b8ivpD2ePB+vXrTf369c1HH31U7rpVlbfeess0bNjQnDhxwnzwwQfGx8fH2tZJSUkmKirK2Gw2Ex0dbSZPnmzX18u2fc+ePUaSyczMtKaVPR6VFRkZ6fK7KOkDFfXLXr16mf/6r/8yd999twkICDCNGzc2w4YNM/n5+XZ1VXQcKdvWQ4cOmbp169qVcXb8LrtfFBYWmgEDBpioqCjj5+dnWrVqZZKSklxuA9RuZDqZXhaZbo9MJ9PJdNQWZDqZXhaZbo9MJ9PJ9KrD7Vyq0Q8//KC33npL/v7+lf7sxYsX9corr2jfvn364IMPlJmZqf79+zuUGzlypN544w2lpaWpcePGeuSRR1RQUOB2PSdOnNBDDz2k22+/Xfv27dPcuXO1cOFCvfrqq1aZ8ePHa/HixZo7d66++uorJSYm6k9/+pO2bt1a4fIbNGigrKwsZWVl6YUXXrCbl5WVpbi4OMXExGjXrl1av369fvrpJ/Xq1cuu3NKlS1W3bl3t3LlTM2fO1IwZM/T3v//dmv/kk0/q888/1/Lly7V//3798Y9/1AMPPKAjR444tOPYsWOaMWOGpk2bpk8++UTSpTOwDzzwgBo2bKi0tDS9//772rRpk/785z+7XK+ff/5Z69ev15AhQ1S/fn2H+cHBwXbvFy9erKysLH366ac6efKkxo4da82bPHmyNmzYoJUrVyorK0tffPGF3WfbtGmjJUuW6Ouvv9Ynn3yizMxMjRo1yprv7e2tmTNn6sCBA1q6dKn++c9/6sUXX3TZdk9wd1+YO3euhgwZomeeeUZffvml1qxZoxtvvNGuTMm2LHnFxsa6XF5xcbFeeOEFhzOoY8aM0dSpUzVhwgQdPHhQ7733npo0aSKp8v3hs88+U8+ePbVgwQL9/ve/d2dzXLahQ4fq1ltvVUJCgp555hlNnDhRMTExkqTw8HC99957OnTokGbMmKE5c+bY9beqkJaWZm3/Zs2aKSkpyXrfu3dvSRX3y3/9619atWqV2rZtqy+++EKLFi3S8uXLNWbMGLu6jDHlHkfKGjlypPz8/Cq9TsXFxWrWrJlWrlypgwcPauLEiRo7dqxWrlxZ6WXh6kSmk+klyHQyvSqR6a6R6aguZDqZXoJMJ9OrEpnu2lWT6R4bvq9l+vXrZ+rUqWPq169v6tevb5o2bWruvfdes379eqtM2bN6CQkJZuDAgQ5n3OTGGe6yvvjiCyPJOkNUckZy+fLlVpnTp08bf39/s2LFCmOMe2c2x44da1q3bm13xnj27NkmICDAFBUVmbNnzxo/Pz+zfft2u+UMHDjQ9OnTp7xNZubNm2euu+466/2kSZPszjpNmDDBxMfH233m+PHjRpL5+uuvre3Stm1bu/aNGjXKtG3b1hhjzDfffGO8vLzMiRMn7JZz7733mjFjxjjdDjt37jTe3t7WOs2fP980bNjQ7kz12rVrjbe3t8nOzna6bjt37jSSzKpVq8rdBsbYf9+//vqr6dKli3n22Wet+Q8++KB5+umnrfflnUnOyckx8fHxJiEhwWV9K1euNI0aNbLe14Qz3K72hbLCw8PNuHHjXM53Z98pXceiRYtM69atzRNPPGGd4czNzTW+vr5mwYIFTutwpz+UnDFNT083QUFBZt68eS7bXF0yMjKMJHPzzTfb/SKlrI8//tj4+vpax46qOMNdWmRkpPW9l6dsv4yLizMtW7a0O/v+7rvvGpvNZs6dO2dN+9vf/lbucaR0W//5z3+aRo0amWHDhlX6DLczgwcPNj169Khw3VD7kOlkemlkuiMy/coi0x3bSqbDXWQ6mV4ame6ITL+yyHTHtl5Nmc4v0SuhW7du2rt3r/bu3atVq1YpPDxc//mf/6kdO3Y4lE1PT9fq1av1yiuvOF1Wnz59FBAQYL22bdtmN3/Pnj169NFHFRkZqcDAQN1zzz2SpGPHjtmVK312LyQkRK1bt1ZGRoY1LScnx66em266ye7zGRkZio2NlZeXlzWtS5cuOnv2rH744QcdPHhQeXl5uv/+++2W88477+jbb78td3udPn1aDRo0cDl/9+7d2rJli91y27RpI0l2y77rrrvs2hcbG6sjR46oqKhI6enpMsaoVatWdsvZunWr3TJKtoO/v7/uuusujRw50tp2GRkZuvXWW+3OVHfp0kXFxcX6+uuvnbbd/P9HCZRuV3lKvu+GDRvqzJkzdr8giI6OVkpKik6cOOHy89u2bVNAQICCg4N14cIFTZ8+3Zq3ZcsW3X///WratKkCAwOVkJCg06dP69y5cw7r76oflGjWrJldOWc6d+6sgIAANWvWTD169FBmZma5617RvlDi5MmT+vHHH3XvvfeWW85d58+f1/jx4/X666+rbt261vSMjAzl5+e7rMfd/pCZmanu3bsrLy9P3bp1q5I2V8aiRYtUr149ZWZm6ocffrCbd9NNN1nfYa9evZSfn293XKiMyZMn2/WJsscgV9zpl126dJG3979j6He/+50uXryob775xpqWm5vr9FckZRlj9MILL2jSpEkKCgqqxBr+27x589SpUyddf/31CggI0IIFC9xeX9Q+ZDqZXoJMJ9PJ9PKR6ajpyHQyvQSZTqaT6eUj0y8Pg+iVUL9+fd1444268cYbdccdd2jRokXy8/PTBx984FD2hRde0IgRIxQWFuZ0WTNmzLCCfu/everUqZM179y5c4qPj1dAQID+53/+R2lpaVq9erWkS5ePVaR0YAQGBtrVs27dOruyxhiHgCkdPMXFxZKktWvX2i3n4MGD+sc//lFuO7777jtFRUW5nF9cXKyHH37Ybrl79+7VkSNHdPfdd1e4niXLqFOnjnbv3m23jIyMDL311lsO22H//v366KOPtGTJEi1ZssTlNijhanrLli3l5eXl9gGv5PvetWuXoqOj9cc//tGaN3HiREVFRVnB6Cw4O3XqpD179mjDhg06ffq0FixYIEn6/vvv9dBDD6l9+/ZKTk7W7t27NXv2bEmyu1ywon5QYtu2bXblnFmxYoX27t2r999/X1lZWUpISCh33SvaF0r8lsspy/P666+rdevWevjhhytVj7v9Yf/+/Ro4cKAef/xxPfnkk9a+ciWkpqZqxowZ+vDDDxUbG6uBAwda+60krVu3zvoOS45Pv3X7Dho0yK5PhIeHV/gZd/plw4YN3drOP/74o1t1vvPOOzp3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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "df = pd.read_csv('data/task1/results.csv')\n", + "mean_times = df.groupby(['Структура', 'Режим'])[['Вставка', 'Поиск', 'Удаление']].mean().reset_index()\n", + "structures = mean_times['Структура'].unique()\n", + "modes = mean_times['Режим'].unique()\n", + "\n", + "fig, axes = plt.subplots(1, 3, figsize=(15, 5))\n", + "operations = ['Вставка', 'Поиск', 'Удаление']\n", + "\n", + "for ax, op in zip(axes, operations):\n", + " # a\n", + " x = np.arange(len(structures))\n", + " width = 0.35\n", + " \n", + " random_vals = []\n", + " sorted_vals = []\n", + " for s in structures:\n", + " random_row = mean_times[(mean_times['Структура']==s) & (mean_times['Режим']=='Cлучайный')]\n", + " sorted_row = mean_times[(mean_times['Структура']==s) & (mean_times['Режим']=='Отсортированный')]\n", + " random_vals.append(random_row[op].values[0] if not random_row.empty else 0)\n", + " sorted_vals.append(sorted_row[op].values[0] if not sorted_row.empty else 0)\n", + " \n", + " ax.bar(x - width/2, random_vals, width, label='Случайный')\n", + " ax.bar(x + width/2, sorted_vals, width, label='Отсортированный')\n", + " ax.set_xticks(x)\n", + " ax.set_xticklabels(structures)\n", + " ax.set_ylabel('Время (сек)')\n", + " ax.set_title(op)\n", + " ax.legend()\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig('data/task1/performance_plot.png', dpi=150)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "1d86131d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
СтруктураРежимВставкаПоискУдаление
0Бинарное деревоCлучайный0.0119210.0001500.000137
1Бинарное деревоОтсортированный0.1221710.0016270.000873
2Связанный списокCлучайный0.0900390.0008930.000605
3Связанный списокОтсортированный0.1624470.0017070.000915
4Хэш-таблицаCлучайный0.0448310.0006180.000324
5Хэш-таблицаОтсортированный0.0493690.0005270.000272
\n", + "
" + ], + "text/plain": [ + " Структура Режим Вставка Поиск Удаление\n", + "0 Бинарное дерево Cлучайный 0.011921 0.000150 0.000137\n", + "1 Бинарное дерево Отсортированный 0.122171 0.001627 0.000873\n", + "2 Связанный список Cлучайный 0.090039 0.000893 0.000605\n", + "3 Связанный список Отсортированный 0.162447 0.001707 0.000915\n", + "4 Хэш-таблица Cлучайный 0.044831 0.000618 0.000324\n", + "5 Хэш-таблица Отсортированный 0.049369 0.000527 0.000272" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('data/task1/results.csv')\n", + "df.groupby(['Структура', 'Режим'])[['Вставка', 'Поиск', 'Удаление']].mean().reset_index()" + ] + }, + { + "cell_type": "markdown", + "id": "c9a486a5", + "metadata": {}, + "source": [ + "# 4. Анализ результатов\n", + "---\n", + "### 4.1 Влияние порядка данных на вставку в BST\n", + "При вставке элементов в отсортированном порядке в бинарное дерево оно превращается в связный список - это связанно с тем, что все элементы вставляются в одну ветвь дерева. Сложность всех операций приблтижается к **O(n)**. Вставка в BST на отсортированных данных заняла 0.122171c вместо 0.011921с, разница более чем в 10 раз. Причём, время вставки даже хуже, чем у чистого связнного списка - это связанно с дополнительными расходами бинарного дерева. Поиск так же ухудшился, примерно в 10 раз, а с ним ухудшилось и удаление.\n", + "\n", + "### 4.2 Почему хэш-таблица почти не чувствительна к порядку\n", + "По графикам видно, что для хэш-таблицы время операций почти не изменяется. Исключение составляет лишь поиск, его время больше на отсортированных данных. Это связано с особенностями теста - поиск 10 несуществующих записей ухудшают результат для отсортированных данных. Все эти наблюдения связаны с механизмом работы хэш-таблицы - она распределяет данные по корзинам независимо от порядка поступления. Получается, что сложность всех операций **O(1)**\n", + "\n", + "### 4.3 Почему связный список всегда медленен при поиске\n", + "Для поиска в связном списке нужно просматривать все элементы по порядку, так что сложность всех операций **O(n)**\n", + "\n", + "### 4.4 Сравнение удаления\n", + "\n", + "- **Связаный список** удаление требует сначала найти элемент за O(n), затем переставить ссылки за O(1). Время удаления (0.000605 с) близко ко времени поиска, что логично.\n", + "- **Хеш-таблица:** при удалении, поиск корзины за O(1) и поиск в коротком связаном списке за O(n) удаляется элемент. Время удаления (0.000324) меньше, чем в списке.\n", + "- **BST:** на случайных данных удаление очень быстрое (0.000137 с) благодаря логарифмической высоте. На отсортированных данных время возрастает до 0.000873, что отражает деградацию до O(n)." + ] + }, + { + "cell_type": "markdown", + "id": "a7ed5470", + "metadata": {}, + "source": [ + "# 5. Вывод\n", + "На основе полученных результатов можно сформулировать следующие рекомендации:\n", + "\n", + "- Хеш-таблица – хороший выбор, если приоритетом является максимальная скорость вставки, поиска и удаления по ключу, а порядок элементов не имеет значения. Время операций близко к **O(1)** и практически не зависит от упорядоченности входных данных. Идеальна для кэшей, словарей и частых запросов по идентификатору.\n", + "\n", + "- Двоичное дерево поиска – следует применять, когда необходимо получать данные в отсортированном порядке. На случайных данных демонстрирует хорошую производительность **O(log n)**, однако при поступлении заранее отсортированных элементов вырождается в связный список с падением скорости до **O(n)**.\n", + "\n", + "- Связный список – демонстрирует линейную сложность поиска и удаления **O(n)** что делает его непригодным для задач с частым доступом к произвольным элементам. Может быть оправдан только в узких случаях, где вставки и удаления происходят исключительно в начале или конце коллекции (очереди, стеки) и не требуется поиск.\n", + "\n", + "Таким образом, для реальных задач чаще всего выбирают хеш-таблицы или сбалансированные деревья в зависимости от требований к упорядоченности данных.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/MusinAA/docs/Report 2.ipynb b/MusinAA/docs/Report 2.ipynb new file mode 100644 index 00000000..d0ec0482 --- /dev/null +++ b/MusinAA/docs/Report 2.ipynb @@ -0,0 +1,903 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6dc3ad27", + "metadata": {}, + "source": [ + "# Отчёт: Поиск выхода из лабиринта (объектно-ориентированная реализация с паттернами)\n", + "\n", + "- Описание задачи и выбранных паттернов (с диаграммой классов из Mermaid).\n", + "- Результаты экспериментов (таблицы, графики).\n", + "- Анализ эффективности алгоритмов и применимости паттернов.\n", + "- Выводы: как ООП и паттерны помогли сделать код гибким и расширяемым. Что было бы сложно изменить без них." + ] + }, + { + "cell_type": "markdown", + "id": "59b2f0d3", + "metadata": {}, + "source": [ + "## 1. Описание задачи и выбранных паттернов\n", + "\n", + "Необходимо создать программу с применением паттернов ООП для решения задачи поиска из лабиринта. Для этого, подготовим схему из Mermaid, отражающую связи между объектами:\n", + "\n", + "```mermaid\n", + "classDiagram\n", + " class Maze {\n", + " -Cell[] cells\n", + " -int width, height\n", + " -Cell start\n", + " -Cell exit\n", + " +getCell(x,y): Cell\n", + " +getNeighbors(cell): List~Cell~\n", + " }\n", + " \n", + " class Cell {\n", + " -int x, y\n", + " -bool isWall\n", + " -bool isStart\n", + " -bool isExit\n", + " +isPassable(): bool\n", + " }\n", + " \n", + " class MazeBuilder {\n", + " <>\n", + " +buildFromFile(filename): Maze\n", + " }\n", + " \n", + " class TextFileMazeBuilder {\n", + " +buildFromFile(filename): Maze\n", + " }\n", + " \n", + " class PathFindingStrategy {\n", + " <>\n", + " +findPath(maze, start, exit): List~Cell~\n", + " }\n", + " \n", + " class BFS\n", + " class DFS\n", + " class AStar\n", + " \n", + " class SearchStats {\n", + " +timeMs: float\n", + " +visitedCells: int\n", + " +pathLength: int\n", + " }\n", + " \n", + " class MazeSolver {\n", + " -Maze maze\n", + " -PathFindingStrategy strategy\n", + " +setStrategy(strategy)\n", + " +solve(): SearchStats\n", + " }\n", + " \n", + " class Observer {\n", + " <>\n", + " +update(event)\n", + " }\n", + " \n", + " class ConsoleView {\n", + " +update(event)\n", + " +render(maze, player, path)\n", + " }\n", + " \n", + " MazeBuilder <|.. TextFileMazeBuilder\n", + " MazeBuilder --> Maze : creates\n", + " PathFindingStrategy <|.. BFS\n", + " PathFindingStrategy <|.. DFS\n", + " PathFindingStrategy <|.. AStarStrategy\n", + " MazeSolver --> PathFindingStrategy : uses\n", + " MazeSolver --> Maze : uses\n", + " Observer <|.. ConsoleView\n", + " MazeSolver --> Observer : notifies\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "e268fdf0", + "metadata": {}, + "source": [ + "Builder — позволяет отделить создание сложного объекта от его представления. \n", + "Strategy — позволяет инкапсулировать разные алгоритмы поиска пути так, чтобы их можно было подставлять динамически. \n", + "Observer — позволяет обеспечить реакцию отображения на изменения состояния без жёсткой привязки. \n", + "\n", + "Код можно найти в репозитории: http://31.128.43.79:3000/musinaa/2026-rff_mp" + ] + }, + { + "cell_type": "markdown", + "id": "6ffa70d6", + "metadata": {}, + "source": [ + "# 2. Практическая часть\n", + "# 2.0 Подготовим окружение" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d457dda4", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "sys.path.insert(0, os.path.abspath( '../'))\n", + "\n", + "from task2.mazeBuilder import TextFileMazeBuilder\n", + "from task2.tester import Tester" + ] + }, + { + "cell_type": "markdown", + "id": "888f0e3c", + "metadata": {}, + "source": [ + "## 2.1 Данные для анализа\n", + "\n", + "В папке `mazeExamples` лежит несколько лабиринтов разных размеров: 5x5, 10x10, 50x50, 100x100. Для каждого лабиринта будем искать путь с помощью всех доступных алгоритмов поиска: BFS, DFS и A*. Измерения будем проводить 10 раз, а затем усреднённое значение записывать." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "22ac68eb", + "metadata": {}, + "outputs": [], + "source": [ + "builder = TextFileMazeBuilder()\n", + "tester = Tester(builder, \"docs/data/task2/results.csv\")\n", + "tester.setTestingDirectory(\"task2/mazeExamples\")\n", + "tester.test()\n", + "tester.saveCSV()" + ] + }, + { + "cell_type": "markdown", + "id": "27441b5f", + "metadata": {}, + "source": [ + "## 2.2 Данные по лабиринтам и графики" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "702c1844", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " Лабиринт 5x5\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ЛабиринтВремя (мс)Посещённые клеткиДлинна пути
Алгоритм
BFS5x50.07533287
DFS5x50.01840387
AStar5x50.02237187
\n", + "
" + ], + "text/plain": [ + " Лабиринт Время (мс) Посещённые клетки Длинна пути\n", + "Алгоритм \n", + "BFS 5x5 0.075332 8 7\n", + "DFS 5x5 0.018403 8 7\n", + "AStar 5x5 0.022371 8 7" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " Лабиринт 10x10\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ЛабиринтВремя (мс)Посещённые клеткиДлинна пути
Алгоритм
BFS10x100.4038145323
DFS10x100.0794383531
AStar10x100.0671462323
\n", + "
" + ], + "text/plain": [ + " Лабиринт Время (мс) Посещённые клетки Длинна пути\n", + "Алгоритм \n", + "BFS 10x10 0.403814 53 23\n", + "DFS 10x10 0.079438 35 31\n", + "AStar 10x10 0.067146 23 23" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " Лабиринт 50x50\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ЛабиринтВремя (мс)Посещённые клеткиДлинна пути
Алгоритм
BFS50x503.010086640427
DFS50x502.066407995435
AStar50x502.081632496427
\n", + "
" + ], + "text/plain": [ + " Лабиринт Время (мс) Посещённые клетки Длинна пути\n", + "Алгоритм \n", + "BFS 50x50 3.010086 640 427\n", + "DFS 50x50 2.066407 995 435\n", + "AStar 50x50 2.081632 496 427" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " Лабиринт 100x100\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ЛабиринтВремя (мс)Посещённые клеткиДлинна пути
Алгоритм
BFS100x10017.14356824951171
DFS100x1008.43086032191243
AStar100x1004.95179012861171
\n", + "
" + ], + "text/plain": [ + " Лабиринт Время (мс) Посещённые клетки Длинна пути\n", + "Алгоритм \n", + "BFS 100x100 17.143568 2495 1171\n", + "DFS 100x100 8.430860 3219 1243\n", + "AStar 100x100 4.951790 1286 1171" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "df = pd.read_csv(\"data/task2/results.csv\")\n", + "for name in [\"5x5\", \"10x10\", \"50x50\", \"100x100\"]:\n", + " print(f\"\\n Лабиринт {name}\")\n", + " display(df[df[\"Лабиринт\"] == name].set_index(\"Алгоритм\"))" + ] + }, + { + "cell_type": "markdown", + "id": "c7a1b48e", + "metadata": {}, + "source": [ + "Как видно из таблиц, A* рекордно низкое врея выполнения, а так же хорошая длинна пути, часто совпадающая с медленными алгоритмами вроде BFS. Примечательно, что у A* всегда посещает меньше клеток, чем остальные алгоритмы, сильнее всего это заметно на большом лабиринте в 100 клеток, где разрыв от BFS: примерно в 2 раза меньше посещённых клеток, с DFS и вовсе почти в 3 раза.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d5078321", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " Лабиринт maze_25x25_wo_exit\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ЛабиринтВремя (мс)Посещённые клеткиДлинна пути
Алгоритм
BFSmaze_25x25_wo_exit1.968229338-1
DFSmaze_25x25_wo_exit0.719102338-1
AStarmaze_25x25_wo_exit1.011797338-1
\n", + "
" + ], + "text/plain": [ + " Лабиринт Время (мс) Посещённые клетки Длинна пути\n", + "Алгоритм \n", + "BFS maze_25x25_wo_exit 1.968229 338 -1\n", + "DFS maze_25x25_wo_exit 0.719102 338 -1\n", + "AStar maze_25x25_wo_exit 1.011797 338 -1" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " Лабиринт maze_25x25_empty\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ЛабиринтВремя (мс)Посещённые клеткиДлинна пути
Алгоритм
BFSmaze_25x25_empty4.57453862549
DFSmaze_25x25_empty0.903779625337
AStarmaze_25x25_empty0.2176354949
\n", + "
" + ], + "text/plain": [ + " Лабиринт Время (мс) Посещённые клетки Длинна пути\n", + "Алгоритм \n", + "BFS maze_25x25_empty 4.574538 625 49\n", + "DFS maze_25x25_empty 0.903779 625 337\n", + "AStar maze_25x25_empty 0.217635 49 49" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tester.setTestingDirectory(\"task2/mazeExamplesSpeical\")\n", + "tester.writefile = \"../docs/data/task2/results2.csv\"\n", + "tester.test()\n", + "tester.saveCSV()\n", + "\n", + "df = pd.read_csv(\"data/task2/results2.csv\")\n", + "for name in [\"maze_25x25_wo_exit\", \"maze_25x25_empty\"]:\n", + " print(f\"\\n Лабиринт {name}\")\n", + " display(df[df[\"Лабиринт\"] == name].set_index(\"Алгоритм\"))" + ] + }, + { + "cell_type": "markdown", + "id": "41192153", + "metadata": {}, + "source": [ + "Из выходных данных видно, что A* всегда быстро находит путь в пустом лабиринте, в реальных системах это очень большой плюс. BFS и BFS, из-за своей особенности пытается найти кратчайший путь и ему приходится оббегать весь лабиринт в поисках оптимального пути. \n", + "\n", + "Для того, чтобы оценить различия в алгоритмах на обычных лабиринтах нагляднее, построем серию графиков." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "43409471", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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zvHjx2natClHjx7l008/ZfPmzTz55JO89dZbTJ48Ods+fXx8mD9/vlXZggULKFu2bLa6q1evZvjw4TRu3JiffvqJiIgIwsPD89TfdevWERERwcaNG6lfvz4jRozg+++/z9M+cmJe9sb8Y6ttO3fu5PHHHychIYElS5awevVqvLy86N69O999953N/TZq1Miyz3Xr1j1QG6dOncoLL7xAvXr1+P777/nmm2+4ffs2rVu35vjx4w+0bzODwcDQoUPR6XTZ7uvfvz/ff/8948aNY8eOHURERDBs2LBc7Xfz5s3odDratGlj8/7SpUuzaNEiq7L58+fj6+ubre6SJUt44oknMBqNLFq0iE2bNvHWW29lm4XZpEkTSpUqleMXG0II4QxSUlJ49913qVatGm5ubjz00EMMHTqUW7duZau7atUqWrRoQalSpShVqhSPPPIIS5YssaqzdetW2rdvT+nSpSlZsiStWrXK9kW7rS+qIyMjbX6QbNCgQbYP2w/yPDk9V16/NL7XWq85fSiOjIykR48e+Pj4UKJECRo1apSr9yG29nf9+nWCgoKoW7cucXFxVvVz+lI/6+sYFxfHkCFDCAwMxM3NjWrVqjF58mT0er3V897rx/wB3/ycmb8I379/P2XKlOHZZ5+17NM8eSLz6wnQoUOHXE2GEEIIUXhSUlIAcHd3z9Pj8vqZ9V6fGfPi7NmzDBkyhO+//55169bRq1cvhg0bxpQpU3L1eA8PD6vP8BEREUydOtWqzpAhQ3BxcWHx4sVW5Tdu3GDNmjUMGjSIEiVKsH79ess+zBMHMy95s379+hzbsW/fPpYtW/bAr4cQxY0s1SIcXubTr8B0gJw/fz6dO3fOVtdgMLBlyxZKlCgBQOfOnalatSoffPABW7ZsAWDkyJF4eXmxe/duSpcuDUDHjh1JTU3l448/5q233rIaFH/llVeYO3cun376KeXLlyc5OZmlS5fyyiuvMGPGDKvn//PPP9FqtSxZssQyIz6vp4s1atTI8k3vo48+ytq1azl48CB9+vTJ035sybrsja22jRs3jrJly7Jjxw7Lh/Nu3brxyCOPMHr0aPr06WP1jXtaWho+Pj6WnO43K/teLly4wMSJE3nzzTf57LPPLOUdO3akZs2aTJ48OcfB+7yYP38+Z86coX///ixdutTqvj///JNevXoxdOhQS9nu3btztd+IiAhq1qxpc1ADTN/Qf/HFF7z//vu4ublx6dIlNmzYwIgRI5g5c6alXlJSEiNHjqRVq1Zs27bN8nq3b98+2z51Oh3BwcH8+eefuWqjEEI4GkVR6NmzJ7///jvvvvsurVu35siRI0ycONHyQc/84fmDDz5gypQp9OrVi1GjRuHt7c3Ro0c5d+6cZX8rV66kX79+PPXUU6xYsQJXV1cWL15M586d+fXXX23+rc2PonqegrR9+3a6dOlCs2bNWLRoEd7e3qxZs4bnnnuOu3fv5mmG2fXr13n88cdJT09n+/bt+Pv726y3bt06KlasCMAbb7xhdV9cXByPPvooWq2WDz74gBo1ahAREcH//vc/zp49y7Jly6hYsaLVBImvvvqKJUuWWJWVL1/e5nPv37+fTp060bFjR1avXn3P2Yvff/99toF0IYQQRc/8GTYvZ6jl5zPrvT4z5sWyZcsst41GI6GhoSiKwty5c5kwYcJ9l9vUarXZxkSyTqby8/Pj+eef58svv+SDDz7Azc0NMB0TU1NTLcfXzOvAm7+AqFevXrb9Z2U0Ghk6dCjdu3fn8OHD9+mxEI5FBs6Fw/v666+pW7cuYDpIrl+/nqFDh2IwGLKdHtWrVy/LoDlgmSm9evVqDAYD6enp/P7777z++uuULFnSMrMI4IknnmD+/Pns3buXrl27WsqbNm1KcHAwX3zxBePHj+fbb7+lbNmydOnSJdvA+cMPP4zRaGTevHkMHDiQUqVKYTAY8tRf8wz727dvM2/ePDQaDe3atcuxnnnJmIJw584d9u3bx+uvv241+KvT6QgLC2Ps2LGcOnXKak3a5ORkfHx8crX/zK83mA7Amf3666/o9Xr69etnVbdEiRK0bdvW5nIk99tnVleuXGHixIlMmDCB5OTkbPc//PDDbNu2jX379hEcHIyLi8t992l2+fJl/Pz8cry/V69erFq1ih9++IEXX3yRhQsX8thjj1GvXj2renv27CExMZE33ngjV9n6+flx4MCBXLVRCCEczW+//cavv/7KjBkzeOeddwDTF6qVKlXiueee4+uvv2bw4MHExMQwdepUXnzxRVauXGl5fMeOHS237969y/Dhw+nWrZvVrKonnniCxo0b895777Fv374HbnNRPU9Be+ONN6hfvz7btm2zDCJ37tyZ69ev895779GvXz+02vuf0Hr9+nXat29/z0HztLQ0wPQ+KzAwEMAyocFs0qRJ3Lx5k2PHjlG5cmXA9CWyh4cHo0eP5p133sn2gd98Nt39BgEOHDiQ60HzO3fuMGrUKIYOHWr1xb4QQoiiZz6DKS9Ln+XlMyvc/zMjmL7Yz/pZ1NbyK9u2bWPq1KkcOHCAxMREq/uuXr1aYEu4DR8+nBUrVlg+axqNRhYuXMiTTz75wBddX7x4McePH+eHH36wOTYhhCOTpVqEw6tbty4hISGEhITQpUsXFi9eTKdOnRgzZky2U7RtfTDz9/cnLS2NpKQk4uPj0ev1zJs3D1dXV6ufJ554ArA9C3vYsGEsWrQIvV7P559/nuOA5uuvv87gwYMZP348ZcuWxdXVNccZVjl5+OGHcXV1xcfHhylTpvD+++/TpUsXm/1ydXXFzc2NqlWrMnr0aMu3xvl18+ZNFEWxzPzKLCAgAID4+Hir8uvXr1OuXLn77vvYsWPZXvOxY8da1bly5Qpg+hCdte53332XLZs7d+5kq/fcc8/dsx3vvPMO/v7+vP322zbvX7FiBQEBATRv3hwPDw+b7cxJcnKy1Rc3Wbm4uPDaa68xf/580tLS+PLLL22ujXft2jUAy0DC/ZQoUSLHN3RCCOHotm3bBpBttvOzzz6Lp6enZemTLVu2WE6rzsmePXu4ceMG/fv3R6/XW36MRiNdunThwIED3Llz54HbnJ/nMX8hbv651xfvmeuZ93u/uvfzzz//cPLkSV588cVsz/HEE08QGxvLqVOn7ruf+Ph42rdvz5EjR/jxxx9zfB9kPm7d67i5efNm2rVrR0BAgFV7zBMcdu7ced/22BIZGUmnTp0oVaoUq1atuu86uR9++CHp6el8+OGH+Xo+IYQQBefUqVNUqFABLy+vXD8mt59Zze73mRFMy7dm/Sz6yy+/WNUxn9kE8OWXX/Lnn39y4MABxo8fD1Cgn+EaNWpE69atLUuwbN68mbNnz9r8vJkX169f5/3332fcuHFUq1atIJoqRLEiM86FUwoKCuLXX3/l9OnTPProo5byrOtnmsvc3NwoVaoUrq6ultnTOX2wtnUw6NOnD6NGjWL06NGcPn2agQMHEh0dna2eu7s7ixcv5ty5c5w7d45vvvmGxMREOnTokOu+bdy4kYoVK5KWlsahQ4cYN24cKSkp2Wa3b926FW9vb1JSUtixYweTJk1Cr9czZ86cXD9XVmXLlkWr1RIbG5vtPvNFLTO/4bh79y6XLl3i4Ycfvu++a9SowZo1a6zKVq5caXXxU/O+165dS5UqVe67Tw8PD3bt2mVVtm3bthwHunfv3s3KlSv59ddfLaevZRUcHMy3337LI488wmuvvcYLL7yQrZ05KVeuHDdu3LhnnVdffZUpU6YwZswY3N3deeqpp/jmm2+s6phPKc96Cl5Obty4kac3gkII4Uji4+NxcXHJttyGRqPB39/f8oVubr50NH9B27t37xzr3LhxA09Pzwdqc36eJ7dftJu/NM4N85fWYDpmPvzwwwwdOpQhQ4bk2ObRo0czevRom/vLzfJz7733HtWrV8ff358JEybw448/5rgvrVZr85oxmdu0adOmHPub1+XwzF588UWaN2/O7t27WbRo0T2vZXLq1Clmz57NV199hbe3d76eTwghRMFQFIUDBw7QpEmTXD8mL59ZIXefGcE0RmA+E87s7bfftrpA55o1a3B1dWXz5s1WXxT/9NNPuW5/Xrz11ls8++yzHDp0iPnz51OrVi2rM+/y491336VMmTKMGTOmgFopRPEiA+fCKZkHrbN+iF63bh0zZ860HJRu377Npk2baN26NTqdjpIlS9KuXTuioqIICgq654EwMzc3N1599VX+97//MXjw4Huup/bZZ5+xfft2IiIiaNKkSZ4/1DVs2NByKlXLli3ZunUrK1euzDZwHhwcbBksfeyxx/jxxx/Zv39/np4rK09PT5o1a8a6dev45JNP8PDwAEzLn6xcuZLAwEBq1aplqb9x40YURcnxYpiZlShRwmp9dSDbWqGdO3fGxcWFf//9l2eeeea++9Rqtdn2mdN6dealfZ555pl7vnnQ6/W8+OKLNGjQgOnTp+Pi4pLrNU3r1Klz3zdBfn5+9OnTh7lz5/LRRx/ZvLhKy5Yt8fb2ZtGiRTz//PP3Xa7lzJkz97wAnBBCODJfX1/0ej3Xrl2zOu4rikJcXBxNmzYFrL90rFSpks19mY+b8+bNy3Epj4I4ZTo/z2P+QtzsxIkT9OvXL9vj8vKlceYvrRMSEli2bBmvvfYaFSpU4JFHHrHZ5nfffZdevXrZbHPt2rVtlmdWvXp1tm/fzuHDh+natStLlixh0KBB2er9/fffVKtW7Z4XGStXrhxBQUF89NFHNu83nw2XVz169GD16tV88MEHjBkzhnbt2uV4HB02bBjNmjWzmYUQQoii9fvvvxMfH8/jjz+e68fk5TNrbj8zgul9R9bPot7e3lYD5xqNBhcXF6tjXXJycraJUwXl6aefpnLlyowaNYqdO3cye/bsB1rWdf/+/SxZsoRNmzbd8wwxIRyZDJwLh3f06FHLKcbx8fGsW7eOLVu28PTTT2ebHa7T6ejYsSMjR47EaDQyffp0EhMTmTx5sqXO3Llzeeyxx2jdujWvv/46VatW5fbt2/zzzz9s2rTJckp4VqNGjaJt27YEBQXds63jxo1j0qRJefoWPLOoqCji4uJIS0sjKiqKLVu2EBoamq3eP//8w/Xr10lNTWXXrl0cPXr0gU/DApg2bRodO3akXbt2jB49Gjc3NxYsWMDRo0dZvXo1Go2GhIQEFi5cyNSpUy2vZUGoWrUqH374IePHj+fMmTN06dKFsmXLcuXKFfbv34+np6dVlnkRERFBiRIl2LRp0z3rTZo0iePHjxMVFXXfU7ezCg0NZenSpZw+fdrqC4asZsyYQf/+/a3OlsisVKlSfPrpp7zyyit06NCBwYMHU6FCBf755x8OHz7M/PnzLXXj4+P5+++/7zlbTgghHFn79u2ZMWMGK1eutDpl+scff+TOnTuWi2x26tQJnU7HwoULadGihc19tWrVijJlynD8+PECOWbmJD/Pk/kL8XvJy5fGWb+0DgkJ4dtvv2X//v3ZBs5r165NzZo1OXz4MFOnTs1Vm20ZO3Ys/v7++Pv7M2zYMIYPH07r1q2tjosJCQls376dJ5988p776tatG7/88gs1atS458z0vJo5cyYuLi5MnjyZ3377jb59+7J///5sgwJr165l27ZtHDx4sMCeWwghRN6lpqby888/89Zbb6HT6ahXrx579+61qpOYmEhycjJ79+6lXr16KIqS58+suf3MmFtPPvkks2bNom/fvrz66qvEx8fzySefWC5qXtB0Oh1Dhw5l7NixeHp65umi3rZ88cUXdO/e/b7HayEcmQycC4f38ssvW257e3tTrVo1Zs2aZbkydGZvvvkmKSkpvPXWW1y9epX69evz888/06pVK0udevXqcejQIcv64VevXqVMmTLUrFnTss65LWXKlLnnkiupqam8+OKLhISEMG7cuHz2FsssL/P66C+99JLND7DmQQF3d3ceeughRowYwZQpU/L9vGZt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brRs2RIAcPXqVRw7dqzU+lyZzWYkJSWVO37a3r17YbPZ8MYbbzjPgLuOOQcAnTp1wpo1ayCEcCbkX375BXq9Hu3atXPOl5ubi+effx5vv/02dDpdmds7cOAA8vLyYDKZnPsTEBCA6OjoKq2nZNyK/jnz1Pbt2zFx4kQMHz4cgGOMttOnT1dpHUREVPuYp5mnAeZpIqKGinmaeRpgnqaGhVecE9WR9u3bY+/evdi0aROOHTuGF154wXkzjCLvvvsuDh8+jNOnT2PlypXYvHlzqa+DAcDAgQMxb948LFiwoNS0Jk2a4Mknn8TMmTOxYsUKJCcnIyEhAe+88w5WrFjhNu+LL76IH374AYcOHcLEiRMRGhpa6o7YRY4ePYoxY8YgKCgId999d5nztGvXDjabDYsXL8bJkyfx6aef4r333nOb569//StOnz6Nv/3tb0hKSsK3336L2bNnY9q0aW5fE/vss8/Qrl27cvsDOL4uN2XKFBw5cgTfffcd5syZg2nTprl9bc2T9dRU+/btER8fj8TERBw4cAAPPfSQ80oFIiJqHJinHZiniYioIWKedmCeJqpbvOKcqI5MnToViYmJGD16NCRJwpgxYxAXF4fvvvvOOc+GDRswZ84cZGdnIyYmBs899xwmT55c5vpmzpxZ7rb+/e9/IywsDK+++ipOnjyJoKAg9OjRA88995zbfPPnz8f06dNx/PhxxMbGYt26ddDr9WWuc+7cubDZbNiyZYvb+GWuunfvjoULF+I///kPnn32WQwYMACvvvqq27hyLVu2xPr16/HMM88gNjYWzZo1w9ixY/Hqq6+6rSs3NxdvvPFGufsIAH/605/QoUMHDBgwAAUFBXjwwQcxd+7cKq+npv773/9i8uTJ6NevH0JDQ/H0008jKyurVrdJRETexTztwDxNREQNEfO0A/M0Ud2ShBCivjtBRHXrp59+wm233YarV68iKCiovrtTLRMnTsS1a9ewdu3a+u4KERGRVzFPExERNVzM00TqwaFaiIiIiIiIiIiIiIhcsHBOREREREREREREROSCQ7UQEREREREREREREbngFedERERERERERERERC5YOCciIiIiIiIiIiIicsHCORERERERERERERGRCxbOiYiIiIiIiIiIiIhcsHBOREREREREREREROSChXMiIiIiIiIiIiIiIhcsnBMRERERERERERERuWDhnIiIiIiIiIiIiIjIBQvnREREREREREREREQu/h8PvnDvwL8cMQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "df = pd.read_csv(\"data/task2/results.csv\")\n", + "\n", + "size_order = [\"5x5\", \"10x10\", \"50x50\", \"100x100\"]\n", + "algo_order = [\"BFS\", \"DFS\", \"AStar\"]\n", + "colors = {\"BFS\": \"blue\", \"DFS\": \"green\", \"AStar\": \"orange\"}\n", + "\n", + "x = range(len(size_order))\n", + "fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n", + "\n", + "params = [\"Время (мс)\", \"Посещённые клетки\", \"Длинна пути\"]\n", + "titles = [\"Время выполнения (мс)\", \"Посещённые клетки\", \"Длина пути\"]\n", + "\n", + "for i, (param, title) in enumerate(zip(params, titles)):\n", + " ax = axes[i]\n", + " for algo in algo_order:\n", + " values = []\n", + " for s in size_order:\n", + " val = df[(df[\"Алгоритм\"] == algo) & (df[\"Лабиринт\"] == s)][param].values\n", + " if len(val) > 0:\n", + " values.append(val[0])\n", + " else:\n", + " values.append(None)\n", + " ax.plot(x, values, marker='o', label=algo, color=colors[algo], linewidth=2, markersize=6)\n", + " ax.set_xticks(x)\n", + " ax.set_xticklabels(size_order)\n", + " ax.set_title(title)\n", + " ax.set_xlabel(\"Размер лабиринта\")\n", + " if i == 0:\n", + " ax.set_ylabel(\"Значение\")\n", + " ax.grid(True, linestyle='--', alpha=0.7)\n", + "\n", + "# Общая легенда сверху\n", + "handles, labels = axes[0].get_legend_handles_labels()\n", + "fig.legend(handles, labels, loc='upper center', bbox_to_anchor=(0.5, 1.05), ncol=3)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "c573b32b", + "metadata": {}, + "source": [ + "## 3. Применение паттерна Observer\n", + "\n", + "Для того, чтобы продемонстрировать работу этого паттерна необходимо иметь возможность очищать вывод, но в Jupyter такой возможности нет. В терминале всё работает корректно." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "898e8536", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[H\u001b[2J\u001b[48;5;9m\u001b[38;5;7mS\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;12m\u001b[38;5;7mE\u001b[0m\n", + "\n" + ] + } + ], + "source": [ + "from task2.consoleView import ConsoleView\n", + "from task2.mazeSolver import MazeSolver\n", + "from task2.strategyObjects.AStar import AStar\n", + "\n", + "maze = builder.buildFromFile(\"../task2/mazeExamples/25x25.txt\")\n", + "console = ConsoleView(maze)\n", + "solver = MazeSolver(AStar(), maze)\n", + "solver.attach(console)\n", + "console.render()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "aa5a4c8c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[H\u001b[2J\u001b[48;5;9m\u001b[38;5;7mS\u001b[0m \u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;196m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;161m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\n", + "\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\n", + "\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\n", + "\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\n", + "\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;91m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\n", + "\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + "\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \n", + " \u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;126m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m \u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;56m\u001b[38;5;10m+\u001b[0m\u001b[48;5;7m\u001b[38;5;7m#\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;21m\u001b[38;5;10m+\u001b[0m\u001b[48;5;12m\u001b[38;5;7mE\u001b[0m\n", + "\n" + ] + } + ], + "source": [ + "# При нахождении решения рендер должен произойти автоматически\n", + "_ = solver.solve()" + ] + }, + { + "cell_type": "markdown", + "id": "484b4ef6", + "metadata": {}, + "source": [ + "## 4. Применимость паттернов\n", + "После выполнения работы можно оценить, насколько для этого помогли паттерны ООП. \n", + "Самый полезный паттерн - это конечно Strategy. Он позволил без лишней мороки провести замеры серийно, не используя каждый алгоритм вручную. \n", + " \n", + "Вторым по значимости я бы назвал Observer, он позволил сделать рендер лабиринта проще, однако сильнее всего оценить его получилось бы совместно с паттерном Commad и игроком с передвижениями. Его я не успел реализовать.\n", + " \n", + "Третий - Builder. В этой работе его преимущества оценить трудно из-за того, что использовался только один формат файла - plaintext. Однако, если понадобится искать пути в больших лабиринтах, то их придётся хрвнить в другом формате, например бинарном, и тогда преимщества паттерна Builder станут очевидны. \n", + " \n", + "Так же я создал класс-оркестратор MazeSolver, который помог перенести почти весь код тестов в одно место и удобно эти тесты использовать. Этот паттерн я так же считаю полезным. " + ] + }, + { + "cell_type": "markdown", + "id": "d4026233", + "metadata": {}, + "source": [ + "## 5. Вывод\n", + "Применение объектно-ориентированного подхода и паттернов проектирования позволило разделить ответственность между независимыми модулями и обеспечить простоту внесения изменений. Если бы логика поиска пути, построения лабиринта и визуализации была сосредоточена в одном классе или реализована процедурно, любое расширение требовало бы переписывания значительной части кода." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/MusinAA/docs/data/task1/performance_plot.png b/MusinAA/docs/data/task1/performance_plot.png new file mode 100644 index 00000000..f4080211 Binary files /dev/null and b/MusinAA/docs/data/task1/performance_plot.png differ diff --git a/MusinAA/docs/data/task1/results.csv b/MusinAA/docs/data/task1/results.csv new file mode 100644 index 00000000..82055901 --- /dev/null +++ b/MusinAA/docs/data/task1/results.csv @@ -0,0 +1,31 @@ +Структура,Режим,Вставка,Поиск,Удаление +Связанный список,Cлучайный,0.09829891600020346,0.0007068659997457871,0.0005386180000641616 +Хэш-таблица,Cлучайный,0.04794800999934523,0.00069890399936412,0.00033887100016727345 +Бинарное дерево,Cлучайный,0.014146466999591212,0.00019723300010809908,0.00022258500030147843 +Связанный список,Отсортированный,0.16592630900049699,0.0017924130006576888,0.001010537000183831 +Хэш-таблица,Отсортированный,0.04675658399992244,0.000497691000418854,0.00027706199944077525 +Бинарное дерево,Отсортированный,0.098506346999784,0.001621370999600913,0.0008596789994044229 +Связанный список,Cлучайный,0.07528530299987324,0.0006713170005241409,0.0004351130000941339 +Хэш-таблица,Cлучайный,0.04169118899972091,0.0004370679998828564,0.0002442360000713961 +Бинарное дерево,Cлучайный,0.009762656000020797,0.0001406600003974745,8.869900011632126e-05 +Связанный список,Отсортированный,0.15083865700034949,0.001965620000191848,0.0009268670000892598 +Хэш-таблица,Отсортированный,0.04658651899990218,0.0004731760000140639,0.00026295399948139675 +Бинарное дерево,Отсортированный,0.10888835700006894,0.0032681640004739165,0.0010110960001838976 +Связанный список,Cлучайный,0.09252672599996004,0.0014638780003224383,0.0009516599993730779 +Хэш-таблица,Cлучайный,0.04701576600018598,0.0004413979995661066,0.00024472499990224605 +Бинарное дерево,Cлучайный,0.010519597999518737,0.00015120700027182465,0.00012815900026907912 +Связанный список,Отсортированный,0.15883956299967394,0.001480011000239756,0.0007378059999609832 +Хэш-таблица,Отсортированный,0.043343710000044666,0.0005192710004848777,0.0002623249993121135 +Бинарное дерево,Отсортированный,0.19170180800028902,0.0011184409995621536,0.0008248280000771047 +Связанный список,Cлучайный,0.09595573600017815,0.0009538959993733442,0.0004928719999952591 +Хэш-таблица,Cлучайный,0.04453241200008051,0.000944256999900972,0.0005029280000599101 +Бинарное дерево,Cлучайный,0.011908257000868616,0.0001221530001203064,0.00011502899997140048 +Связанный список,Отсортированный,0.16769071699945926,0.0015361639998445753,0.0011414199998398544 +Хэш-таблица,Отсортированный,0.05018426599963277,0.0006002179998176871,0.000283696000224154 +Бинарное дерево,Отсортированный,0.09999411199987662,0.0010742320000645122,0.0009550129998388002 +Связанный список,Cлучайный,0.08812657299949933,0.0006700599997202517,0.0006053869992683758 +Хэш-таблица,Cлучайный,0.042967892999513424,0.0005705349994968856,0.0002917279998655431 +Бинарное дерево,Cлучайный,0.01326883900037501,0.00013954399946669582,0.00013297800069267396 +Связанный список,Отсортированный,0.16893773900028464,0.0017602859998078202,0.0007569420004074345 +Хэш-таблица,Отсортированный,0.05997269399995275,0.000543855999239895,0.0002741980006248923 +Бинарное дерево,Отсортированный,0.11176624800009449,0.0010512540002309834,0.0007160159993873094 diff --git a/MusinAA/docs/data/task2/results.csv b/MusinAA/docs/data/task2/results.csv new file mode 100644 index 00000000..17548aed --- /dev/null +++ b/MusinAA/docs/data/task2/results.csv @@ -0,0 +1,16 @@ +Алгоритм,Лабиринт,Время (мс),Посещённые клетки,Длинна пути +BFS,10x10,0.4038135000882903,53,23 +BFS,5x5,0.07533170064562,8,7 +BFS,100x100,17.14356810080062,2495,1171 +BFS,50x50,3.010086300491821,640,427 +BFS,25x25,1.0405578999780118,232,173 +DFS,10x10,0.07943829987198114,35,31 +DFS,5x5,0.018403499416308478,8,7 +DFS,100x100,8.430859900545329,3219,1243 +DFS,50x50,2.0664067997131497,995,435 +DFS,25x25,0.5787261994555593,316,173 +AStar,10x10,0.0671462003083434,23,23 +AStar,5x5,0.022370600345311686,8,7 +AStar,100x100,4.951790099585196,1286,1171 +AStar,50x50,2.081632300541969,496,427 +AStar,25x25,0.5791453000711044,186,177 diff --git a/MusinAA/docs/data/task2/results2.csv b/MusinAA/docs/data/task2/results2.csv new file mode 100644 index 00000000..d12deec5 --- /dev/null +++ b/MusinAA/docs/data/task2/results2.csv @@ -0,0 +1,7 @@ +Алгоритм,Лабиринт,Время (мс),Посещённые клетки,Длинна пути +BFS,maze_25x25_wo_exit,1.9682294001540868,338,-1 +BFS,maze_25x25_empty,4.574537699954817,625,49 +DFS,maze_25x25_wo_exit,0.719102000221028,338,-1 +DFS,maze_25x25_empty,0.903778699648683,625,337 +AStar,maze_25x25_wo_exit,1.0117966015968705,338,-1 +AStar,maze_25x25_empty,0.21763520016975235,49,49 diff --git a/MusinAA/task1/__init__.py b/MusinAA/task1/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/MusinAA/task1/structures/BinaryTree.py b/MusinAA/task1/structures/BinaryTree.py new file mode 100644 index 00000000..e98c31a7 --- /dev/null +++ b/MusinAA/task1/structures/BinaryTree.py @@ -0,0 +1,88 @@ +""" +Двоичное дерево поиска + +Узел — словарь: +{'name': 'Имя', 'phone': '123', 'left': None, 'right': None}. +""" + +def bst_insert(root: dict|None, name: str, phone: str) -> dict: + """Итеративно вставляет, возвращает новый корень (если корень меняется).""" + if root == None: + return {'name': name, 'phone': phone, 'left': None, 'right': None} + + # '674' < '722' == True, lol + current = root + while True: + if current['name'] == name: + current['phone'] = phone + return root + elif name < current['name']: + if current['left'] == None: + current['left'] = bst_insert(None, name, phone) + return root + else: + current = current['left'] + else: + if current['right'] == None: + current['right'] = bst_insert(None, name, phone) + return root + else: + current = current['right'] + # Увы, это самый лаконичный вариант, который я придумал. + + +def bst_find(root: dict|None, name: str) -> str|None: + """Поиск в ширину.""" + node = find_node_to_delete(root, name) + if node != None: + return node['phone'] + +def find_node_to_delete(root: dict|None, name: str) -> dict|None: + """Поиск в ширину.""" + while root != None: + if root['name'] == name: + return root + elif name < root['name']: + root = root['left'] + else: + root = root['right'] + return None + +def find_minimal_child(root: dict) -> dict|None: + while root['left']: + root = root['left'] + return root + +def bst_delete(root: dict, name: str) -> None: + """Удаляет узел и возвращает новый корень.""" + if root is None: + return None + + if name < root['name']: + root['left'] = bst_delete(root['left'], name) + elif name > root['name']: + root['right'] = bst_delete(root['right'], name) + else: + # Случай 1: нет детей или один ребенок + if root['left'] is None: + return root['right'] + elif root['right'] is None: + return root['left'] + + # Случай 2: два ребенка + min_node = find_minimal_child(root['right']) + root['name'] = min_node['name'] + root['phone'] = min_node['phone'] + root['right'] = bst_delete(root['right'], min_node['name']) + + return root + + +def bst_list_all(root: dict) -> list: + """Центрированный обход. + Рекурсивно собирает записи в отсортированном порядке.""" + + if root is None: + return [] + node_values = {"name": root['name'], "phone": root['phone']} + return bst_list_all(root['left']) + [node_values] + bst_list_all(root['right']) \ No newline at end of file diff --git a/MusinAA/task1/structures/HashTable.py b/MusinAA/task1/structures/HashTable.py new file mode 100644 index 00000000..dd165999 --- /dev/null +++ b/MusinAA/task1/structures/HashTable.py @@ -0,0 +1,59 @@ +""" +Хеш-таблица + +Хранится как список buckets фиксированной длины, +каждый элемент — голова связного списка (или None). +""" + +from task1.structures.LinkedList import * + +def hash_fun(name: str, size: int) -> int: + """Принимает имя и возвращает индекс бакета для него.""" + if size <= 0: + raise ValueError("size должен быть больше 0") + + hashSum = 0 + n = size+1 + base = 1103 # ord('я') + for letter in name: + hashSum += ord(letter) * pow(base, n) + n -= 1 + return int(hashSum) % size + +def ht_insert(buckets: list|None, name: str, phone: str, blen:int = 50) -> list: + """Возвращает новый массив бакетов + Вычисляет индекс, вызывает ll_insert для соответствующего бакета. + Функция не меняет размер массива бакетов автоматически!""" + if buckets == [] or buckets == None: + buckets = [None] * blen + # raise ValueError("Длинна buckets должна быть больше 0") + + size = len(buckets) + index = hash_fun(name, size) + buckets[index] = ll_insert(buckets[index], name, phone) + return buckets + +def ht_delete(buckets: list, name: str) -> list: + """Возвращает новый массив бакетов без элемента с именем name""" + if buckets == []: + raise ValueError("Длинна buckets должна быть больше 0") + + size = len(buckets) + index = hash_fun(name, size) + buckets[index] = ll_delete(buckets[index], name) + return buckets + +def ht_find(buckets: list|None, name: str) -> str|None: + if buckets == [] or buckets == None: + raise ValueError("Длинна buckets должна быть больше 0") + + size = len(buckets) + index = hash_fun(name, size) + return ll_find(buckets[index], name) + +def ht_list_all(buckets): + """Собирает все записи из всех бакетов и сортирует""" + allRecords = [] + for bucket in buckets: + allRecords.extend(ll_list_all(bucket)) + return sorted(allRecords, key=lambda x: x[0]) \ No newline at end of file diff --git a/MusinAA/task1/structures/LinkedList.py b/MusinAA/task1/structures/LinkedList.py new file mode 100644 index 00000000..7022f7f7 --- /dev/null +++ b/MusinAA/task1/structures/LinkedList.py @@ -0,0 +1,63 @@ +""" +Связный список (LinkedListPhoneBook) + +Узел представляется словарём: +{'name': 'Имя', 'phone': '123', 'next': None}. +""" + + +def ll_insert(head : dict|None, name: str, phone: str) -> dict: + """ + Проходит до конца (или сразу добавляет в конец) и возвращает новую + голову (если вставка в начало) или изменяет список по ссылке. + Удобнее возвращать новую голову, если вставка может быть в начало. + """ + + newNode = {'name': name, 'phone': phone, 'next': None} + if head == None: + return newNode + + currentNode = head + while currentNode['next'] != None: + if currentNode['name'] == name: + currentNode['phone'] = phone + return head + currentNode = currentNode['next'] + currentNode['next'] = newNode + return head + +def ll_find(head : dict|None, name: str) -> str|None: + """Ищет узел, возвращает телефон или None.""" + currentNode = head + while currentNode != None: + if currentNode['name'] == name: + return currentNode['phone'] + currentNode = currentNode['next'] + return None + +def ll_delete(head : dict|None, name: str) -> dict|None: + """Удаляет узел, возвращает новую голову.""" + if head == None: + return None + + if head['name'] == name: + return head['next'] + + currentNode = head + while currentNode['next'] != None: + if currentNode['next']['name'] == name: + currentNode['next'] = currentNode['next']['next'] + return head + currentNode = currentNode['next'] + return head + +def ll_list_all(head: dict|None) -> list: + """Cобирает все записи в список и сортирует. + сортировка вынесена отдельно).""" + records = [] + currentNode = head + while currentNode != None: + records.append((currentNode['name'], currentNode['phone'])) + currentNode = currentNode['next'] + records.sort(key=lambda item: item[0]) + return records \ No newline at end of file diff --git a/MusinAA/task1/structures/__init__.py b/MusinAA/task1/structures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/MusinAA/task1/util/__init__.py b/MusinAA/task1/util/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/MusinAA/task1/util/randomNames.py b/MusinAA/task1/util/randomNames.py new file mode 100644 index 00000000..2e08f82b --- /dev/null +++ b/MusinAA/task1/util/randomNames.py @@ -0,0 +1,55 @@ +import random + +names_pool = ( + "Иван", "Мария", "Петр", "Анна", "Сергей", "Елена", "Алексей", "Ольга", + "Дмитрий", "Татьяна", "Михаил", "Наталья", "Андрей", "Ирина", "Николай", + "Светлана", "Владимир", "Екатерина", "Александр", "Юлия", "Павел", "Ксения", + "Виктор", "Анастасия", "Артем", "Виктория", "Максим", "Полина", "Даниил", + "София", "Евгений", "Алиса", "Станислав", "Дарья", "Георгий", "Вероника", + "Кирилл", "Маргарита", "Тимофей", "Арина", "Руфина", "Илларион", "Стелла", + "Роман", "Валерия", "Игорь", "Алина", "Олег", "Диана", "Юрий", "Милана", + "Василий", "Ева", "Никита", "Алиса", "Константин", "Кира", "Денис", "Ангелина", + "Вячеслав", "Мирослава", "Григорий", "Эмилия", "Леонид", "Василиса", "Руслан", + "Стефания", "Арсений", "Есения", "Антон", "Яна", "Матвей", "Любовь", "Семен", + "Надежда", "Федор", "Софья", "Лев", "Варвара", "Егор", "Амелия", "Борис", + "Агата", "Захар", "Камилла", "Давид", "Олеся", "Ярослав", "Людмила", "Данила", + "Регина", "Марк", "Каролина", "Артур", "Нелли", "Глеб", "Инна", "Платон", + "Нина", "Святослав", "Римма", "Родион", "Лидия", "Эдуард", "Жанна", "Вадим", + "Рената", "Савелий", "Алла", "Назар", "Снежана", "Демид", "Лариса", "Филипп", + "Злата", "Тимур", "Майя", "Клим", "Эльвира", "Дамир", "Таисия", "Илья", + "Роза", "Виталий", "Азалия", "Степан", "Лиана", "Богдан", "Инесса", "Эрик", + "Ариана", "Алан", "Юлиана", "Лука", "Антонина", "Мирон", "Клавдия", "Гордей", + "Руслана", "Макар", "Елизавета", "Северин", "Александра", "Моисей", "Агафья", + "Наум", "Серафима", "Влад", "Фаина", "Кузьма", "Пелагея", "Ермак", "Ульяна", + "Тарас", "Марианна", "Остап", "Бронислава", "Архип", "Владислава", "Фома", + "Станислава", "Еремей", "Зинаида", "Прохор", "Раиса", "Мстислав", "Галина", + "Ростислав", "Валентина", "Серафим", "Евдокия", "Лаврентий", "Кристина", + "Никон", "Анфиса", "Феликс", "Лия", "Иннокентий", "Роксана", "Всеволод", + "Эвелина", "Модест", "Юнона", "Трофим", "Изабелла", "Аполлон", "Глория", + "Касьян", "Аврора", "Любомир", "Адель", "Бронислав", "Доминика", "Афанасий", + "Фрида", "Евстафий", "Ассоль", "Венедикт", "Цветана", "Епифан", "Мелисса", + "Добрыня" +) + +_non_existent_names = [ + "Ноль", "Целковый", "Полушка", "Четвертушка", "Осьмушка", + "Пудовичок", "Медячок", "Серебрячок", "Золотничок", "Девятичок" +] +assert set(names_pool).isdisjoint(set(_non_existent_names)), \ +"В списке несуществующих имён существуют существующие имена сущностей" +names_pool_to_find = random.choices(names_pool, k=100) + _non_existent_names + +def generate_phone(phone_len=11) -> str: + # 88005553535 + return str(random.randint(10**phone_len, 10**(phone_len+1)-1)) + +def generate_test_data(N=10000, _sorted=False): + records = [] + for i in range(N): + name = random.choice(names_pool) + phone = generate_phone() + records.append((name, phone)) + + if _sorted: + return sorted(records) + return records \ No newline at end of file diff --git a/MusinAA/task1/util/timeTester.py b/MusinAA/task1/util/timeTester.py new file mode 100644 index 00000000..3e3204e6 --- /dev/null +++ b/MusinAA/task1/util/timeTester.py @@ -0,0 +1,37 @@ +import time +import random +from typing import Callable, Any +from task1.util.randomNames import names_pool_to_find, names_pool + +def test(records: list, + insert_func: Callable[[Any, str, str], Any], + find_func: Callable[[Any, str], Any], + delete_func: Callable[[Any, str], Any]) -> dict: + data = None + + # Вставка всех записей + start = time.perf_counter() + for item in records: + data = insert_func(data, item[0], item[1]) + end = time.perf_counter() + insert_time = end - start + + # Поиск 110 случайных записей + start = time.perf_counter() + for name in names_pool_to_find: + find_func(data, name) + end = time.perf_counter() + find_time = end - start + + # Удаление 50 случайных записей + start = time.perf_counter() + for name in random.choices(names_pool, k = 50): + data = delete_func(data, name) + end = time.perf_counter() + delete_time = end - start + + return { + "insert_time" : insert_time , + "find_time" : find_time , + "delete_time": delete_time + } diff --git a/MusinAA/task2/.gitignore b/MusinAA/task2/.gitignore new file mode 100644 index 00000000..a548902a --- /dev/null +++ b/MusinAA/task2/.gitignore @@ -0,0 +1 @@ +maze_generator.py \ No newline at end of file diff --git a/MusinAA/task2/__init__.py b/MusinAA/task2/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/MusinAA/task2/consoleView.py b/MusinAA/task2/consoleView.py new file mode 100644 index 00000000..6192d6ee --- /dev/null +++ b/MusinAA/task2/consoleView.py @@ -0,0 +1,94 @@ +""" +Реализовать класс ConsoleView, который отображает лабиринт, +текущее положение игрока (если реализован пошаговый режим) и найденный путь. +Метод render(maze, player_position, path) рисует карту в консоли.""" + +import os + +from task2.mazeObjects.cell import Cell +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.path import Path +from task2.observerSubject import MazeEvent, MazeEventType, Observer + +SBROS = "\033[0m" + +WALL = "#" +EXIT = "E" +START = "S" +PATH_SYMBOL = "+" +SPACE_SYMBOL = " " + +# Я убрал аргументы из render(), чтобы не передавать их при каждом запуске. +# И работать внутри класса приятнее, чем тянуть эти аргументы туда-сюда +class ConsoleView(Observer): + maze:Maze|None + path:Path|None + + def __init__(self, maze:Maze|None=None, path:Path|None=None): + super().__init__() + self.maze = maze + self.path = path + + def _getCellColored(self, cell:Cell) -> str: + if cell.isWall: + # Белый + return self._fmt_str(7, 7, WALL) + elif cell.isExit: + # Кислотно-зелёный + return self._fmt_str(12, 7, EXIT) + elif cell.isStart: + # Кислотно-красный + return self._fmt_str(9, 7, START) + elif self.path and self.path.array: + if cell in self.path.array: + # Градиент + percent = self.path.array.index(cell) / len(self.path.array) + n = self._ANSICalculator(*self._getGradient(percent)) + return self._fmt_str(n, 10, PATH_SYMBOL) + return SPACE_SYMBOL + + def _fmt_str(self, bg:int, fg:int, symbol:str) -> str: + return f"\033[48;5;{bg}m\033[38;5;{fg}m{symbol}{SBROS}" + + def _ANSICalculator(self, r:int, g:int, b:int): + r = max(0, min(5, r)) + g = max(0, min(5, g)) + b = max(0, min(5, b)) + return 16 + 36*r + 6*g + b + + def _getGradient(self, percent:float): + r = 5 * (1-percent) + g = 0 + b = 5 * percent + return int(round(r)), int(round(g)), int(round(b)) + + def render(self, player_position=None): + """ + Печатем ячейку. + Цвет зависит от индекса ячейчки в массиве path. + Если в массиве нет - просто белый. + """ + + os.system('cls' if os.name == 'nt' else 'clear') + + if not self.maze: + print("Лабиринт ещё не загружен") + return None + + output = "" + for y in range(self.maze.height): + for x in range(self.maze.width): + cell = self.maze.getCell(x, y) + output += self._getCellColored(cell) + output += "\n" + print(output) + + def update(self, event: MazeEvent): + if event.evtype in (MazeEventType.MAZE_LOADED, MazeEventType.PATH_FOUND, MazeEventType.MOVE): + if event.evtype == MazeEventType.PATH_FOUND: + if not event.data: raise ValueError + self.path = event.data + if event.evtype == MazeEventType.MAZE_LOADED: + if not event.data: raise ValueError + self.maze = self.maze + self.render() diff --git a/MusinAA/task2/mazeBuilder.py b/MusinAA/task2/mazeBuilder.py new file mode 100644 index 00000000..65ff63ec --- /dev/null +++ b/MusinAA/task2/mazeBuilder.py @@ -0,0 +1,72 @@ +from abc import ABC, abstractmethod +from itertools import product +import sys +import os.path as path + +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell +from task2.observerSubject import MazeEvent, MazeEventType, Subject + +class MazeBuilder(ABC): + """Интерфейс MazeBuilder с методом buildFromFile(filename)""" + @abstractmethod + def buildFromFile(self, filename: str): + """Создание лабиринта из файла.""" + +class TextFileMazeBuilder(MazeBuilder): + """Читает файл, парсит символы, + создаёт объекты Cell, + задаёт координаты и флаги, + после чего возвращает готовый Maze.""" + + start:dict + end:dict + + def _cellStrategy(self, letter: str) -> Cell: + if letter == '#': + return Cell(isWall=True) + elif letter == ' ': + return Cell() + elif letter == 'S': + return Cell(isStart=True) + elif letter == 'E': + return Cell(isExit=True) + else: + sys.stderr.write(f"Неизвестный символ '{letter}' при загрузке из файла\n") + return Cell() + + def _updateStartEnd(self, letter: str, x:int, y:int) -> None: + if letter == 'S': + self.start = {'x': x, 'y': y} + elif letter == 'E': + self.end = {'x': x, 'y': y} + + def _generate_row_from_txt(self, filename: str) -> list[str]: + with open(filename) as file: + text = file.read() + text = text.strip() + if not text: + raise ValueError(f"Файл \"{filename}\" пуст") + text = text.split('\n') + return text + + def buildFromFile(self, filename: str): + rows = self._generate_row_from_txt(filename) + height = len(rows) + width = len(rows[0]) + array = [[Cell() for j in range(width)] for i in range(height)] + + try: + for x, y in product(range(width), range(height)): + cell = self._cellStrategy(rows[y][x]) + self._updateStartEnd(rows[y][x], x, y) + cell.x = x + cell.y = y + array[y][x] = cell + except IndexError: + raise ValueError(f"В файле {filename}: Строка {y+1} имеет длину {len(rows[y])}, ожидалось {width}") + + maze_name, _ = path.splitext(path.basename(filename)) + + return Maze(array, self.start, self.end, name=maze_name) + \ No newline at end of file diff --git a/MusinAA/task2/mazeExamples/100x100.txt b/MusinAA/task2/mazeExamples/100x100.txt new file mode 100644 index 00000000..cadb849b --- /dev/null +++ b/MusinAA/task2/mazeExamples/100x100.txt @@ -0,0 +1,100 @@ +S # # # # # # # # # # # # # # + # # ####### ### # ##### # # # # # # # # ### # # ### # # ### # ##### # ##### ### ### ### ######### # + # # # # # # # # # # # # # # # # # # # # # # # # # # + # ##### ##### ### ### ##### ##### ####### # ##### ####### # # # ####### ##### # ######### ### ### # + # # # # # # # # # # # # # # # # # # # # # # # # # + # # ##### # # ##### # # ####### # ### ##### # # # # ### ### ######### ##### # ##### # # ### ### # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + ##### # # # ### ### ####### # # ### ######### ### ### ### ### # # # # # ### ##### # # ### # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # + ### # ### # ##### ##### ######### ######### # ##### ### # ####### # ##### ### ####### # ### # ### # + # # # # # # # # # # # # # # # # # # # # # + # ################# # ### # # # # # ########### ############# # ##### ##### ##### # ##### ### # ### + # # # # # # # # # # # # # # # # # # # # # # + ### # ### # ### ####### # ##### ######### ### # ### ### # ####### # ### ####### ##### # ### # # # # + # # # # # # # # # # # # # # # # # # # # # # # + ######### ### ### # ### # ####### ##### # # # ####### ##### ####### # ########### ####### ######### + # # # # # # # # # # # # # # # # # # # # # +## # ####### ### ##### # ####### ### # # # # ##### ### ########### # # # ### # ##### # # ### ##### # + # # # # # # # # # # # # # # # # # # # # # # # # # + ### # # ########### ######### # ### # # ### ### ####### ### # # # # ##### # ### ##### # # ### ### # + # # # # # # # # # # # # # # # # # # # # # # # # # # # +## ##### # # # # # ### # ### ##### # # # ##### # ### # ### # # # # # # # ##### ### ####### # ### ### + # # # # # # # # # # # # # # # # # # # # # # # # # # # # + ##### ### # # # # # ######### ### ### ### # ##### ##### ### # ##### # ######### ############# ### # + # # # # # # # # # # # # # # # # # # # # # # # # + # ##### # # ### ### ##### # ### ### ##### # # ### # ##### ##### ### ### # ##### ### # # ### # # ### + # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # ####### ####### ### ### ######### ### # # ##### # ### ########### ### # ### ####### ### # # # + # # # # # # # # # # # # # # # # # # # # # # + ################### # # # # ### # # # ######### # # ### ############### # ### ##### ### ### ##### # + # # # # # # # # # # # # # # # # # # # # # + ##### # # ### # # ### # ####### # # ##### # # ### ##### # ####### # # # ######### # ######### ##### + # # # # # # # # # # # # # # # # # # # # # # # # # # # # +#### # # ### # # ### # ### ####### ##### # # ### # # ##### # # ####### # # # ##### ### # # ####### # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +## # # # # ### ### # ### ### # # # ### # ####### ### # ########### # ##### ##### # # ### ### ##### # + # # # # # # # # # # # # # # # # # # # # # # # # # # + ########### # # ########### ### # # # # # ### # # ### # ####### # ######### # # ### # ######### ### + # # # # # # # # # # # # # # # # # # # # # # # # +######## # # # ### # ########### # # ####### ### # # # ####### ### # # # ### # ### ######### # # # # + # # # # # # # # # # # # # # # # # # # # # # # + ##### ##### ### # # # ####### ### ### # # # # ############# # ##### # ### ##### ######### ### ### # + # # # # # # # # # # # # # # # # # # # # # # # # # + ### ### # ### # ##### # # # ### # # # ### # ### ### # # # # ########### ####### # ##### ####### ### + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +## ####### # ##### # ### ### # # # # # # # ####### ### # # # # # # # # ### # # ##### # # # # ##### # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + ### # # # ##### ####### # ### # ### ### ####### # # ### ####### ### ####### # ### ####### # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # + # ##### ##### # # ### ### # ######### ### ### ### ### ####### ##### # ######### ##### # ### # ### # + # # # # # # # # # # # # # # # # # # # # # # # # # + # # ####### # ##### ### # # # # # ### ### # ### ### ######### # ####### # ####### ### ######### ### + # # # # # # # # # # # # # # # # # # # # # # # # # # # + ######### # ### ### # # # # # # ####### ##### ### # # ##### # ### # # ####### # # # ### # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # +## # # # ### ##### # ######### # # ####### ### ### # ##### ######### # # # ####### ### # # # # ### # + # # # # # # # # # # # # # # # # # # # # # # # + ### ######### ####### # # ######### # # ### ### ### ##### ### # ########### ######### # # # ### ### + # # # # # # # # # # # # # # # # # # # # # # # # +## ######### # ### # ####### ### # ### ### # # ####### # ### ##### ### # # ### # ### ##### # # ### # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # ### ### ### # # # ##### # ### # ### ### # # # ####### ##### ### ### # ##### # ##### # ### # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # ### ### # ### # ######### # ######### # ### # # # ### ##### ### # ### # # ### # ##### ##### # + # # # # # # # # # # # # # # # # # # # # # # # # # # + ##### # ### ##### ####### ### # ##### # # # ### ### # ##### # # ### # ####### ##### # # # ### # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # + ### # ### ######### # ##### ### # ### # # # ############# ### ### # ##### # ### ######### # ### # # + # # # # # # # # # # # # # # # # # # # # # # # # +## # # # ### ##### # ##### # ### ### # # # ### # # ######### # # ##### ### ####### ### # ######### # + # # # # # # # # # # # # # # # # # # # # # # # # # # # + # ############### ### ####### ### # ### ####### # # # # ######### # ### # # # ##### ##### # # ##### + # # # # # # # # # # # # # # # # # # # # # # + ##### # # ### # ### ######### # ######### # # ### # # ####### # ########### # # # ##### ####### # # + # # # # # # # # # # # # # # # # # # # # # # # +## # ####### ### # # # ############# ### ### ### ### ##### # # ### ########### ##### # ### ### # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # + ### ### # # # ##### ### # # ##### ####### # # ### ### # # ##### # # ####### ##### # # # # # ##### # + # # # # # # # # # # # # # # # # # # # # # # # # # # # +###### ##### ### # ### ### # # ########### # # # ##### # ### ##### # # ### ######### ### ##### # ### + # # # # # # # # # # # # # # # # # # # # # # # + # # # # # ### ####### ######### # # ######### ### # ##### ##### ##### ### # # # # # # ### ####### # + # # # # # # # # # # # # # # # # # # # # # # # # +#### # ##### # # # ##### ### # ### # ##### ### # ##### ### ######### ### ### ########### # # ##### # + # # # # # # # # # # # # # # # # # # # # # # # # # # # + ######### ##### # ####### # # # ##### # ### # # # # ####### ##### # # ### ### # # # # ### # # ### # + # # # # # # # # # # # # # # # # # # # # # # # # # # + # ### # ##### # # # ############### ### ######### ### # ##### # # ######### # ### # ### # # # # ### + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # ####### # ### # ##### ##### # # ### # ### # # ##### # ### # # # ####### # ##### # # # ### # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # + ##### # ### # # # ##### ##### # # # ### ### # # # # ######### # ########### # # ##### ####### # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # +## # # # # ##### # ### ####### ########### ### # # ####### # # ##### # # # ### ##### ##### # ##### # + # # # # # # # # # # # # # # # # # # # # # # + ### ##### ########### # ### # # ####### # # # ############# # ### ### # ### ######### # ### ### # # + # # # # # # # # # # # # # # # # # # # # # # # # # + ##### # # # ##### ####### # ### # # ##### # ### ####### ######### # ########### ### # ######### # # + # # # # # # # # # +################################################################################################## E diff --git a/MusinAA/task2/mazeExamples/10x10.txt b/MusinAA/task2/mazeExamples/10x10.txt new file mode 100644 index 00000000..3633a552 --- /dev/null +++ b/MusinAA/task2/mazeExamples/10x10.txt @@ -0,0 +1,10 @@ +S # + ### ### # + # # # +## # # ### + # # # + ####### # + # # +## # ##### + +######## E diff --git a/MusinAA/task2/mazeExamples/25x25.txt b/MusinAA/task2/mazeExamples/25x25.txt new file mode 100644 index 00000000..dbe4af89 --- /dev/null +++ b/MusinAA/task2/mazeExamples/25x25.txt @@ -0,0 +1,25 @@ +S # # # + # ##### # # # ####### # + # # # # # # +#### # ##### # # ####### + # # # # # # # +## # # # ##### ### # # # + # # # # # # # # # + ### # # # # ### # # # # + # # # # # # # # + # ### # # ### ### # #### + # # # # # # # + ### # # # ####### ##### + # # # # + # ################# ### + # # # # + # # # ####### ####### ## + # # # # # + ### ##### # ### ### ### + # # # # # # + # # # ##### # # ####### + # # # # # # + ##### # ####### # ### ## + # # # # # # # +#### # # # ### ##### # # + # # # E diff --git a/MusinAA/task2/mazeExamples/50x50.txt b/MusinAA/task2/mazeExamples/50x50.txt new file mode 100644 index 00000000..bdbcf625 --- /dev/null +++ b/MusinAA/task2/mazeExamples/50x50.txt @@ -0,0 +1,50 @@ +S # # # # # # # + ### # ##### # ### ### # # ### # # ### # ### # # # + # # # # # # # # # # # # # # # + ####### # # ####### ##### # ##### ####### ### ### + # # # # # # # # # # + ### # ##### ### # ### # # ##### # ############# # + # # # # # # # # # # # # # + # ### # # ### ############# # # ##### ##### # # # + # # # # # # # # # # # # # # +#### ##### # ### # ##### # # ##### # ### # ##### # + # # # # # # # # # # # # + ### ####### ####### # ####### # ##### # ### ### # + # # # # # # # # # # # # + ####### # # # ### ##### # ##### ### # ### ####### + # # # # # # # # # # # # # +## ### ####### ### # # ### # # # # ### # ### ### # + # # # # # # # # # # # # + ####### # ##### ####### ### ######### ##### ### # + # # # # # # # # # # # +#### # # ### ##### ####### # # # ### # # # ### # # + # # # # # # # # # # # # # # # # + # # # ### # # # # # # ### ####### # ##### # ### # + # # # # # # # # # # # # # # # # + # # # ### ######### # # ### # # # ##### # # # ### + # # # # # # # # # # # # # + ####### ### # ### ####### # # ##### # ######### # + # # # # # # # # # # # # # + ########### ### ### ### # ### # # ##### # ### # # + # # # # # # # # # # # # # # + ### # ### ### ####### ### # ### # # # ####### # # + # # # # # # # # # # # # # # # # +## # ### # # ### # # # # # # # # # ### # ### ### # + # # # # # # # # # # # # # # # # # # + ##### # # ##### # # # ####### # ### # # # ### # # + # # # # # # # # # # # # # # # + # # # ### # ### ########### # ##### # ### # # ### + # # # # # # # # # # # # # +#### ##### # # ### ### # ##### # ##### # ######### + # # # # # # # # # # # + # ### ##### ### ### # ### ########### ######### # + # # # # # # # # # # + ### # ##### # # ##### # ####### # ### ### # ##### + # # # # # # # # # # # +## ##### # ### ### # ##### ####### # # ######### # + # # # # # # # # # # # # + ### # ##### # # ##### # ### ##### ##### ####### # + # # # # # # # # # # # + # ########### ########### ##### ####### # ### # # + # # # # +################################################ E diff --git a/MusinAA/task2/mazeExamples/5x5.txt b/MusinAA/task2/mazeExamples/5x5.txt new file mode 100644 index 00000000..28f10587 --- /dev/null +++ b/MusinAA/task2/mazeExamples/5x5.txt @@ -0,0 +1,5 @@ +##### +# S # +# ### +# E +##### \ No newline at end of file diff --git a/MusinAA/task2/mazeExamplesSpeical/maze_25x25_empty.txt b/MusinAA/task2/mazeExamplesSpeical/maze_25x25_empty.txt new file mode 100644 index 00000000..7f7dfce9 --- /dev/null +++ b/MusinAA/task2/mazeExamplesSpeical/maze_25x25_empty.txt @@ -0,0 +1,25 @@ +S + + + + + + + + + + + + + + + + + + + + + + + + E diff --git a/MusinAA/task2/mazeExamplesSpeical/maze_25x25_wo_exit.txt b/MusinAA/task2/mazeExamplesSpeical/maze_25x25_wo_exit.txt new file mode 100644 index 00000000..b977d127 --- /dev/null +++ b/MusinAA/task2/mazeExamplesSpeical/maze_25x25_wo_exit.txt @@ -0,0 +1,25 @@ +S # # # + # ##### # # # ####### # + # # # # # # +#### # ##### # # ####### + # # # # # # # +## # # # ##### ### # # # + # # # # # # # # # + ### # # # # ### # # # # + # # # # # # # # + # ### # # ### ### # #### + # # # # # # # + ### # # # ####### ##### + # # # # + # ################# ### + # # # # + # # # ####### ####### ## + # # # # # + ### ##### # ### ### ### + # # # # # # + # # # ##### # # ####### + # # # # # # + ##### # ####### # ### ## + # # # # # # # +#### # # # ### ##### # # + # # # # diff --git a/MusinAA/task2/mazeObjects/__init__.py b/MusinAA/task2/mazeObjects/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/MusinAA/task2/mazeObjects/cell.py b/MusinAA/task2/mazeObjects/cell.py new file mode 100644 index 00000000..9d617aba --- /dev/null +++ b/MusinAA/task2/mazeObjects/cell.py @@ -0,0 +1,13 @@ +class Cell: + """Хранит координаты (x, y) + флаги isWall, isStart, isExit + метод isPassable() (возвращает True для прохода, если не стена).""" + def __init__(self, x: int = 0, y: int = 0, isWall:bool = False, isStart:bool = False, isExit:bool = False): + self.x = x + self.y = y + self.isWall = isWall + self.isStart = isStart + self.isExit = isExit + + def isPassable(self): + return not self.isWall diff --git a/MusinAA/task2/mazeObjects/maze.py b/MusinAA/task2/mazeObjects/maze.py new file mode 100644 index 00000000..7ed8fcef --- /dev/null +++ b/MusinAA/task2/mazeObjects/maze.py @@ -0,0 +1,41 @@ +from task2.mazeObjects.cell import Cell + +class Maze: + """Хранит двумерный массив клеток, + ширину, высоту, ссылки на стартовую и выходную клетку. + Методы: + getCell(x, y), getNeighbors(cell) – возвращает список соседних проходимых клеток + (вверх, вниз, влево, вправо, если в пределах границ и не стена).""" + + def __init__(self, mazeArray: list[list[Cell]], start: dict, end: dict, name:str="") -> None: + self.mazeArray = mazeArray + self.height = len(mazeArray) # X + self.width = len(mazeArray[0]) # Y + + self.startCell = self.getCell(start['x'], start['y']) + self.endCell = self.getCell(end['x'], end['y']) + self.name = name + + def getCell(self, x: int, y: int): + return self.mazeArray[y][x] + + def checkCell(self, x: int, y: int): + if not(0 <= x and x < self.width): + return False + if not(0 <= y and y < self.height): + return False + return self.getCell(x, y).isPassable() + + def getNeighbors(self, cell: Cell): + point = (cell.x, cell.y) + offsets = ((0, 1), + (0, -1), + (-1, 0), + (1, 0)) + passableCells = [] + for ofst in offsets: + x = point[0]+ofst[0] + y = point[1]+ofst[1] + if self.checkCell(x, y): + passableCells.append(self.getCell(x, y)) + return passableCells \ No newline at end of file diff --git a/MusinAA/task2/mazeObjects/path.py b/MusinAA/task2/mazeObjects/path.py new file mode 100644 index 00000000..3277c73a --- /dev/null +++ b/MusinAA/task2/mazeObjects/path.py @@ -0,0 +1,6 @@ +from task2.mazeObjects.cell import Cell + +class Path: + def __init__(self, array:list[Cell]|None, visited_cells:int): + self.array = array + self.visited_cells = visited_cells \ No newline at end of file diff --git a/MusinAA/task2/mazeSolver.py b/MusinAA/task2/mazeSolver.py new file mode 100644 index 00000000..f2e1fc76 --- /dev/null +++ b/MusinAA/task2/mazeSolver.py @@ -0,0 +1,66 @@ +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell +from task2.observerSubject import MazeEvent, MazeEventType, Subject +from task2.strategyObjects.pathFindingStrategy import PathFindingStrategy +from task2.strategyObjects.BFS import BFS + + +import time + +class SearchStats: + maze_name:str = "None" + """Время выполнения в миллисекундах, количество посещённых клеток, длина найденного пути""" + def __init__(self, path: list[Cell]|None, duration:float, visited_cells:int, path_len:int, strategy_name:str): + self.duration = duration + self.visited_cells = visited_cells + self.path_len = path_len + self.path = path + self.strategy_name = strategy_name + + def toDict(self,): + return { + "strategy_name" : self.strategy_name, + "maze_name" : self.maze_name, + "duration" : self.duration, + "visited_cells" : self.visited_cells, + "path_len" : self.path_len + } + +class MazeSolver(Subject): + """ + MazeSolver содержит поля maze и strategy. + Метод setStrategy(strategy) для динамической смены алгоритма. + Метод solve() вызывает strategy.findPath(...) и возвращает объект SearchStats (время выполнения в миллисекундах, + количество посещённых клеток, длина найденного пути). + Для замера времени используйте time.perf_counter() до и после вызова стратегии. + """ + + def __init__(self, strategy:PathFindingStrategy, maze:Maze|None=None): + super().__init__() + self._maze = maze + self.strategy = strategy + + def setMaze(self, maze: Maze|None): + self._maze = maze + self.notify(MazeEvent(MazeEventType.MAZE_LOADED, data=maze)) + + def setStrategy(self, strategy:PathFindingStrategy): + self.strategy = strategy + + def getStrategyName(self): + return self.strategy.__class__.__name__ + + def solve(self): + if not self._maze: + raise ValueError + + t_start = time.perf_counter() + path = self.strategy.findPath(self._maze, self._maze.startCell, self._maze.endCell) + duration = (time.perf_counter() - t_start) * 1000 + + path_len = len(path.array) if path.array else -1 + strategy_name = self.getStrategyName() + + stats = SearchStats(path.array, duration, path.visited_cells, path_len, strategy_name) + self.notify(MazeEvent(MazeEventType.PATH_FOUND, data=path)) + return stats \ No newline at end of file diff --git a/MusinAA/task2/observerSubject.py b/MusinAA/task2/observerSubject.py new file mode 100644 index 00000000..c49b8f83 --- /dev/null +++ b/MusinAA/task2/observerSubject.py @@ -0,0 +1,43 @@ +""" +Создать интерфейс Observer с методом update(event), +где event может быть строкой или объектом с типом события ("path_found", "move", "maze_loaded"). +""" + +from enum import Enum +from abc import ABC, abstractmethod + +class MazeEventType(Enum): + PATH_FOUND = "path_found" + MOVE = "move" + MAZE_LOADED = "maze_loaded" + +class MazeEvent: + data=None + def __init__(self, evtype: MazeEventType, data=None): + if not isinstance(evtype, MazeEventType): + raise TypeError(f"evtype must be an EventType, got {type(evtype)}") + self.evtype = evtype + self.data = data + +class Observer(ABC): + @abstractmethod + def update(self, event: MazeEvent): + raise NotImplementedError + + +class Subject(ABC): + """Издатель: управляет подписчиками и отправляет им уведомления.""" + def __init__(self): + self._observers:set[Observer] = set() + + def attach(self, obs:Observer): + "Подписать наблюдателя" + self._observers.add(obs) + + def detach(self, obs:Observer): + "Отписать наблюдателя" + self._observers.discard(obs) + + def notify(self, event:MazeEvent): + for obs in self._observers: + obs.update(event) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/AStar.py b/MusinAA/task2/strategyObjects/AStar.py new file mode 100644 index 00000000..6e4c4b2f --- /dev/null +++ b/MusinAA/task2/strategyObjects/AStar.py @@ -0,0 +1,46 @@ +import heapq +from itertools import count + +from task2.strategyObjects.pathFindingStrategy import PathFindingStrategy +from task2.strategyObjects.util import restorePath + +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell +from task2.mazeObjects.path import Path + +class AStar(PathFindingStrategy): + """Алгоритм с эвристикой (etc. манхэттенское расстояние) – компромисс между скоростью и оптимальностью.""" + def heuristic(self, first: Cell, second: Cell) -> int: + return abs(first.x - second.x) + abs(first.y - second.y) + + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: + tie_breaker = count() + start_heuristic = self.heuristic(start, exit) + heap: list[tuple[int, int, int, Cell]] = [ + (start_heuristic, start_heuristic, next(tie_breaker), start) + ] + g_score: dict[Cell, int] = {start: 0} + parents: dict[Cell, Cell | None] = {start: None} + visited: set[Cell] = set() + + while heap: + _, _, _, current = heapq.heappop(heap) + if current in visited: + continue + visited.add(current) + + if current.isExit: + return Path(restorePath(parents, exit), len(visited)) + + for neighbor in maze.getNeighbors(current): + tentative_score = g_score[current] + if tentative_score < g_score.get(neighbor, 10**12): + g_score[neighbor] = tentative_score + parents[neighbor] = current + heuristic = self.heuristic(neighbor, exit) + priority = tentative_score + heuristic + heapq.heappush( + heap, + (priority, heuristic, next(tie_breaker), neighbor), + ) + return Path(None, len(visited)) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/BFS.py b/MusinAA/task2/strategyObjects/BFS.py new file mode 100644 index 00000000..859897cd --- /dev/null +++ b/MusinAA/task2/strategyObjects/BFS.py @@ -0,0 +1,43 @@ +from task2.strategyObjects.pathFindingStrategy import PathFindingStrategy +from task2.strategyObjects.util import restorePath + +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell +from task2.mazeObjects.path import Path + +import queue + +class BFS(PathFindingStrategy): + """Поиск в ширину – гарантирует кратчайший путь по количеству шагов. + Возвращает None, если пути нет""" + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: + visited = dict() + parents = dict() + q = queue.Queue() + + q.put(start) + visited[start] = 0 + parents[start] = None + + found_exit = False + while not q.empty(): + current = q.get() + + # Условие нахождение выхода + if current.isExit: + found_exit = True + break + + # Перебор соседей + for hood in maze.getNeighbors(current): + if hood in visited: + continue + visited[hood] = visited[current] + 1 + parents[hood] = current + q.put(hood) + + if not found_exit: + path_list = None + else: + path_list = restorePath(parents, exit) + return Path(path_list, len(visited)) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/DFS.py b/MusinAA/task2/strategyObjects/DFS.py new file mode 100644 index 00000000..31d02ebe --- /dev/null +++ b/MusinAA/task2/strategyObjects/DFS.py @@ -0,0 +1,41 @@ +from task2.strategyObjects.pathFindingStrategy import PathFindingStrategy +from task2.strategyObjects.util import restorePath + +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell +from task2.mazeObjects.path import Path + +class DFS(PathFindingStrategy): + """Поиск в глубину – быстрый, но не обязательно кратчайший. + Возвращает None, если пути нет""" + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: + visited = dict() + parents = dict() + stack = [] + + stack.append(start) + visited[start] = 0 + parents[start] = None + + found_exit = False + while stack: + current = stack.pop() + + # Условие нахождение выхода + if current.isExit: + found_exit = True + break + + # Перебор соседей + for hood in maze.getNeighbors(current): + if hood in visited: + continue + visited[hood] = visited[current] + 1 + parents[hood] = current + stack.append(hood) + + if not found_exit: + path_list = None + else: + path_list = restorePath(parents, exit) + return Path(path_list, len(visited)) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/__init__.py b/MusinAA/task2/strategyObjects/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/MusinAA/task2/strategyObjects/pathFindingStrategy.py b/MusinAA/task2/strategyObjects/pathFindingStrategy.py new file mode 100644 index 00000000..94170657 --- /dev/null +++ b/MusinAA/task2/strategyObjects/pathFindingStrategy.py @@ -0,0 +1,14 @@ +from abc import ABC, abstractmethod + +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell +from task2.mazeObjects.path import Path + +class PathFindingStrategy(ABC): + """Интерфейс PathFindingStrategy с методом findPath(maze, start, exit), + возвращающим список клеток пути (от старта до выхода включительно) или пустой список, если пути нет.""" + + @abstractmethod + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: + """Возвращает список клеток пути от старта до выхода включительно. Пути нет - пустой список.""" + raise NotImplementedError \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/util.py b/MusinAA/task2/strategyObjects/util.py new file mode 100644 index 00000000..26dd7779 --- /dev/null +++ b/MusinAA/task2/strategyObjects/util.py @@ -0,0 +1,12 @@ +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell + +def restorePath(parents: dict, exit: Cell) -> list[Cell]|None: + path = [] + current = exit + while current: + path.append(current) + if current not in parents: + return None + current = parents[current] + return path[::-1] \ No newline at end of file diff --git a/MusinAA/task2/tester.py b/MusinAA/task2/tester.py new file mode 100644 index 00000000..6e56a5f4 --- /dev/null +++ b/MusinAA/task2/tester.py @@ -0,0 +1,84 @@ +from task2.mazeBuilder import MazeBuilder +from task2.mazeObjects.maze import Maze +from task2.mazeSolver import MazeSolver, SearchStats + +from task2.strategyObjects.BFS import BFS +from task2.strategyObjects.DFS import DFS +from task2.strategyObjects.AStar import AStar + +import csv +import os + +TEST_ITERATIONS = 10 + +class Tester(): + """Для каждого лабиринта и каждой стратегии запустить solve() 5–10 раз, + усреднить время, количество посещённых клеток, длину пути. + Записать результаты в CSV: + лабиринт,стратегия,время_мс,посещено_клеток,длина_пути.""" + result:list[SearchStats] + def __init__(self, builder:MazeBuilder, writefile:str): + self._builder = builder + self.writefile = "../" + writefile + + def setTestingDirectory(self, directory:str): + if directory[-1] != "/": + directory += "/" + self._directory = "../" + directory + + def _getMazes(self) -> list[Maze]: + arr = [] + files = os.listdir(self._directory) + only_txt_files = [f for f in files if os.path.isfile(os.path.join(self._directory, f)) and os.path.splitext(f)[1] == ".txt"] + + for f in only_txt_files: + arr.append(self._builder.buildFromFile(os.path.join(self._directory, f))) + return arr + + def _solveAvg(self, solver: MazeSolver): + avgtime = 0 + for i in range(TEST_ITERATIONS): + result = solver.solve() + # Всё кроме времени будет одинаковым + avgtime += result.duration/TEST_ITERATIONS + result.duration = avgtime + return result + + def saveCSV(self): + rows = [] + for r in self.result: + r = r.toDict() + row = (r["strategy_name"], + r["maze_name"], + r["duration"], + r["visited_cells"], + r["path_len"] + ) + rows.append(row) + with open(self.writefile, "w", newline="") as f: + writer = csv.writer(f) + writer.writerow(["Алгоритм", "Лабиринт", "Время (мс)", "Посещённые клетки", "Длинна пути"]) + writer.writerows(rows) + + def test(self): + self.result = [] + arr = self._getMazes() + for algoritm in (BFS, DFS, AStar): + solver = MazeSolver(algoritm()) # это прикол + for maze in arr: + solver.setMaze(maze) + self.result.append(self._solveAvg(solver)) + self.result[-1].maze_name = maze.name + return self.result + + +if __name__ == "__main__": + exit() + from task2.mazeBuilder import TextFileMazeBuilder + + builder = TextFileMazeBuilder() + tester = Tester(builder, "docs/data/task2/results.csv") + tester.setTestingDirectory("task2/mazeExamples") + tester.test() + tester.saveCSV() + \ No newline at end of file