Пользователь
12,0
рейтинг
14 декабря 2015 в 14:22

Разработка → Несколько хороших манкал

             Хотя этикетка была не того цвета и содержала немало орфографических ошибок, большая ее часть находилась на месте, включая сделанную крошечным шрифтом надпись «Может содержать орехи».
                                                         сэр Терри Пратчетт 

Го или Ур? Можно долго спорить, какая из игр древнее, но победит, в этом противостоянии, скорее всего, Манкала. Археологи предпочитают иметь дело с материальными свидетельствами, но как только речь заходит о настольных играх, всё быстро уходит в область предположений. Было найдено немало досок, но гораздо меньше сведений о том, как на них играть. Древние не утруждали себя детальным описанием правил.

С Манкалой ситуация прямо противоположная. Это не одна игра, а весьма многочисленное семейство. В одной только Западной Африке, счёт идёт на десятки (если не на сотни) разновидностей. Доска (как материальный артефакт) для таких игр не обязательна. Достаточно взять пригоршню камушков и выкопать несколько ямок в песке. Не удивительно, что археологи испытывают затруднения с определением возраста этих игр. Им попросту нечего искать! Но для внимательного исследователя «настольных игр», манкалы не менее интересны, чем птицы семейства пересмешниковых для Чарлза Дарвина.

На сегодняшний день, в каталоге Zillions of Games содержится более двух тысяч приложений. Нельзя сказать, чтобы среди них совсем не было манкал. Во всяком случае, двурядные и четырёхрядные варианты игр представлены весьма основательно. Вот такой набор игр предоставляется всего лишь одним из приложений:


Это действительно достойный список, но, как я уже писал выше, количество манкал исчисляется сотнями, а здесь представлены, скажем так, наиболее привычные из них. Существуют куда более удивительные и замечательные разновидности этой игры. И сейчас я хочу ими заняться! Но для начала, стоит составить небольшой словарик терминов, для того, чтобы люди, не знакомые с предметом, имели хоть какие-то шансы в нём разобраться.

