В данном уроке мы попробуем описать процесс создания симулятора сокращения численности населения, перенаселения и рождаемости. Он также известен под названием Игра «Жизнь», или Conway’s Game of Life. Симуляция разыгрывается на двухмерной сетке клеток. Процесс создания будет фокусироваться на срезах.
У каждой клетки есть восемь примыкающих клеток в горизонтальных, вертикальных и диагональных направлениях. В каждом поколении клетки живут и умирают, что зависит от числа живых соседей.
Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎
Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.
Создание новой вселенной в игре Жизнь
Для первой реализации Игры в «Жизнь» поставим лимит, ограничив размер вселенной. Примем решение касательно размеров сетки и определим некоторые константы:
1 2 3 4 |
const ( width = 80 height = 15 ) |
Затем определим тип Universe
, что будет содержать двухмерное поле клеток. С булевым типом каждая клетка будет либо живой (true
), либо мертвой (false
):
1 |
type Universe [][]bool |
Вместо массивов лучше использовать срезы. Таким образом, universe
можно будет поделить или изменить через функции и методы.
В следующих уроках мы в подробностях разберем указатели, что является альтернативным способом напрямую делиться массивами через функции и методы.
Напишите функцию NewUniverse
, что использует make
для определения и возвращения Universe
c высотой строк height
и шириной столбцов width
на каждый ряд:
1 |
func NewUniverse() Universe |
Новые определенные срезы по умолчанию будут с нулевыми значениями, а это false
. По этой причине изначально вселенная пуста.
Запуск пустой вселенной в игре Жизнь
Напишите метод для вывода на экран вселенной. Для этого нужно использовать пакет fmt
. Живые клетки представьте через звездочку, а мертвые через пробел. Не забудьте о переходе на новую строку после вывода каждой строки:
1 |
func (u Universe) Show() |
Затем напишите функцию main для создания NewUniverse
и Show
. Перед продолжением убедитесь, что на данном этапе вы можете запустить программу, несмотря на то, что вселенная пока пуста.
Размещение живых клеток в игре Жизнь
Напишите метод Seed
, что случайным образом размещает примерно 25% живых клеток (true
):
1 |
func (u Universe) Seed() |
Помните, что для использования функции Intn
нужен импорт пакета math/rand
. По завершении обновите функцию main для заполнения вселенной с Seed
и отображения работы с Show
.
Реализация правил игры Жизнь в программе
Правила Игры в «Жизнь» следующие:
- Живая клетка, у которой менее двух живых соседей, умирает;
- Живая клетка, у которой два или три живых соседа, живет до следующего поколения;
- Живая клетка, у которой более трех живых соседей, умирает;
- Мертвая клетка, у которой есть ровно три живых соседа, оживает.
Для имплементации правил игры разобьем их на три этапа, каждый из которых может быть методом:
- Способ определения, жива ли клетка;
- Способность подсчета количества живых соседей;
- Логика для определения состояния клетки, живая или мертвая, в следующем поколении.
Жизнь или смерть?
Определить, живая клетка или мертвая, должно быть не так уж сложно. Просто осмотрите клетку в срезе Universe
. Если булево значение true
, тогда клетка жива.
Напишите метод Alive
для типа Universe
со следующей сигнатурой:
1 |
func (u Universe) Alive(x, y int) bool |
Сложности возникают, когда клетка находится за пределами вселенной. Клетка (-1,-1) живая или мертвая? На сетке 80 x 15 клетка (80,15) живая или мертвая?
Сделаем так, чтобы вселенная при выходе за пределы значений возвращалась к началу. Сосед над (0,0) будет (0,14) вместо (0,-1), что можно посчитать через добавление height
к y
. Если y
превышает высоту height
сетки, можете обратиться к оператору модуля (%
), что мы ранее использовали, чтобы выяснить, является ли год високосным. Используйте %
для деления y
на height
и сохраните остаток. То же сделайте для x
и width
.
Подсчет соседей в игре Жизнь
Напишите метод для подсчета живых соседей указанной клетки, от 0 до 8. Вместо получения доступа к данным вселенной напрямую используйте метод Alive
, чтобы вселенная возвращалась к началу:
1 |
func (u Universe) Neighbors(x, y int) int |
Убедитесь, что подсчитываются примыкающие соседи, а не клетка вопроса.
Логика игры Жизнь
Теперь вы можете определить, есть ли у клетки два, три или более соседей. Также можно реализовать правила, описанные ранее. Напишите метод Next
, что делает следующее:
1 |
func (u Universe) Next(x, y int) bool |
Не редактируйте вселенную напрямую. Вместо этого выясните, должна ли клетка быть живой или мертвой в следующем поколении.
Параллельная вселенная игры Жизнь
Для завершения симуляции вам нужно пройтись по каждой клетке вселенной и определить, каким должно быть состояние Next
.
Может возникнуть загвоздка. Подсчет соседей базируется на предыдущем состоянии вселенной. Если модифицировать вселенную напрямую, данные изменения затронут подсчет соседей окружающих клеток.
Простым решением проблемы станет создание двух вселенных одинакового размера. Чтение через вселенную А
происходит во время размещения клеток по вселенной В
. Напишите функцию Step
для осуществления данной операции:
1 |
func Step(a, b Universe) |
Как только вселенная В
будет содержать следующее поколение, можете поменять вселенные и повторить процесс:
1 |
a, b = b, a |
Для очищения экрана перед отображением нового поколения выводится "\x0c"
, что является специальной последовательностью ANSI для выхода. Затем отображается вселенная и используется функция Sleep
из пакета time
для замедления анимации.
На заметку: Кроме Go Playground вам может потребоваться другой механизм для очищения экрана. Это может быть
"\033[H"
на macOS.
Теперь у вас есть все необходимое для создания симулятора игры Жизнь на Golang. Напишите свою программу и запустите ее на Go Playground.
Внизу дается полный текст программы симуляторы игры Жизнь.
Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.
E-mail: vasile.buldumac@ati.utm.md
Образование
Технический Университет Молдовы (utm.md), Факультет Вычислительной Техники, Информатики и Микроэлектроники
- 2014 — 2018 Universitatea Tehnică a Moldovei, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Universitatea Tehnică a Moldovei, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»