{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "# Майнор \"Интеллектуальный анализ данных\" \n", "# Курс \"Введение в программирование\"\n", "\n", "\n", "## Автор материала: Юрий Кашницкий, ФКН НИУ ВШЭ\n", "
\n", "Материал распространяется на условиях лицензии Ms-RL. Можно использовать в любых целях, кроме коммерческих, но с обязательным упоминанием автора материала." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Командный проект. Задача \"Закон джунглей\"\n", "### Задача из курса ШАД «Яндекс» по Python (с разрешения преподавателя Алексея Зобнина)\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Напишите программу, моделирующую экологическую систему океана, в котором обитают хищники и жертвы. \n", "\n", "Океан представляется двумерным массивом ячеек. В ячейке может находиться либо хищник, либо жертва, либо препятствие. В каждый квант времени ячейки последовательно обрабатываются. Хищник может съесть соседнюю жертву или просто переместиться на соседнюю клетку, добыча также может переместиться на соседнюю клетку. Если в течение некоторого времени хищник ничего не съел, он погибает. Через определенные интервалы времени хищники и жертвы размножаются, если рядом есть свободная ячейка. При этом потомок занимает свободную ячейку. \n", "\n", "Текущее состояние экрана отображается на экране, желательно в виде графического интерфейса. Моделирование закачивается либо по истечении некоторого числа итераций, либо когда погибнут все хищники или жертвы. \n", "\n", "Проверьте на этой модели гипотезу о цикличности популяций хищников и жертв. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Начало решения" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from __future__ import print_function\n", "from IPython.display import clear_output\n", "from time import sleep\n", "from random import choice" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Инициализация поля размерами SIZE_X (по горизонтали, т.е. число столбцов) на SIZE_Y (по вертикали, т.е число строк).\n", "На поле случайным образом бросаются NUM_PRED хищников ('X'), NUM_VIC жертв ('O') и NUM_OBST препятствий ('#').**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "SIZE_X, SIZE_Y = 10, 4\n", "NUM_PRED, NUM_VIC, NUM_OBST = 2, 4, 4\n", "\n", "def initialize_field():\n", " '''\n", " Returns a list of SIZE_X lists (each of length SIZE_y)\n", " with NUM_PRED 'X's (for predators), NUM_VIC 'O's (for victims)\n", " and NUM_OBST '#'s (for obstacles) in random places. Each remaining element\n", " contains a '*'.\n", " '''\n", " field = [['*'] * SIZE_X for y in range(SIZE_Y)]\n", " cell_idx = [(x, y) for x in xrange(SIZE_X)\n", " for y in xrange(SIZE_Y)]\n", " \n", " # add predators\n", " num_pred = NUM_PRED\n", " while(num_pred):\n", " col, row = choice(cell_idx)\n", " if field[row][col] == '*':\n", " field[row][col] = 'X'\n", " num_pred -= 1\n", " \n", " # add victims\n", " num_vic = NUM_VIC\n", " while(num_vic):\n", " col, row = choice(cell_idx)\n", " if field[row][col] == '*':\n", " field[row][col] = 'O'\n", " num_vic -= 1\n", " \n", " # add obstacles\n", " num_obst = NUM_OBST\n", " while(num_obst):\n", " col, row = choice(cell_idx)\n", " if field[row][col] == '*':\n", " field[row][col] = '#'\n", " num_obst -= 1\n", " \n", " return field" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Печать поля. Если clear_all влючен, весь предыдущий вывод затрется. В совокупности с функцией sleep из time можно печатать одно и то же поле в разные моменты времени, а не подряд несколько полей.**" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def print_field(field, clear_all=True):\n", " '''\n", " Prints the field (a list of lists). If the field is big, it sucks :)\n", " \n", " :param field - a list of lists\n", " :param clear_all - whether to clear previous output.\n", " '''\n", " if clear_all:\n", " clear_output()\n", " print('/' * (2 * SIZE_X + 5))\n", " for col in range(len(field)):\n", " print('// ', end='')\n", " for row in range(len(field[0])):\n", " print(field[col][row], end=' ')\n", " print('//')\n", " print('/' * (2 * SIZE_X + 5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Обработка одной клетки в один момент времени. Пока реализован только переход в соседнюю клетку. Если это хищник или жертва и рядом (по горизонтали или вертикали) есть свободные клетки, хищник (или жертва) переходит в одну из случайно выбранных свободных клеток.**" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def process_one_cell(field, (col, row)):\n", " '''\n", " If a cell (col, row) is occupied with 'X' or 'O'\n", " it modifies the field and returns a new one.\n", " \n", " :param field - a list of lists\n", " :param (col, row) - a tuple with 2 integer coordinates.\n", " col should be in [0, SIZE_X - 1],\n", " row should be in [0, SIZE_Y - 1]\n", " :return field, (new_col, new_row) - filed is a modified list of lists,\n", " (new_col, new_row) - are the coordinates of a new cell\n", " or the old obe if there was no movement\n", " '''\n", " if field[col][row] in ['X', 'O']:\n", " cur_animal = field[col][row]\n", " possible_moves = []\n", " for (new_col, new_row) in [(col, min(row + 1, SIZE_X - 1)),\n", " (col, max(row - 1, 0)),\n", " (max(col - 1, 0), row),\n", " (min(col + 1, SIZE_Y - 1), row)]:\n", " if field[new_col][new_row] == \"*\":\n", " possible_moves.append((new_col, new_row))\n", " if possible_moves:\n", " new_col, new_row = choice(possible_moves)\n", " field[new_col][new_row] = cur_animal\n", " field[col][row] = '*'\n", " return field, (new_col, new_row)\n", " return field, (col, row)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Функция для запуска обработки всех клеток поля. Здесь учитывается, что если на прошлом шаге в некоторую клетку пришел хищник или жертва, то ее уже не надо обрабатывать.**" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def process_field(field, verbose=False):\n", " '''\n", " Applies process_one_cell to each cell with repsect to the fact \n", " that a cell should not be processed if it has already been a destination\n", " of a previous move.\n", " \n", " :param field - a list of lists\n", " :param verbose - whether to print the moves\n", " \n", " :return field - a modified list of lists\n", " '''\n", " processed_cells = []\n", " for col in range(SIZE_Y):\n", " for row in range(SIZE_X):\n", " if (col, row) not in processed_cells:\n", " field, (new_col, new_row) = process_one_cell(field, (col, row))\n", " if (new_col, new_row) != (col, row):\n", " if verbose:\n", " print(\"{} steps {}->{}\".format(field[new_col][new_row],\n", " (col, row), (new_col, new_row)))\n", " processed_cells.append((new_col, new_row))\n", " return field\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Проверка на игрушечном примере. Посмотрим, как переместились 2 хищника и 3 жертвы за один ход. Чтоб разобраться было проще, напечатаем координаты ходов.**" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/////////////////////////\n", "// * * # * * X O * * * //\n", "// * * * X # * * * # * //\n", "// * * * * * # O * * * //\n", "// * * * * * * * * O O //\n", "/////////////////////////\n", "X steps (0, 5)->(1, 5)\n", "O steps (0, 6)->(0, 7)\n", "X steps (1, 3)->(1, 2)\n", "O steps (2, 6)->(2, 7)\n", "O steps (3, 8)->(2, 8)\n", "O steps (3, 9)->(3, 8)\n", "/////////////////////////\n", "// * * # * * * * O * * //\n", "// * * X * # X * * # * //\n", "// * * * * * # * O O * //\n", "// * * * * * * * * O * //\n", "/////////////////////////\n" ] } ], "source": [ "f = initialize_field()\n", "print_field(f)\n", "f = process_field(f, verbose=True)\n", "sleep(1)\n", "print_field(f, clear_all=False)" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [default]", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.12" } }, "nbformat": 4, "nbformat_minor": 0 }