Словарик
  • посев — У большинства народов, практикующих их, манкалы символизируют привычную сельскохозяйственную деятельность. Метафора «посева» объединяет все эти игры. Выполняя ход, игрок забирает все камни из одной из своих лунок и начинает раскладывать их по одному, по всем следующим лункам, в одном из направлений, разрешённых правилами. Существуют различные пословицы и поговорки, связывающие тактику игры с сельскохозяйственными понятиями, аналогичные русскому варианту «что посеешь, то и пожнёшь».
  • однократный посев — В большом количестве вариантов игры, «посев» выполняется «однократно». После того как игрок раскладывает последний из взятых камней (не важно, в пустую или заполненную лунку), ход переходит другому игроку. Существуют различные варианты «посева», затрудняющие расчёт в игре. Например, посев может начинаться не со следующей лунки, а с текущей (то есть, один камень просто остаётся в лунке) или стартовая лунка может пропускаться при посеве, если взятое число камней достаточно для того, чтобы сделать один или несколько кругов, обойдя все лунки.
  • циклический посев — Более сложная разновидность хода. Ход начинается также как и «однократный посев», но, если игрок выкладывает последний камень в заполненную лунку, он немедленно забирает из неё все камни (включая добавленный последним) и продолжает посев со следующей лунки. Ход заканчивается когда последний камень падает в пустую лунку.
  • бесконечный посев — Как легко догадаться, выполняя «циклический посев», игрок вполне может «зациклиться». Игрок не сможет завершить ход, поскольку последний камень никогда не будет попадать в пустую лунку. Такая ситуация называется «бесконечным посевом» и реакция на неё регламентируется правилами конкретной игры. Обычно, при возникновении «бесконечного посева», партия считается не сыгранной либо переигрывается.
  • захват — Цель почти любой манкалы (есть несколько исключений) — захват максимального количества камней. Правила, позволяющие перекладывать камни с доски в свой «амбар», существенно различаются, в зависимости от варианта игры. В двурядных манкалах, правила захвата часто связаны с количеством камней в финальной лунке (например, в "Тогыз Кумалак", захват выполняется, если после добавления последнего камня посева число камней в лунке стало чётным). В четырёхрядных манкалах, поскольку посев идёт лишь по своей территории, захват «позиционный» (в Chuba, если последний камень упал в пустую лунку внутреннего ряда, захватываются все камни из противостоящей лунки во внутреннем ряду противника, а также камни из следующей за ней лунки внешнего ряда, если они там есть).
  • серийный захват — Часто, захват осуществляется сразу из нескольких лунок. Так например, в Вари, игрок захватывает камни, если в последней лунке посева оказалось 2 или 3 камня. Если в предыдущих (по направлению посева) лунках противника также оказалось по 2 или 3 камня, они захватываются тоже!
  • полный захват — В большинстве манкал, игрок не сможет выполнить ход, оставшись без камней. Часто, в таких случаях, игра завершается. Все камни, оставшиеся на территории противника, перекладываются в его амбар, после чего подсчитываются. Это вполне нормальное завершение игры, но, чтобы игра была более интересной, вводятся правила, целью которых является увеличение продолжительности игры. Например, правилами может быть запрещено выполнение ходов, приводящих к захвату всех оставшихся камней на территории противника, так называемому «полному захвату».
  • правило «голода» — Другая сторона той же монеты. Если противник остался без камней на своей стороне, игрок обязан «подкормить» его, подкинув на чужую территорию хотя бы один камень. Если такой ход невозможен — игра заканчивается. Это один из примеров очень редкой для манкал разновидности форсированных ходов, аналогичных обязательному взятию в Шашках или уходу из под шаха в Шахматах.
  • нулевой посев — Во многих случаях, первый игрок имеет преимущество. Чтобы решить эту проблему (а также сломать всевозможные дебютные «домашние заготовки»), в некоторых манкалах, при выполнении первого хода захват не выполняется. Цель этого «нулевого» прогона — рандомизация позиции на доске. Часто, для экономии времени, игроки выполняют «нулевой посев» одновременно. В этих случаях он служит и для определения очерёдности хода. Игрок, завершивший посев первым, делает первый ход.
  • коми — Этот термин пришёл из Го и является ещё одним способом компенсации преимущества первого игрока. Второй игрок, ещё до начала игры, получает некоторое оговоренное количество очков (как правило дробное, чтобы исключить возможность ничьих). В Го и некоторых современных манкалах такой подход активно используется.
  • сэнтэ и готэ — Ещё два понятия из Го. Сэнтэ — это ход, на который противник вынужден ответить, а готэ — напротив, вынужденный ход. Некоторые современные манкалы оперируют этими терминами, хотя и понимают их несколько по своему.
  • правило «пинг-понга» — В Алемунгула возможна ситуация, при которой игроки будут иметь возможность, ход за ходом, перекидывать друг другу один и тот же камень. Правило «пинг-понга» запрещает подобное повторение позиции. По аналогии с предыдущими терминами, его следовало бы назвать "Правилом Ко", но, по всей видимости, жители Эфиопии были слабо знакомы с японской игрой.


Tchuka Ruma


Начать я решил с простого. Чука Рума не является традиционной игрой (в том смысле, что лет ей не 5000, а всего 120), но по правилам весьма сходна с Даконом, широко распространённым на территории Индонезии. За исключением того что Чука Рума рассчитана на игру одного человека. Да, это единственная известная мне манкала-пасьянс. Вот как она выглядит:


Требуется перенести все камни в «амбар» (крайнюю правую лунку), соблюдая следующие правила:

  • В начале игры, можно взять все камни из любой лунки (кроме «амбара») и выполнить циклический посев, раскладывая камни слева-направо и переходя от «амбара» к крайней левой лунке.
  • Если последний камень падает в «амбар», игрок получает право повторить ход, вновь выбрав любую не пустую лунку, кроме «амбара» (именно это правило роднит «Чука Руму» с манкалами семейства «Чонгкак» и «Дакон»).
  • Если циклический посев завершён в любой другой лунке — игрок проигрывает (пасьянс не сошёлся).

Эта замечательная «гимнастика для ума» впервые (в 1895 году) была описана французским математиком Анри-Огюстом Деланнуа в переписке с его коллегой Эдуардом Лукасом. Любое сходство с «Даконом» не случайно, так как, по всей видимости, именно эту игру Анри-Огюст использовал в качестве прототипа.

