[Перевод] Игра 2048 в Wolfram Mathematica

Перевод поста 2048, Wolfram Style, написанного для официального блога компании Wolfram Research Дэном Фортунато, младшим программистом Wolfram|Alpha Parser Content.Перевод сделал Сергей Шевчук (opckSheff на Хабрахабре)Архив с файлом Wolfram Mathematica, в котором содержится код, вы можете скачать здесь.

2048-Game-In-Wolfram-Mathematica_43.gif

Если в течение последних нескольких недель вы выходили в интернет, то вы вряд ли могли не встретиться с игрой под названием 2048, разработанной Габриэлем Чирулли. Будучи основанной на похожих играх, 1024! от Veewo Studio и THREES от Ашера Воллмера, эта игра имеет простую механику, которая затянет вас надолго — перемещайте по полю фишки, на которых написаны степени числа 2 и соединяйте их попарно, чтобы получить ещё более высокие степени. Главная цель игры — получить фишку 2048. Достаточно сложно объяснить, насколько в действительности интересна и увлекательна эта игра, поэтому я рекомендую вам самим сыграть в нее.

Чтобы отдать должное этой простой игре (и в честь всех математических игр!), я решил продемонстрировать всю мощь Языка Wolfram, используя его, чтобы разработать нашу собственную версию 2048. Начнём! Основной структурой для игрового поля послужит матрица 4×4, заполненная пустыми элементами (строками нулевой длины):

In[1]:=

2048-Game-In-Wolfram-Mathematica_1.gif

Out[2]=

2048-Game-In-Wolfram-Mathematica_2.png

После начала новой игры я случайным образом расположу на поле две фишки со значениями 2 или 4. Больший приоритет я отдам фишке 2, таким образом, она будет появляться на поле чаще.

In[3]:=

2048-Game-In-Wolfram-Mathematica_3.png

In[4]:=

2048-Game-In-Wolfram-Mathematica_4.png

Out[4]=

2048-Game-In-Wolfram-Mathematica_5.png

Настало время сделать наше игровое поле немного красивее. Я могу полностью повторить стиль оригинальной игры, импортировав её CSS-стиль (CSS — Cascading Style Sheets, каскадные таблицы стилей). Как вы можете видеть, в CSS я смог найти цвета для фона и текста всех фишек.

In[5]:=

2048-Game-In-Wolfram-Mathematica_6.gif

Out[8]=

2048-Game-In-Wolfram-Mathematica_7.png

Теперь у меня есть список, содержащий каждый номер фишки и соответствующие ему цвета! Далее я могу обработать его, создав функцию для поиска цвета и перевода её из HEX (шестнадцатиричной записи цвета, используемой в CSS) в RGB (цветовую модель, основанную на сочетании красного, зелёного и синего цветов). Также я определяю цвета для остального игрового поля и, на всякий случай, для некоторых цветов по-умолчанию.

In[9]:=

2048-Game-In-Wolfram-Mathematica_8.png

In[10]:=

2048-Game-In-Wolfram-Mathematica_9.gif

In[13]:=

2048-Game-In-Wolfram-Mathematica_10.gif

Теперь я использую цветовую информацию для написания функции, отрисовывающей фишки. Необходимо проявить осмотрительность и сделать размер шрифта меньше, когда количество цифр в числе растёт.

In[15]:=

2048-Game-In-Wolfram-Mathematica_11.png

In[16]:=

2048-Game-In-Wolfram-Mathematica_12.png

In[17]:=

2048-Game-In-Wolfram-Mathematica_13.png

Я определил функцию drawTile таким образом, чтобы впоследствии её можно было легко изменить…

In[18]:=

2048-Game-In-Wolfram-Mathematica_14.png

Out[18]=

2048-Game-In-Wolfram-Mathematica_15.gif

Чтобы применить этот стиль к оригинальному игровому полю, я просто рассматриваю каждый элемент игрового поля в матрице и располагаю соответствующую ему фишку на нужном месте.

In[19]:=

2048-Game-In-Wolfram-Mathematica_16.png

In[20]:=

2048-Game-In-Wolfram-Mathematica_17.png

Out[20]=

2048-Game-In-Wolfram-Mathematica_18.gif

Выглядит красиво! Теперь нам нужно научиться управлять игрой.

Когда происходит нажатие одной из клавиш, я хочу, чтобы все фишки сдвигались по доске в указанном направлении настолько далеко, насколько это возможно, при этом одинаковые фишки должны объединяться. Я могу использовать опцию NotebookEventActions, чтобы регистрировать нажатия клавиш и соответствующе реагировать. Я сделаю так, чтобы управление осуществлялось клавишами wasd, вы можете выбрать любые другие:

In[21]:=

2048-Game-In-Wolfram-Mathematica_19.png

In[22]:=

2048-Game-In-Wolfram-Mathematica_20.png

