Dagaz: Пинки здравому смыслу (часть 5)
По обеим сторонам нашего плоского бытиябесконечно глубоко и далекопростирается сама жизнь. Чарлз Ховард Хинтон «Эпизод из жизни Флатландии» — Надо было ходить пешкой на е-один-дельта-аш…— Тогда летит четвертый конь.— Пусть. Пешки выходят в пространство слонов…— Какое пространство слонов? Где ты взял пространство слонов?! Ты же девятый ход неверно записал!
Многие наверняка помнят этот отрывок из незабвенного «Полдня» Аркадия и Бориса Стругацких. Люди «Полдня» почти такие же как мы, но умнее и лучше нас. Они покоряют космос и играют в четырёхмерные шахматы. Авторы «Звёздного пути» также не обошли тему настольных игр стороной, но, в их случае, Спок играет в шахматы в трёх измерениях: Выход за привычные нам пределы двумерной шахматной доски символизирует интеллектуальную мощь людей будущего и, по замыслу авторов, делает игру более интересной. Так ли это? Что, на самом деле, могут дать настольным играм третье и последующие за ним измерения?
6. Третье измерение Трёх-, четырёх-, пяти- и даже шести-мерные доски не являются в Zillions of Games какой-то экзотикой. Имеются варианты с гексагональными досками. Поклонники StarTrek-а также не оставлены без внимания (трёхмерная Klin Zha мне особенно нравится). Дело не ограничивается лишь шахматами. Здесь есть четырёхмерные крестики-нолики, Reversi и даже что-то отдалённо напоминающее Go.ZoG поддерживает доски вплоть до пяти измерений (Axiom поддерживает лишь двумерные grid-ы), но никто не мешает задать доску с произвольной топологией, определив все её позиции и связи между ними вручную. Проблема не в реализации таких игр, а в том, чтобы понять, что происходит на доске:
[embedded content]
Глядя на эту видеозапись, я завидую людям будущего. Моего интеллекта явно не хватает на то, чтобы играть даже на такой «микроскопической» доске размером 2×2x2×2x2×2. Другая крайность более понятна. В отличии от игр на основе классических шахмат, варианты Сёги на досках ограниченного размера (и размерности) оказываются неожиданно интересны. Дело здесь не в доске. Практически все варианты Сёги интересны, благодаря правилу сброса:
[embedded content]
Если бы речь шла лишь о досках с размерностью отличной от двух, на этом статью можно было бы и закончить, но есть другой способ использования в играх третьего измерения! Всем известные «Крестики-нолики» — не слишком интеллектуальная игра, но как она изменится если поставить доску вертикально? Помимо двух игроков, в игру вмешивается «третья сила» — сила гравитации. Фишки по прежнему требуется расположить «в одну линию» (4 в ряд), но добиться этого гораздо сложнее:
Игра обретает новое измерение. Фишки уже нельзя разместить в любом месте доски, они должны опираться на другие фишки, добавленные ранее. «Капитанская жёнушка» — всё ещё играется на двумерной доске, но никто не мешает применить тот же принцип и к другим играм, таким как шашки или шахматы. Вот здесь имеется великолепная подборка, состоящая из 92 таких «башенных» игр.
В «Абстрактных шахматах», все фигуры представляют собой стопки, состоящие из одинаковых фишек (кроме королевской фигуры, представляющей собой особую фишку). Одиночная фишка двигается как пешка, стопка из двух фишек — как шахматный конь, из трёх — как слон и т.д. Помимо обычных шахматных ходов, игроку разрешается брать верхнюю фишку из любой своей стопки и переносить её (ходом короля) на другую свою стопку (стоящую рядом). Свойства фигур изменяются в зависимости от текущего количества фишек в стопке.
[embedded content]
Не стоит думать, что этот принцип используется лишь в синтетических играх, придуманных недавно. «Северные шашки», упомянутые мной в предыдущей статье могут рассматриваться как вариант «Многоэтажных шашек», описанных ещё в 1961 году. Еще более почтенную историю имеют «Столбовые шашки».
[embedded content]
В этой игре, «башня» может захватывать фишки противника, «перепрыгивая» через них, по правилам «Русских шашек». При выполнении прыжка, под низ стопки берётся самая верхняя фишка из атакуемой башни. Таким образом, выполняя взятие, можно освобождать свои фишки, захваченные «башней» противника ранее. Также как и в «Русских шашках», прохождение через последнюю горизонталь превращает верхнюю фигуру стопки в дальнобойную дамку. Дамки захватываются и освобождаются наравне с обычными фигурами, не теряя своих качеств.
Существует и вариант «столбовых» шахмат. Также как в «Столбовых шашках», фигуры в «Таврелях» могут устанавливаться друг на друга (на короля устанавливать другие фигуры запрещается). Принадлежность и допустимые ходы такой «башни» определяются фигурой, находящейся сверху. Превращённая пешка, захваченная «башней», теряет свой статус и вновь превращается в обычную. Допускается построение «башен» и на фигурах своего цвета. В отличии от «Столбовых шашек», разделение «башни» происходит по желанию игрока. Игрок может даже освободить фигуру противника, захваченную им ранее (такой ход может оказаться полезным при возникновении угрозы пата).
В Ритмомахии состав «башни» определяет список доступных ей ходов и это единственная известная мне игра, в которой фигуру можно «убивать по частям». Ещё более сложная, в этом отношении, игра описана здесь. Выстраивание фишек «друг на друга» не является прерогативой шашек и шахмат. Эта возможность востребована и в других играх, например, в различного вида «боевых гонках». В «Урской игре» (в её варианте от Дмитрия Скирюка), фишка, поставленная сверху, блокирует движение всех фишек, оказавшихся под ней. Встречаются и игры, в которых, «оседлав» фишку противника, можно «покататься» на ней за чужой счёт.
Реализация «башенных» игр в ZoG никогда не была и не будет простой. Основная проблема связана с тем, что каждая ячейка доски, в этом «конструкторе игр» не может содержать более одной фигуры. Такой подход удобен в «шахматных» играх, поскольку переход на поле, занятое другой фигурой, означает автоматическое взятие последней (что позволяет сэкономить одну команду в описании хода), но как только в игре начинают фигурировать «башни», её описание превращается в кошмар. Впрочем, иногда удаётся выкрутиться.
В Ритмомахии у каждого игрока всего по одной составной фигуре. Это позволяет держать на поле некую «фиктивную» фигуру, изображающую пирамиду, а где-то в стороне от доски выводить её «расшифровку». Разумеется, такой подход не избавляет от головных болей полностью. Возникает масса «интересных» моментов. Например, когда «поедается» последняя фигура в пирамиде, очень важно удалить с доски и её «маркер». В противном случае, на доске останется «пустая» фигура, не способная «ходить» и быть «взятой», но мешающая движению других фигур. С учётом сложности правил самой Ритмомахии, реализацию такой игры никак нельзя назвать простой.В «Уре» был применён аналогичный трюк. Выстраивать фишки «в стопки», в этой игре, можно лишь на определённых полях и высота «стопки» не может превышать четырёх фишек. Для этих специальных полей были созданы своего рода «карманы», в которые складывались заблокированные фишки, при их захвате. Когда верхняя фишка покидала «стопку», последнюю из захваченных фишек следовало переложить из «кармана» на поле доски. Описание игрового поля превратилось в настоящий лабиринт:
Поле ''Урской игры'' (define board-defs (image «images/Ur/ur.bmp») (grid (start-rectangle -483 27 -422 99) (dimensions («i/j/k/l/m/n/o/z/a/b/c/d/e/f/g/h/y/x» (67 0)) ; files (»4/3/2/1/0» (0 68)) ; ranks ) ) (dummy offboard) (links afree (z2 a4) (a4 b4) (b4 c4) (c4 d4) (d4 e4) (e4 f4) (f4 g4) (g4 offboard)) (links bfree (z2 a0) (a0 b0) (b0 c0) (c0 d0) (d0 e0) (e0 f0) (f0 g0) (g0 offboard)) (links anext (a0 d1) (b0 d1) (c0 d1) (d0 d1) (e0 d1) (f0 d1) (g0 d1) (d1 c1) (c1 b1) (b1 a1) (a1 a2) (a2 b2) (b2 c2) (c2 d2) (d2 e2) (e2 f2) (f2 g2) (g2 g1) (g1 h1) (h1 h2) (h2 h3) (h3 g3) (g3 g2) ) (links cnext (h2 h3) (h3 g3) (g3 g2) (g2 f2) (f2 e2) (e2 d2) (d2 c2) (c2 b2) (b2 a2) (a2 z2) ) (links bnext (a4 d3) (b4 d3) (c4 d3) (d4 d3) (e4 d3) (f4 d3) (g4 d3) (d3 c3) (c3 b3) (b3 a3) (a3 a2) (a2 b2) (b2 c2) (c2 d2) (d2 e2) (e2 f2) (f2 g2) (g2 g3) (g3 h3) (h3 h2) (h2 h1) (h1 g1) (g1 g2) ) (links dnext (h2 h1) (h1 g1) (g1 g2) (g2 f2) (f2 e2) (e2 d2) (d2 c2) (c2 b2) (b2 a2) (a2 z2) ) (links next (x1×2) (x2×3) (x3 offboard)) (links up (b1 i1) (i1 i2) (i2 i3) (i3 offboard) (d1 j1) (j1 j2) (j2 j3) (j3 offboard) (b3 k1) (k1 k2) (k2 k3) (k3 offboard) (d3 l1) (l1 l2) (l2 l3) (l3 offboard) (g2 m1) (m1 m2) (m2 m3) (m3 offboard) (c2 n1) (n1 n2) (n2 n3) (n3 offboard) (f2 o1) (o1 o2) (o2 o3) (o3 offboard) ) (symmetry Up (anext bnext) (cnext dnext) (afree bfree)) (symmetry? Up (anext bnext) (cnext dnext) (afree bfree)) (zone (name dices) (players? Dice) (positions x1×2 x3) ) (zone (name dices-lock) (players? Dice) (positions x0) ) (zone (name promotion) (players Down) (positions h1) ) (zone (name promotion) (players? Up Up) (positions h3) ) (zone (name rosette) (players? Up Up Down) (positions a1 a3 d2 g1 g3) ) (zone (name end) (players? Up Up Down) (positions z2) ) ) Это решение вряд ли можно считать идеальным. Игрокам приходится запоминать все фишки, заблокированные в «карманах», ведь на поле они никак не отображаются! Кроме того, человеку не знакомому с игрой, может быть сложно разобраться с тем, что происходит на доске — фишки исчезают и появляются без какой либо очевидной системы. В некоторых случаях, удобнее использовать другой подход. Если поле доски может содержать лишь одну фигуру — пусть фигурами будут сами «стопки», а не составляющие их фишки! Этот подход идеально работает для игр семейства «Манкала», но если порядок в наборе фишек важен и в «стопке» могут содержаться различные фигуры — начинается комбинаторика.Комбинаторика, как и было сказано (define merge-w (if (piece? w) (add $1w) else (if (piece? b) (add $1b) else
(if (piece? ww) (add $1ww) else (if (piece? wb) (add $1wb) else (if (piece? bw) (add $1bw) else (if (piece? bb) (add $1bb) else
(if (piece? www) (add $1www) else (if (piece? wwb) (add $1wwb) else (if (piece? wbw) (add $1wbw) else (if (piece? wbb) (add $1wbb) else (if (piece? bww) (add $1bww) else (if (piece? bwb) (add $1bwb) else (if (piece? bbw) (add $1bbw) else (if (piece? bbb) (add $1bbb) else
(if (piece? wwww) (add $1wwww) else (if (piece? wwwb) (add $1wwwb) else (if (piece? wwbw) (add $1wwbw) else (if (piece? wwbb) (add $1wwbb) else (if (piece? wbww) (add $1wbww) else (if (piece? wbwb) (add $1wbwb) else (if (piece? wbbw) (add $1wbbw) else (if (piece? wbbb) (add $1wbbb) else (if (piece? bwww) (add $1bwww) else (if (piece? bwwb) (add $1bwwb) else (if (piece? bwbw) (add $1bwbw) else (if (piece? bwbb) (add $1bwbb) else (if (piece? bbww) (add $1bbww) else (if (piece? bbwb) (add $1bbwb) else (if (piece? bbbw) (add $1bbbw) else (if (piece? bbbb) (add $1bbbb) else
(if (piece? wwwww) (r w) (add $1wwww) else (if (piece? wwwwb) (add $1wwww) else (if (piece? wwwbw) (r w) (add $1wwwb) else (if (piece? wwwbb) (add $1wwwb) else (if (piece? wwbww) (r w) (add $1wwbw) else (if (piece? wwbwb) (add $1wwbw) else (if (piece? wwbbw) (r w) (add $1wwbb) else (if (piece? wwbbb) (add $1wwbb) else (if (piece? wbwww) (r w) (add $1wbww) else (if (piece? wbwwb) (add $1wbww) else (if (piece? wbwbw) (r w) (add $1wbwb) else (if (piece? wbwbb) (add $1wbwb) else (if (piece? wbbww) (r w) (add $1wbbw) else (if (piece? wbbwb) (add $1wbbw) else (if (piece? wbbbw) (r w) (add $1wbbb) else (if (piece? wbbbb) (add $1wbbb) else (if (piece? bwwww) (r w) (add $1bwww) else (if (piece? bwwwb) (add $1bwww) else (if (piece? bwwbw) (r w) (add $1bwwb) else (if (piece? bwwbb) (add $1bwwb) else (if (piece? bwbww) (r w) (add $1bwbw) else (if (piece? bwbwb) (add $1bwbw) else (if (piece? bwbbw) (r w) (add $1bwbb) else (if (piece? bwbbb) (add $1bwbb) else (if (piece? bbwww) (r w) (add $1bbww) else (if (piece? bbwwb) (add $1bbww) else (if (piece? bbwbw) (r w) (add $1bbwb) else (if (piece? bbwbb) (add $1bbwb) else (if (piece? bbbww) (r w) (add $1bbbw) else (if (piece? bbbwb) (add $1bbbw) else (if (piece? bbbbw) (r w) (add $1bbbb) else (if (piece? bbbbb) (add $1bbbb)
)))))))))))))))))))))))))))))))) )))))))))))))))) )))))))) )))) )) ) Этот кошмарный макрос — всего лишь небольшой фрагмент моей реализации игры «Фокус», описанной Мартином Гарднером в его «Математических досугах» (полную версию кошмара можно смотреть здесь). Сложнее всего было найти и исправить все ошибки. Конечно, можно было бы автоматизировать кодогенерацию при помощи prezrf, но, на самом деле, ещё не известно, какое из этих «двух зол» злее. Впрочем, работает программа великолепно:[embedded content]
Кстати В процессе этого «праздника кодирования» выяснилось, что макросам ZoG крайне далеко до функций высшего порядка. Первая версия не работала из за реализации этого макроса: (define add-piece (if empty? add else (merge-$1 $2) ) ) Подстановка параметра $1 отрабатывала замечательно, но находить макрос по полученному имени (например merge-w) ZoG решительно отказывалась, хотя в исходном коде он, разумеется, был! Пришлось чуть больше поработать руками. Разумеется, этот подход не работает в более сложных случаях. В «Фокусе» размер «стопки» ограничен пятью фишками. Всё что не попадает в это «прокрустово ложе» либо переносится в резерв игрока, либо полностью удаляется с доски (в зависимости от принадлежности фишек игроку, выполняющему ход). В «Столбовых шашках» фигуры не покидают доску никогда! В процессе игры, все 24 фишки могут быть выстроены в одну «башню». При этом, часть фигур может быть дамками! Желающие могут сами подсчитать количество возможных вариантов и сравнить это число с 62 фигурами, использованными для реализации «Фокуса». В «Столбовых шашках» необходимо создавать настоящую трёхмерную доску: Описание доски в ''Столбовых шашках'' (define Bdef (image «images\Bashne\bd8×8x2.bmp») (grid (start-rectangle 5 45 53 93) (dimensions («a/b/c/d/e/f/g/h» (49 0)) ; files (»8/7/6/5/4/3/2/1» (0 49)) ; ranks )
(directions (ne 1 -1) (nw -1 -1) (se 1 1) (sw -1 1) ) )
(grid (start-rectangle 407 89 455 93) (dimensions («A/B/C/D/E/F/G/H» (49 0)) ; files (»8/7/6/5/4/3/2/1» (0 49)) ; ranks (»-1/-2/-3/-4/-5/-6/-7/-8/-9/-10/-11/-12/-13/-14/-15/-16» (0 -3)) ; ranks ) (directions (u 0 0 1)(u5 0 0 5) (r 1 0 0) ; scan ) ) ) Можно видеть, что Karl Scherer был слишком оптимистичен в отношении максимально возможной высоты «башен». Доска, в его реализации, состоит из двух grid-ов. Левый — представляет собой обычную двумерную доску, на которой игроки перемещают фигуры, но все ходы, выполненные на этой доске, дублируются в правом grid-е, содержащем детальное описание фигур.Это наиболее правильный подход к реализации таких игр, но даже с его помощью будет затруднительно реализовать «Таврели». С учётом того, что на королевскую фигуру установка других фигур запрещается, «башня» максимальной высоты, в этой игре, может состоять из 31 фигуры (подсчёт количества возможных вариантов построения башен — интересная комбинаторная задача).
Из всего сказанного выше должно быть понятно, что разработка методов эффективного и лаконичного описания «башенных» игр является серьёзным вызовом для разработчика универсального игрового «движка». К сожалению, я не могу сказать, что решил эту проблему. Было бы заманчиво разрешить размещать на поле доски более одной фигуры, но это решение сразу же поднимает ряд острых вопросов. Упорядочен ли набор фигур размещенных на поле? Как определить владельца набора? Какие части набора могут выполнять ход как «единое целое» и по каким правилам? Я не вижу разумных решений на этом пути.
Более перспективной выглядит возможность объединения фигур в наборы, в процессе генерации хода. Можно объединять фигуры, расположенные друг над другом (ещё до выполнения основной фазы генерации хода), и перемещать этот набор как единое целое. Фигуры, расположенные «в стопке» независимы и мы всегда можем определить принадлежность отдельной фигуры и возможность выполнения ей хода. Самое главное, что такой подход универсален. Помимо «башенных» игр, он позволяет описывать все те игры, в которых разрешается перемещать группы фигур за один ход (такие как Ordo или головоломка «Рыжий осёл», описанная М.Гарднером в тех же «Математических досугах»).
К сожалению, вопросы всё равно остаются. Фигуры, объединённые в набор, должны перемещаться «параллельно», в одном направлении, но выбранное направление может быть не определено для какой-то из начальных позиций набора! Также, перемещение может предусматривать выполнение проверок при прохождении промежуточных полей всеми фигурами набора (как в игре «Ордо»). Совершенно непонятно как сформулировать такие проверки лаконичным и понятным для человека образом. Неясно, как реализовать групповые перемещения, отличные от «параллельного переноса», например такие, как поворот части доски в «Turn the Tables Checkers». В общем, вопросов хватает. Надеюсь, мне удастся их решить.
В заключение статьи, приведу цитату из замечательного блога Григория (gest-а), посвящённую ещё одной многомерной игре:
… У каждого игрока по четыре фигуры. За каждой фигурой остаётся след, отмечающий её перемещения. Можно убивать противника в прошлом, перерезая его темпоральную линию. Можно убивать вражескую фигуру в прошлом и этим воскресать собственную фигуру, в той точке, где противник её бы убил, если бы не был сам убит до этого. В ситуации, когда противник может перерезать темпоральную линию твоей фигуры и этим воскресить фигуру, ранее убитую тобой, можно использовать другую свою фигуру, чтобы убить уже убитую вражескую фигуру ещё раньше.
Люди придумали много игр, над которыми можно поломать голову…