Алгоритмы неформально. Инструкция для начинающих питонистов - [16]

Шрифт
Интервал


Все вместе

Все, о чем говорилось выше, можно объединить в функцию, которая получает начальный квадрат со значениями nan и перемещается по нему, применяя три правила для заполнения. Все функция приведена в листинге 2.2.


Листинг 2.2. Функция, лежащая в основе реализации алгоритма Курусимы

import random

def fillsquare(square,entry_i,entry_j,howfull):

     while(sum(math.isnan(i) for row in square for i in row) > howfull):

        where_we_can_go = []

        if(entry_i < (n - 1) and entry_j < (n - 1)):

            where_we_can_go.append('down_right')

        if(entry_i < (n - 1) and entry_j > 0):

            where_we_can_go.append('down_left')

        if(entry_i > 0 and entry_j < (n - 1)):

            where_we_can_go.append('up_right')

        if(entry_i > 0 and entry_j > 0):

            where_we_can_go.append('up_left')

        where_to_go = random.choice(where_we_can_go)

        if(where_to_go == 'up_right'):

            new_entry_i = entry_i - 1

            new_entry_j = entry_j + 1

            square[new_entry_i][new_entry_j] =

                   rule1(square[entry_i][entry_j],n,True)

        if(where_to_go == 'down_left'):

            new_entry_i = entry_i + 1

            new_entry_j = entry_j - 1

            square[new_entry_i][new_entry_j] =

                   rule1(square[entry_i][entry_j],n,False)

        if(where_to_go == 'up_left' and (entry_i + entry_j) != (n)):

            new_entry_i = entry_i - 1

            new_entry_j = entry_j - 1

            square[new_entry_i][new_entry_j] =

                   rule2(square[entry_i][entry_j],n,True)

        if(where_to_go == 'down_right' and (entry_i + entry_j) != (n-2)):

            new_entry_i = entry_i + 1

            new_entry_j = entry_j + 1

            square[new_entry_i][new_entry_j] =

                   rule2(square[entry_i][entry_j],n,False)

        if(where_to_go == 'up_left' and (entry_i + entry_j) == (n)):

            new_entry_i = entry_i - 1

            new_entry_j = entry_j - 1

            square[new_entry_i][new_entry_j] =

                   rule3(square[entry_i][entry_j],n,True)

        if(where_to_go == 'down_right' and (entry_i + entry_j) == (n-2)):

            new_entry_i = entry_i + 1

            new_entry_j = entry_j + 1

            square[new_entry_i][new_entry_j] =

                   rule3(square[entry_i][entry_j],n,False)

   ❶  entry_i = new_entry_i

        entry_j = new_entry_j

    return(square)

Эта функция получает четыре аргумента: первый — исходный квадрат, содержащий значения nan; второй и третий — индексы ячейки, с которой начинается обход; четвертый — степень заполнения квадрата (количество допустимых значений nan). Функция состоит из цикла while, который при каждой итерации записывает число в квадрат по одному из трех правил. Цикл продолжается, пока не остается количество значений nan, заданное четвертым аргументом. После записи значения в ячейку цикл «переходит» в эту ячейку, изменяя индексы (❶), после чего все повторяется.

После того как функция будет написана, остается только правильно вызвать ее.


Использование правильных аргументов

Начнем заполнять магический квадрат с центральной ячейки. В аргументе howfull будет передаваться значение (n**2)/2-4. Причина для использования такого значения howfull станет понятной, когда мы увидим результаты:

entry_i = math.floor(n/2)

entry_j = math.floor(n/2)

square = fillsquare(square,entry_i,entry_j,(n**2)/2 - 4)

В данном случае функция fillsquare() вызывается с передачей существующей переменной square, определенной ранее. Напомню, что мы определили переменную square и заполнили ее значениями nan, кроме пяти центральных элементов. После того как функция fillsquare() с этим значением square на входе будет выполнена, она заполняет многие оставшиеся незаполненные значения.

Выведем полученный квадрат и посмотрим, как он выглядит после заполнения:

printsquare(square)

Результат выглядит так:

         [0]   [1]   [2]   [3]   [4]   [5]   [6]

   [0]    22   nan    16   nan    10   nan     4

   [1]   nan    23   nan    17   nan    11   nan

   [2]    30   nan    24    49    18   nan    12

   [3]   nan    31     7    25    43    19   nan

   [4]    38   nan    32     1    26   nan    20

   [5]   nan    39   nan    33   nan    27   nan

   [6]    46   nan    40   nan    34   nan    28

Обратите внимание: nan занимают чередующиеся ячейки, образуя шахматный узор. Это объясняется тем, что выбранные нами правила диагонального перемещения дают нам доступ приблизительно к половине ячеек в зависимости от того, какая ячейка была выбрана как начальная.

Допустимы те же перемещения, что и при игре в шашки: фигура, начинающая на черном квадрате, может перемещаться по диагонали на другие черные квадраты, но диагональные движения никогда не позволят ей встать на белую клетку. Если обход начинается с центральной ячейки, то оставшиеся значения nan недоступны. В алгоритме howfull передается значение (n**2)/2-4 вместо 0, поскольку мы знаем, что однократный вызов функции не позволит заполнить всю матрицу. Но если начать с одного из соседей центральной ячейки, то можно получить доступ к остальным значениям nan «шахматной доски». Снова вызовем функцию fillsquare(), однако на этот раз с другой исходной ячейкой и четвертым аргументом, равным 0 (он означает, что в квадрате не должно остаться пустых ячеек):


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Геймдизайн. Рецепты успеха лучших компьютерных игр от Super Mario и Doom до Assassin’s Creed и дальше

Что такое ГЕЙМДИЗАЙН? Это не код, графика или звук. Это не создание персонажей или раскрашивание игрового поля. Геймдизайн – это симулятор мечты, набор правил, благодаря которым игра оживает. Как создать игру, которую полюбят, от которой не смогут оторваться? Знаменитый геймдизайнер Тайнан Сильвестр на примере кейсов из самых популярных игр рассказывает как объединить эмоции и впечатления, игровую механику и мотивацию игроков. Познакомитесь с принципами дизайна, которыми пользуются ведущие студии мира! Создайте игровую механику, вызывающую эмоции и обеспечивающую разнообразие.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.