Теперь давайте подумаем о том, что же происходит, когда фишки сдвигаются, скажем, влево. В первую очередь мне необходимо реализовать объединение одинаковых фишек. Каждая строка должна рассматриваться отдельно, поскольку при горизонтальном смещении вертикальные совпадения не объединяются. Я хочу найти последовательности из двух одинаковых чисел, возможно, с пустыми клетками между ними, и заменить их суммой. Здесь на помощь приходит мощь Языка Wolfram, и я могу использовать сопоставление с заданным шаблоным выражением, чтобы легко это осуществить.

In[23]:=

2048-Game-In-Wolfram-Mathematica_21.png

После сложения одинаковых фишек, всё, что я должен сделать — это добавить несколько пустых элементов справа, чтобы заполнить строку. Процедура повторяется для всех строк игрового поля.

In[24]:=

2048-Game-In-Wolfram-Mathematica_22.png

Сдвиг вправо осуществляется так же, с одним незначительным изменением — я хочу, чтобы сочетания одинаковых фишек справа объединялись до сочетаний, находящихся левее. Рассмотрим в качестве примера строку {$empty, 2, 2, 2}. Используя функцию combineLeft и нажав стрелку влево, я получу строку {$empty, $empty, 4, 2}, но на самом деле я хочу, чтобы сначала объединилась правая пара двоек. Переворот строки, сдвиг ячеек влево и обратный переворот легко решают проблему.

In[25]:=

2048-Game-In-Wolfram-Mathematica_23.png

In[26]:=

2048-Game-In-Wolfram-Mathematica_24.png

Теперь, когда у нас есть две этих функции, реализовать сдвиг вверх и вниз очень просто! Сдвиг вверх — это то же самое, что сдвиг влево на транспонированном игровом поле, за которым следует обратное транспонирование. Таким же отношением связаны и операции сдвига вправо и вниз.

In[27]:=

2048-Game-In-Wolfram-Mathematica_25.gif

Если клавиша нажата, новые фишки на поле должны добавляться только в том случае, если состояние поля изменилось, то есть если некоторые фишки переместились или объединились. Для этого необходимо отслеживать предыдущее состояние игрового поля.

Теперь научимся вести подсчёт очков в течение игры. Каждый раз, когда объединяются две фишки, я собираю их сумму функцией Sow, а потом использую на всех суммах функцию Reap, когда все возможные объединения совершены. Также я вывожу значение наибольшей полученной на данный момент фишки.

In[29]:=

2048-Game-In-Wolfram-Mathematica_26.png

Наконец, давайте добавим проверку на выигрыш и проигрыш. Игра считается выигранной, если наибольшая фишка на поле имеет значение 2048 или выше. Я проиграл, если доска заполнена и у меня больше нет возможных ходов. В данном случае я снова могу использовать язык шаблонных выражений, чтобы определить, остались ли на доске возможные сочетания фишек.

In[30]:=

2048-Game-In-Wolfram-Mathematica_27.png

In[31]:=

2048-Game-In-Wolfram-Mathematica_28.png

Используя функцию Dynamic, я могу поддерживать отображаемое игровое поле в полном соответствии с внесёнными изменениями. Кроме того, я могу окружить всё это функцией DynamicModule и использовать Initialization, чтобы настроить обработку нажатий клавиш и игровое поле. Поместив DynamicModule внутрь CreateDialog мы можем открывать игру в отдельном окне.

Наконец, игра полностью готова.

In[32]:=

2048-Game-In-Wolfram-Mathematica_31.png

2048-Game-In-Wolfram-Mathematica_32.gif

Сейчас всё выглядит вполне симпатично, но у нас в компании Wolfram Research мы любим что-нибудь более… заостренное. Такое, как Spikey — логотипы различных версий системы Mathematica и Wolfram|Alpha. Давайте немного изменим цвета фишек и их форму.

In[33]:=

2048-Game-In-Wolfram-Mathematica_33.gif

In[34]:=

2048-Game-In-Wolfram-Mathematica_34.png

Out[34]=

2048-Game-In-Wolfram-Mathematica_35.gif

In[35]:=

2048-Game-In-Wolfram-Mathematica_36.png

In[36]:=

2048-Game-In-Wolfram-Mathematica_37.png

In[37]:=

2048-Game-In-Wolfram-Mathematica_38.gif

In[39]:=

2048-Game-In-Wolfram-Mathematica_39.png

Теперь мы можем переключаться между двумя стилями при помощи кнопок.

In[40]:=

2048-Game-In-Wolfram-Mathematica_40.png

Out[40]=

2048-Game-In-Wolfram-Mathematica_41.png

In[41]:=

2048-Game-In-Wolfram-Mathematica_42.png

2048-Game-In-Wolfram-Mathematica_43.gif

Удачной вам игры!

© Habrahabr.ru