{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib tk\n",
    "import time, math\n",
    "from random import random\n",
    "import numpy as np\n",
    "from IPython import display\n",
    "from PIL import Image\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.animation as animation\n",
    "writer = animation.writers['ffmpeg'](fps=30, metadata=dict(artist='Me'), bitrate=1800)\n",
    "\n",
    "# Коды элементов\n",
    "\n",
    "BAD = 0\n",
    "GOOD = 1\n",
    "BASIC_FLOOR = 2\n",
    "FENCE_PORT = 3\n",
    "CORNER_PORT = 4\n",
    "STORAGE_PORT = 5\n",
    "GATE_LEAF_PORT = 6\n",
    "GATE_PORT = 7\n",
    "TRACK = 8\n",
    "MACHINE_PORT = 9\n",
    "WORK_PORT = 10\n",
    "MM_PORT = 11\n",
    "POWER_PORT = 12\n",
    "UTIL_PORT = 13\n",
    "PLANNER_PORT = 14\n",
    "MINE_PORT = 15\n",
    "\n",
    "#Словарь, где хранятся ссылки на клетки по координатам\n",
    "\n",
    "cells={}\n",
    "\n",
    "class FloorElement():\n",
    "    def __init__(self,parent,x,y,element_type):\n",
    "        self.x=x\n",
    "        self.y=y\n",
    "        self.element_type=element_type\n",
    "        self.parent=parent\n",
    "        self.parent.floor[(self.x,self.y)]=self\n",
    "\n",
    "class Cell():\n",
    "    def __init__(self,x,y):\n",
    "        self.x=x\n",
    "        self.y=y\n",
    "        cells[(self.x,self.y)] = self\n",
    "        self.floor={}\n",
    "        self.content={}\n",
    "        self.generate()\n",
    "    def destroy(self):\n",
    "        del cells[(self.x,self.y)] \n",
    "    def generate(self):\n",
    "\n",
    "        # Настройка параметров клетки\n",
    "        self.max_machine_size=20               # Максимальное число блоков в машине \n",
    "        self.work_machine_number_max=30         # Максимальное число рабочих машин\n",
    "        self.planners_max=3                     # Максимальное число планировщиков\n",
    "        self.utils_max=3                        # Максимальное число утилизаторов\n",
    "        self.powers_max=4                       # Максимальное число электростанций\n",
    "        self.mines_max=4                        # Максимальное число шахт\n",
    "        self.storage_number_max_without_mm=500  # Максимальная емкость склада\n",
    "        self.mm_max=50                          # Максимальное число мобильных манипуляторов (ММ)\n",
    "        \n",
    "        self.work_machine_number_rep=12         # Число рабочих машин, достаточное для репликации\n",
    "        self.storage_number_rep_without_mm=200  # Емкость склада, достаточная для репликации\n",
    "        self.work_machine_number_grow=6         # Число рабочих машин, достаточное для автономного роста\n",
    "        self.storage_number_grow_without_mm=100 # Емкость склада, достаточная для автономного роста\n",
    "        self.storage_free=15                    # Число складских ячеек в резерве\n",
    "        self.machine_free=2                     # Число машиномест в резерве \n",
    "\n",
    "        # Найти общее количество машин (включая служебные) и общую емкость склада (включая места для ММ)\n",
    "        \n",
    "        self.machine_number_max=self.work_machine_number_max+self.planners_max+self.utils_max+self.powers_max+self.mines_max\n",
    "        self.storage_number_max=self.mm_max+self.storage_number_max_without_mm\n",
    "\n",
    "        # Подобрать прямоугольную форму машины, по возможности близкую к квадратной, содержащую количество\n",
    "        # блоков не меньше заданного и хорошо стыкуемую с соседями, дорожками и складской зоной\n",
    "        # Определить ширину и высоту машины, фактическое количество в ней блоков и занимаемую ей площадь\n",
    "        \n",
    "        self.machine_height=round(math.sqrt(self.max_machine_size),0)//3*3+1\n",
    "        self.machine_width=self.max_machine_size//self.machine_height\n",
    "        if self.machine_width*self.machine_height<self.max_machine_size:\n",
    "            self.machine_width=self.machine_width+1\n",
    "        self.fact_machine_size=self.machine_height*self.machine_width\n",
    "        self.fact_machine_area=(self.machine_height+5)*(self.machine_width+5)\n",
    "\n",
    "        # Подобрать прямоугольную форму рабочей зоны, по возможности близкую к квадратной, содержащую \n",
    "        # количество машин не меньше заданного и хорошо стыкуемую с дорожками и складскими зонами\n",
    "        # Определить ширину и высоту рабочей зоны, фактическое количество машин и занимаемую ей площадь\n",
    "        \n",
    "        self.machine_coloumns=round(math.sqrt(self.machine_number_max),0)\n",
    "        self.machine_rows=self.machine_coloumns\n",
    "        if self.machine_coloumns*self.machine_rows<self.machine_number_max:\n",
    "            self.machine_rows+=1\n",
    "        if self.machine_width%2==0:\n",
    "            if self.machine_coloumns%2==1:\n",
    "                if self.machine_coloumns%2==1:\n",
    "                    self.machine_coloumns+=1\n",
    "                else:\n",
    "                    self.machine_coloumns,self.machine_rows=self.machine_rows,self.machine_coloumns\n",
    "        self.siderows=self.machine_rows*(1+(self.machine_height-1)/6)\n",
    "        if self.siderows!=int(self.siderows):\n",
    "            self.machine_rows+=1\n",
    "        self.siderows=self.machine_rows*(1+(self.machine_height-1)/6) \n",
    "        self.fact_machine_number=self.machine_coloumns*self.machine_rows\n",
    "\n",
    "        # Рассчитать размер территории, занимаемой клеткой\n",
    "        \n",
    "        self.fact_machine_block_area=self.fact_machine_number*self.fact_machine_area\n",
    "        self.storage_desired_area=self.storage_number_max*5.5\n",
    "        self.total_desired_area=self.storage_desired_area+self.fact_machine_block_area\n",
    "        self.presize=(int(math.sqrt(self.total_desired_area)))\n",
    "        self.presize=(1+self.presize//6)*6\n",
    "        if (self.presize-(self.siderows*6))%12!=0:\n",
    "            self.presize+=6\n",
    "        self.realsize=self.presize+5\n",
    "\n",
    "        # Создать территорию\n",
    "        \n",
    "        self.Terrain=np.ones((self.realsize,self.realsize))\n",
    "        #Terrain=np.sign(np.array(Image.open(\"intest.png\"))[:,:,0])\n",
    "\n",
    "        # Создать карту, заполненную элементами пола\n",
    "        \n",
    "        self.Map=self.Terrain*BASIC_FLOOR\n",
    "\n",
    "        # Создать забор\n",
    "        \n",
    "        self.Map[0]=self.Map[-1]=self.Map[:,0]=self.Map[:,-1]=FENCE_PORT\n",
    "\n",
    "        # Создать углы\n",
    "        \n",
    "        self.Map[0,0]=self.Map[0,-1]=self.Map[-1,0]=self.Map[-1,-1]=CORNER_PORT\n",
    "\n",
    "        # Создать трассу по периметру клетки\n",
    "        \n",
    "        self.Map[2:-2,2:-2]=TRACK\n",
    "        self.Map[3:-3,3:-3]=BASIC_FLOOR\n",
    "\n",
    "        # Создать ворота, порты ворот, складские места\n",
    "        \n",
    "        for y in range(4,self.presize+2,6):\n",
    "            self.Map[y-2,2:-3]=TRACK\n",
    "            self.Map[y,0]=self.Map[y+2,0]=self.Map[y,-1]=self.Map[y+2,-1]=GATE_LEAF_PORT\n",
    "            self.Map[0,y]=self.Map[0,y+2]=self.Map[-1,y]=self.Map[-1,y+2]=GATE_LEAF_PORT\n",
    "            self.Map[y+1,0]=self.Map[y+1,-1]=self.Map[0,y+1]=self.Map[-1,y+1]=GATE_PORT\n",
    "            self.Map[y+1,1]=self.Map[y+1,-2]=self.Map[1,y+1]=self.Map[-2,y+1]=TRACK\n",
    "            for x in range(4,self.presize+2,2):\n",
    "                self.Map[y,x]=self.Map[y+2,x]=STORAGE_PORT\n",
    "                \n",
    "        # Создать машинную зону   \n",
    "        \n",
    "        self.center=int(self.realsize/2)\n",
    "        self.mxstart=int(self.center-(self.machine_coloumns*(self.machine_width+5))/2)\n",
    "        self.mystart=int(self.center-(self.siderows*3))\n",
    "        self.mxstop=int(self.center+(self.machine_coloumns*(self.machine_width+5))/2)\n",
    "        if self.mxstart%2!=0:\n",
    "            self.mxstart-=1\n",
    "            self.mxstop-=1\n",
    "        self.mystop=int(self.center+(self.siderows*3))\n",
    "        \n",
    "        self.Map[self.mystart+1:self.mystop-1,self.mxstart:self.mxstop]=BASIC_FLOOR\n",
    "        self.Map[2:-2,self.mxstart]=self.Map[2:-2,self.mxstop]=TRACK\n",
    "\n",
    "        special_machines_list=([PLANNER_PORT]*self.planners_max+[POWER_PORT]*self.powers_max+\n",
    "            [UTIL_PORT]*self.utils_max+[MINE_PORT]*self.mines_max)\n",
    "        \n",
    "        for y in range(self.mystart,self.mystop,int(self.machine_height)+5):\n",
    "            self.Map[y,self.mxstart:self.mxstop]=TRACK\n",
    "            for x in range(self.mxstart,self.mxstop,int(self.machine_width)+5):\n",
    "                kind=MACHINE_PORT\n",
    "                if len(special_machines_list)>0:\n",
    "                    kind = special_machines_list.pop(0)\n",
    "                self.Map[3+y:3+y+int(self.machine_height),3+x:3+x+int(self.machine_width)]=kind\n",
    "                for sy in range(3+y,3+y+int(self.machine_height),2):\n",
    "                    self.Map[sy,2+x]=WORK_PORT\n",
    "                for sx in range(4+x,3+x+int(self.machine_width),2):\n",
    "                    self.Map[2+y,sx]=WORK_PORT\n",
    "                zystart=3+y\n",
    "                if self.Map[2+y,2+x+int(self.machine_width)]==WORK_PORT:\n",
    "                    zystart+=1\n",
    "                for zy in range(zystart,3+y+int(self.machine_height),2):\n",
    "                    self.Map[zy,3+x+int(self.machine_width)]=WORK_PORT\n",
    "                zxstart=3+x\n",
    "                if self.Map[2+y+int(self.machine_height),2+x]==WORK_PORT:\n",
    "                    zxstart+=1\n",
    "                for zx in range(zxstart,3+x+int(self.machine_width),2):\n",
    "                    self.Map[3+y+int(self.machine_height),zx]=WORK_PORT\n",
    "\n",
    "        # Создать дополнительные вертикальные трассы возле машинной зоны   \n",
    "        \n",
    "        for x in range(self.mxstart,self.mxstop,int(self.machine_width)+5):\n",
    "            if self.Map[4,x] == STORAGE_PORT:\n",
    "                self.Map[2:-3,x]=TRACK\n",
    "            else:\n",
    "                self.Map[self.mystart:self.mystop,x]=TRACK\n",
    "\n",
    "        # Создать порты мобильных манипуляторов\n",
    "        \n",
    "        mm_counter=self.mm_max\n",
    "        for y in range(self.realsize):\n",
    "            for x in range(self.realsize):\n",
    "                if mm_counter>0:\n",
    "                    if self.Map[y,x]==STORAGE_PORT:\n",
    "                        self.Map[y,x]=MM_PORT\n",
    "                        mm_counter-=1\n",
    "                        if self.Map[y-2,x]==TRACK:\n",
    "                            self.Map[y-1,x]=TRACK\n",
    "                        elif self.Map[y+2,x]==TRACK:\n",
    "                            self.Map[y+1,x]=TRACK\n",
    "\n",
    "        # Зарегистрировать элементы карты\n",
    "        \n",
    "        for y in range(self.realsize):\n",
    "            for x in range(self.realsize):\n",
    "                if self.Map[y,x]>1:                          \n",
    "                    FloorElement(self,x,y,self.Map[y,x])\n",
    "                                                     \n",
    "# Создать клетку                            \n",
    "                            \n",
    "c=Cell(20,20)\n",
    "\n",
    "# Показать клетку\n",
    "\n",
    "fig=plt.figure(figsize=(7, 5))\n",
    "ax=fig.add_subplot(1, 1, 1)\n",
    "im1=plt.imshow(c.Map, cmap=plt.get_cmap('bone'))\n",
    "ax.set_title('Map MS:'+str(c.max_machine_size)+' MN:'+str(c.work_machine_number_max)+\n",
    "             ' SN:'+str(c.storage_number_max_without_mm)+' MM:'+str(c.mm_max))          \n",
    "plt.show()"
   ]
  }
 ],
 "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.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