Самый ''простой'' посев
В принципе, никто не мешает использовать для разработки манкал «штатный» ZRF. Кучки камней представляются отдельными фигурами (по числу камней) и вся задача «посева» заключается в правильном изменении типа нескольких фигур, за один ход (ZSG-нотация становится совершенно нечитаемой, но читать её никто и не собирается). Это было бы почти так же просто как рокировка, если бы не один фатальный недостаток ZRF. В нём напрочь отсутствует какая либо арифметика!

Код на нём действительно кошмарен
(define AB if (piece? $1) (change-type $2) else)

(define OC (set-position-flag occ true))

(define ABC
	((AB $1 $2)   ((AB $3 $4)   ((AB $5 $6)   ((AB $7 $8)
	((AB $9 $10)  ((AB $11 $12) ((AB $13 $14) ((AB $15 $16)
	((AB $17 $18) ((AB $19 $20) ((AB $21 $22) ((AB $23 $24)
	((AB $25 $26) ((AB $27 $28) ((AB $29 $30) ((AB $31 $32)
	((AB $33 $34) ((AB $35 $36) ((AB $37 $38) ((AB $39 $40) 
	((AB $41 $42) ((AB $43 $44) ((AB $45 $46) ((AB $47 $48)
	((AB $49 $50) ((AB $51 $52) ((AB $53 $54) ((AB $55 $56)
	((AB $57 $58) ((AB $59 $60) ((AB $61 $62) ((AB $63 $64)
	((AB $65 $66) ((AB $67 $68) ((AB $69 $70) ((AB $71 $72)
	(set-flag emu true)))))))))))))))))))))))))))))))))))))
)

(define sow-in-store cascade (while not-empty? e) to (OC) (go from))

(define sow-in-store2 
	cascade (while not-empty? e) 
	cascade e to (while (not-in-zone? store) (opposite e))
)

(define sow-in-store3 
	cascade (while not-empty? e) 
	cascade e cascade e to (while (not-in-zone? store) (opposite e))
)
...


Это часть реализации Калаха и продраться через все её макросы действительно не просто. Я решил не мучать свой мозг и задействовать Axiom. Используемый ей, в качестве скриптового языка, ForthScript конечно придаёт процессу программирования некоторую пикантность. Но в нём можно складывать числа!

Начнём с определения фигур
DEFER		MARK
...
{pieces
	{piece}		m
	{piece}		p1	1	{value}
	{piece}		p2	2	{value}
	...
pieces}
...
' m	IS MARK


Фигура m — фиктивная. От неё будет выполняться «отсчёт» при построении всех остальных фигур. Псевдоним MARK позволит на неё ссылаться из вышележащего кода. Числовое значение — количество камней в «кучке» и, по совместительству, вес «фигуры», используемый AI Axiom (для «Чука Румы» этот вопрос не особенно актуален, но в играх двух игроков будет иметь первостепенную важность).

Добавим движущиеся фигуры
: get-value ( -- value )
	empty? IF			( Если поле пусто )
		0			( Возвращаем 0 )
	ELSE				( иначе )
		piece piece-value	( Достаём значение value из описания фигуры )
	ENDIF
;

: move-q ( -- )
	get-value stone-count !		( Сохраняем количество камней в переменную )
	next verify			( Перемещаемся в следующую лунку )
	from here move			( Переносим фигуру с её начального положения в текущее )
	build-trace			( Рассчитываем изменения всех фигур )
	from to 			( Возвращаемся в исходную точку )
	use-trace			( Применяем все рассчитанные изменения ... )
	add-move			( и завершаем генерацию хода )
;

{moves q-moves
	{move} move-q
moves}

{pieces
	...
	{piece}		q1	{moves}	q-moves	1	{value}
	{piece}		q2	{moves}	q-moves	2	{value}
	{piece}		q3	{moves}	q-moves	3	{value}
	...
pieces}


Здесь есть две «тёмных лошадки» — build-trace и use-trace, далее мы рассмотрим их базовую реализацию. Оставшаяся часть move-q связана с «перемещением» фигуры. Дело в том, что любой ход в ZoG должен быть связан с одним из двух возможных действий: перемещением фигуры с одной позиции доски на другую (move) или добавлением новой фигуры на доску (drop). Соответственно, одно из этих управляющих слов должно быть задействовано и в описании хода. Все остальные (побочные) действия должны выполняться после этого (основного) действия.

