\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
}