Рассчитаем ''трассу''
COLS []		trace[]
VARIABLE	trace-count
VARIABLE	stone-count

: build-trace ( -- )
	0 trace-count !				( На всякий случай, "очищаем" массив )
	0 BEGIN					( и начинаем цикл )
		DUP COLS >= IF			( Если оказалось, что мы обошли вокруг доски )
			DROP 0			( Зацикливаем массив, его длина не должна превышать количества лунок )
		ENDIF
		DUP trace-count @ < IF		( Если мы уже вычисляли число камней в этой лунке )
			DUP trace[] @		( Достаём ранее вычисленное значение )
		ELSE				( иначе )
			trace-count ++		( Увеличиваем размер массива )
			from here <> IF		( и если это не исходная лунка )
				get-value	( Достаём из неё количество камней )
			ELSE
				0		( Исходная лунка первоначально пуста, мы "вынули" из неё камни )
			ENDIF
		ENDIF
		1+ OVER trace[] !		( Добавляем один камень )
		stone-count --			( Уменьшаем количество оставшихся камней )
		stone-count @ 0= IF		( И если камни кончились ... )
			TRUE			( Завершаем цикл )
		ELSE				( иначе )
			1+ next verify		( Двигаемся по доске дальше )
			FALSE			( и НЕ завершаем цикл )
		ENDIF
	UNTIL					( Цикл завершается, если на верхушке стека TRUE )
	...					( Здесь удобное место для всякой "магии" )
	DROP
;


Все изменения рассчитаны, осталось их применить!

И изменим все фигуры, попавшие под раздачу
: use-trace ( -- )
	0 BEGIN					( Перебираем все элементы массива )
		next verify			( Двигаясь в направлении посева )
		DUP trace[] @                   ( Вынимаем из массива количество камней )
		MARK + create-piece-type	( И создаём фигуру соответвующего типа, добавляя его к MARK )
		1+ DUP trace-count @ >=		( Если конец массива - завершаем цикл )
	UNTIL DROP				( Не забываем следить за стеком ! )
;


Ну вот, мы научились брать камни из лунки и раскладывать их по одному, в направлении посева. В том или ином виде, этот код будет использован во всех сегодняшних манкалах. Разумеется, реальный код немного сложнее. Например, приходится «подсвечивать» те группы камней, ходить которыми разрешено (иначе сходить ими не удастся) и снимать подсветку с остальных групп. При попадании в «амбар», необходимо помечать все группы, оставшиеся на доске. И разумеется, необходимо написать код, определяющий условия завершения игры. Куча мелочей, без которых ничего работать не будет!

Вот что получилось в итоге:



Надо сказать, что AI Axiom щелкает такие задачки «как орешки». Исходный расклад (по два камня в четырёх лунках) ZoG решила на минимальных настройках «продолжительности хода». Для более сложных раскладов, настройки пришлось «подкрутить», поскольку, в противном случае, программа попадала в тупик. В процессе тестирования, был найден ещё один «решаемый» расклад, для любителей «поломать голову».

Ohojitxi


В эту весьма оригинальную манкалу играют в республике Кот-д’Ивуар. Внешне, она выглядит как обычная двурядная манкала, с шестью лунками на каждой стороне, но поскольку при игре доска располагается «вертикально», её более уместно причислять не к двурядным, а к «шестирядным» манкалам. Посев однократный, против часовой стрелки и только на своей территории — в трёх рядах, обращённых к игроку.

На этом неожиданности не заканчиваются! Цель игры — не захват камней противника, а избавление от своих собственных. Захваченные камни передаются противнику (помещаются в одну из его лунок). Кто первый избавится от всех своих камней — тот и победил. Захват серийный, если последний камень падает в лунку с тремя камнями (дополняя их до четырёх) — камни захватываются. Вместе с ними захватываются камни из всех предыдущих (против направления посева) лунок, содержащих четыре камня. Если бы первоначально все 24 камня находились в одной лунке, игру можно было бы завершить за один ход!



В общем, игра довольно забавная. На первый взгляд, она не сильно отличается от предыдущего пасьянса (поскольку посев всегда ведётся лишь на своей территории), но если противник успеет «собрать четвёрку» раньше вас, будьте уверены, он постарается выбрать лунку таким образом, чтобы максимально расстроить все ваши планы (и всё придётся начинать сначала). Единственное ограничение заключается в том, что он не может каждый раз выбирать одну и ту же лунку.

Как важно быть внимательным
Доска в Axiom — это один большой линейный массив. Серьёзно, мы можем просто начать с нуля и перебрать все позиции, добавляя к индексу единичку. Поскольку, в реальной жизни, редко встречаются одномерные доски (редко, но встречаются), Axiom заботится о нас, предоставляя средство для определения досок «двумерных»:

2	CONSTANT	COLS
6	CONSTANT	ROWS

{board
	ROWS COLS	{grid}
board}

На самом деле, это всё тот же одномерный массив, ячейки которого поименованы забавным образом (ещё он позволяет определять «направления», оперируя приращениями координат, а не парами позиций, но это нам сейчас не понадобится):


В ZRF-описании, мы должны разметить доску аналогичным образом, чтобы ZoG понимала, с чем имеет дело:

  (board 
    (image "Images/Ohojitxi/6x2.bmp")
    (grid
      (start-rectangle 6 4 73 89)
      (dimensions
        ("a/b" (67 0)) ; files
        ("6/5/4/3/2/1" (0 85)) ; ranks
      )
    )
  )

Вот с этого места и начинается веселье. Мы пишем много кода, кодируя посевы и захваты, постепенно забывая об унылом и отсталом ZRF. В какой то момент, нам становится позарез необходимо закодировать новое правило — «выполняя захват, игрок не может каждый раз выбирать одну и ту же лунку противника». Очевидно, пометки лунок необходимо где то хранить! А где ещё, если не на доске?

4	CONSTANT	COLS

Смело расширяем доску вдвое! Нет, это даже работает. Некоторое время. Сразу вслед за этим, мы получаем от программы загадочное послание:


Ясно, что кто-то кого-то не понимает, но чтобы вспомнить о ZRF требуется ещё полчаса нервных поисков! И уже после того как игра сделана, отлажена и даже отправлена для публикации, всплывает тот факт, что вариантов досок мы делали два.

Играть в Охочичи приятно при наличии большого количества свободного времени. Партия равных соперников может продолжаться очень долго. Для того, чтобы собрать последние камни, приходится потратить немало ходов. Как правило, противник успевает раньше и всё начинается с начала. Серийный захват помогает разорвать порочный круг, но его ещё надо сложить. Когда программа играет «сама с собой», средняя продолжительность партии составляет порядка 500 ходов (впрочем, меня она обыгрывает так быстро, что я не успеваю сообразить, что произошло).

Afrika


Да-да, именно через эту букву! Слово-то немецкое. Я имею в виду, что придумал игру немец — Ralf Gering. И произошло это в 2004 году. Это скандальная манкала! Во-первых, ей меньше 120 лет. Помимо этого, она собрала 5 «рейтингов ненависти» на BoardGameGeek. Впоследствии выяснилось, что все они от «виртуалов» одного и того же человека (подозреваю, что это было что-то личное) и из пяти был оставлен один, самый первый.

Если говорить серьёзно, то эта игра слишком не похожа на все другие манкалы. По «геймплею» она гораздо ближе к Шашкам. Всё дело в механизме захвата. В «Африке» он обязательный! В других манкалах тоже есть «форсированные» ходы (правило «голода» — в большинстве африканских манкал), но там они не имеют столь первостепенного значения! Если есть возможность захвата — игрок должен брать! И это то, что делает игру уникальной.


Правила просты. Посев однократный, всегда из своего ряда, против часовой стрелки, без захода в «амбары». Захват осуществляется из не пустой лунки противника, расположенной напротив пустой лунки игрока и может выполняться лишь из лунок, содержащих минимальное количество камней (если в одной лунке два камня, а в другой три — брать можно только из той, где два). Захват считается отдельным ходом и имеет приоритет по отношению к «посеву». Такие правила закономерно приводят к тактике «отдай меньше, чтобы забрать больше»:


Диаграмма великолепно иллюстрирует концепцию. Мы отдаём один камень, чтобы взамен забрать четыре (сразу скажу, что столь очевидный ход впоследствии заводит в тупик, у задачки есть лучшее решение). Самое замечательное в этом то, что противник не может игнорировать нашу жертву. Он обязан взять камень и, теряя ход, не может защитить свои. Это в гораздо большей степени «сэнтэ» чем смысл, вкладываемый в это понятие в Го. Как и в Шашках, отказ от форсированных ходов сделает игру куда менее интересной.

Как правило, в играх с «обязательным взятием», «обратная игра» представляет определённый интерес (возможно для многих будет сюрпризом, но "Поддавки", в тактическом плане, гораздо более сложная игра, чем обычные шашки). В ноябре 2010 года, Benedikt Rosenau предложил «обратный» вариант игры, на основе правил «Африки». Разумеется, я реализовал оба варианта игры.

Чьи камни?
В Охочичи посев вёлся на своей территории, а в «Чука Руме» игрок вообще был один. «Африка» — первая игра, в которой мы заходим на территорию противника. Немедленно возникает проблема. Дело в том, что в ZoG игрок может перемещать только свои фигуры! Отчасти, это ограничение связано с вопросами производительности и оно может даже казаться разумным, до тех пор, пока мы не сталкиваемся с чем-то вроде этого. В нашем случае, важно, что мы должны следить не только за типом фигур (количество камней и пометка), но и за их принадлежностью.

К счастью, это просто
: get-player ( -- )
	here COLS < IF				( Если текущая позиция в верхней половине доски )
		Second				( Фигура принадлежит игроку Second )
	ELSE					( иначе ... )
		First				( Это First )
	ENDIF
;


Это почти всё, о чем приходится заботится, за исключением одного нюанса. Если после хода игрока, на его территории остаются группы, расположенные напротив пустых лунок, мы должны найти наименьшую из них и пометить её (а также, возможно, ещё несколько групп, содержащих равное количество камней) для того, чтобы одну из них смог взять противник (это будет его обязательный ход). Разумеется, взять он их сможет только при условии того, что помеченные фигуры будут принадлежать ему, следовательно эту ситуацию придётся обработать особым образом:

Помечаем фигуры
: use-trace ( -- )
	0 BEGIN
		next verify
		get-player				( Определяем, на чьей мы стороне )
		OVER trace[] @				( и количество камней )
		DUP min-target @ = IF			( Если оно совпадает с целью захвата )
			OVER current-player = IF	( и расположено на нашей стороне )
				check-target		( Помечаем группу камней, подлежащую захвату )
			ENDIF
		ENDIF					
		DUP 0< IF				( Если группа камней помечена )
			SWAP DROP next-player SWAP	( Ей должен владеть противник )
		ENDIF
		MARK + create-player-piece-type		( Вычисляем тип фигуры и создаём её с правильным владельцем )
		1+ DUP trace-count @ >=			( Перебираем элементы массива, пока они не кончатся )
	UNTIL DROP
	...
;


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

Статистически, первый игрок имеет небольшое преимущество, но я не стал вводить коми (2.5 очка) для второго игрока. Первым ходит человек и небольшое преимущество в борьбе с машиной не будет лишним.

Gabata


Закончив «разминку», я приступил к двум наиболее интересным для себя играм. Обе играются на уникальной трёхрядной доске и распространены на восточном побережье Сомалийского полуострова. Собственно, доска и даёт название первой из них. Габата — очень архаичная игровая система. Некоторые исследователи считают её родоначальницей всех манкал. Форма доски диктует непривычную схему посева. Это проще показать, чем объяснить:


Стрелки показывают направление посева. Посев циклический и начинать ход можно только из своих лунок (нижний ряд и три правых лунки во втором ряду). В принципе, в большинство игр, традиционно играемых на доске «Габаты», можно было бы играть на обычной, двурядной доске, но в самой «Габате» трёхрядность используется при выполнении захвата. Если последний камень падает в пустую лунку, игрок захватывает все камни противника, расположенные в том же столбце доски.

Тонкости захвата
Семантика перемещения фигур в ZoG причудлива. Изначально имеется две возможности: перемещение фигуры с одного поля доски на другое (move) и создание фигуры заданного типа на выбранном поле (drop). Самое главное, о чём приходится помнить, это то, что на всём протяжении расчёта хода, позиция на доске остаётся в том же состоянии, в котором она была в момент начала расчёта. Это кажется логичным, но на практике портит немало крови.


На диаграмме представлен кейс, с которым я столкнулся довольно поздно, когда игра, в основном, была уже готова. Второй игрок (тот что сверху) должен взять один камень (из своего же посева) и продолжить захват. Так это должно было выглядеть. А вот как это выглядело:


В какой то момент, я заметил, что у игрока оказалось две выделенных группы камней! Попробуем разобраться, что произошло. Выполняя посев, мы «переместили» группу из 4 камней на одну лунку вправо (там же она и осталась). Если бы не выполнялось взятий, мы должны были бы заменить содержимое этой лунки одним камнем, но так как мы взяли этот камень, то обнулили его в trace:

: use-trace ( -- )
	0 BEGIN
		next verify
		DUP trace[] @
		DUP 0 <> IF
			...
		ELSE					( Если посеянные камни необходимо удалить )
			DROP				( Следим за стеком !!! )
			empty? NOT IF capture ENDIF	( Удаляем камни из лунки, если она не пуста )
		ENDIF
		1+ DUP trace-count @ >=
	UNTIL DROP
;

Мы удаляем взятые камни из не пустых лунок, но в нашем случае, лунка была пуста! Мы не пытались заполнить её камнем из посева (поскольку он был взят), но и не удалили камни из неё (поскольку при попытке удаления из пустой лунки могут возникнуть проблемы). Чего мы не учли, так это того, что лунка, пустая в начале хода, вполне может перестать быть таковой по его завершении. Лунка была заполнена «основным» действием по переносу камней в соседнюю лунку. Мораль этой истории в том, что не только начальное поле хода следует обрабатывать особым образом.

Легко видеть, что захваты, выполняемые в различных столбцах, не равноценны. Возможны захваты сразу из двух лунок, также как и ситуации, при которых захватить не удастся вообще ничего (например, при завершении хода в одной из трёх начальных лунок противника). Игрок получает право на выполнение ещё одного хода, камнем осуществившим захват (неограниченное количество раз) и это правило вносит в игру ещё большее тактическое разнообразие. Габату часто называют «пиратской манкалой» и с тем, что играют в неё на территории Сомали это связано лишь отчасти:



Когда один из игроков не может выполнить очередной ход, его оппонент захватывает все оставшиеся на доске камни. Игра продолжается несколько раундов (это характерно для всех игр на доске «Габаты»). Начиная очередной раунд, игроки раскладывают камни, захваченные в предыдущем раунде, по своим лункам, по три, начиная с левой, в нижнем ряду. Если в последней лунке оказывается меньше трёх камней, более сильный игрок, дополняет её до трёх, из своих камней. Оставшиеся камни более сильного игрока сразу уходят в его «амбар». Выигрывает тот, кто соберёт все камни.

Selus


Эта игра — моя любимая! Играется на той же доске, что и Габата (и также, с использованием циклического посева), но с совершенно иным механизмом захвата. В ней, игроки строят ловушки («wegue»). Ходить из wegue нельзя, но любой камень, попавший в них, становится собственностью создавшего их игрока. Построить ловушку просто — если последний камень посева попадает в лунку с тремя камнями (дополняя её до четырёх), лунка становится wegue. Количество wegue не ограничено!

Нельзя назвать такой механизм захвата уникальным. Есть несколько родственных Селусу игр с аналогичным взятием камней. В казахской манкале "Тогыз Кумалак" игрок может построить «туздык» (но только один за игру), собрав три камня в лунке. Уникальность Селуса в том, что камни, попавшие в лунку, можно захватывать (в том числе, «отбирая» их у противника). Если последний камень посева падает в wegue, он захватывается в «амбар» игрока, забирая с собой ещё один камень из ловушки.



Если захват выполняется из своей wegue, игрок получает ещё один ход, но есть одно исключение. Крайняя левая лунка, в нижнем ряду, называется «ayemi» («глаз»). Игрок не может захватывать камни из ayemi на своей стороне, а захватив камень из ayemi на стороне противника, всегда получает право на дополнительный ход (независимо от того, кем была построена wegue). Очевидно, что строить wegue в своём ayemi крайне нежелательно!

Из первоначального расклада, wegue могли бы быть созданы самыми первыми ходами. Чтобы этого не происходило, wegue запрещается создавать первым ходом каждому из игроков. Попав в лунку с тремя камнями (на первом ходу), игрок просто продолжает циклический посев дальше. В этой игре нет одновременного нулевого посева, как в Габате, но итоговый результат ничуть не хуже. Камни в лунках «перемешиваются» просто замечательно.

Также как Габата, Селус играется в несколько раундов, до полного отъёма камней, но здесь игрок может пропускать ход (только в том случае, если ходить ему нечем). Его противник, просто продолжает ходить по обычным правилам. Лишь когда оба игрока не могут выполнить ход, игра заканчивается. Игроки подсчитывают камни в своих «ловушках» и «амбарах» и тот, кто набрал больше, считается победителем.

Сюрприз от Axiom
Пропуск хода — особенно болезненная тема! Фактически, это такой специальный ход, который не изменяет на доске ничего и не связан с какой либо фигурой. В Axiom возможность пропуска хода описывается явно:

{move-priorities
	{move-priority} normal-type
	{move-priority} pass-type
move-priorities}

{moves p-moves
	{move} move-p	{move-type} normal-type
	{move} Pass	{move-type} pass-type
moves}

{pieces
	...
	{piece}		m
	{piece}		p1	{moves}	p-moves	1	{value}
	...
pieces}

Если ZRF сконфигурирован правильно (опция "pass turn" = forced), ход пропускается автоматически (при отсутствии возможности какого либо другого хода). Но не всё так просто. Допустим, у игрока есть wegue и, кроме них, нет никаких других фигур на его стороне. Это может показаться неожиданным, но вместо Pass, мы получаем следующее сообщение:


Дело в том, что Pass ход был связан с p-moves, а поскольку фигур с этим обработчиком у игрока нет, Axiom даже не пытается их «двигать»! Чтобы всё работало правильно, обработчик ходов необходимо назначить и ловушкам тоже (не важно, что он будет состоять только из Pass-хода). Другим способом могло бы стать создание фиктивного типа фигур с обработчиком drop ходов, аналогично тому, как сама Axiom обманывает ZoG:

  ; The following dummy piece is required in order to placate the Zillions engine.
  ; It appears as though Zillions must find at least one "moves" keyword somewhere
  ; in the zrf in order for it to be happy and thus allow "moves" to work correctly.
  (piece 
     (name Dummy)
     (dummy) (moves (from))
  )

Этот комментарий можно отливать из бронзы.

С ловушками в Селус вышло небольшое разночтение. Дмитрий Скирюк утверждает, что при захвате последнего камня, ловушка ликвидируется, но задачка, встречающаяся в ряде источников, намекает, что это не так. Я сделал оба варианта (и задачку). Габату можно найти в том же архиве.

К чему я это всё?


Манкалы — это весело! А их разработка при помощи Axiom — так и вовсе превращает жизнь в одно сплошное приключение.
Валентин @GlukKazan
карма
119,2
рейтинг 12,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (6)

  • 0
    Круть
    • 0
      Рад, что вам понравилось
  • +1
    Как всегда, увлекательная статья. И отдельное спасибо за фразу
    если бы не один фатальный недостаток ZRF (не тот, о котором вы подумали)
    • 0
      Спасибо, исправил опечатку
  • +1
    Калах же!
    Еще на старинных Агат-9 в школе играл, ну и на Nokia 3310, конечно!
    Почему про него ничего нет?
    • 0
      На самом деле, есть (по вторым спойлером). Если серьёзно, Калах — манкала очень неоднозначная (хотя и широко известная на территории бывшего СССР). По сути, это сильно упрощённый Чонгкак (с одиночным посевом вместо циклического и без нулевого посева). Есть мнение (Дмитрия Скирюка), что в процессе упрощения он сильно подрастерял в игровом балансе. Сам я Калах на Агатах и Векторах застал, но в те юные годы слабо разбирался в манкалах. После сильно в него тоже не играл. В любом случае, рекомендую ознакомится с первоисточниками (Дакон, на мой взгляд, очень интересен).

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