Игра в бисер на Python
Давай сыграем в игру?
Давай сыграем в игру?

Что вообще такое «игра в бисер»?

В бытовом языке этот фразеологизм означает нечто заумное, переусложненное и бесполезное. Выражение восходит к роману писателя Германа Гессе, за который тот на минуточку получил Нобелевскую премию. В романе изображен вымышленный мир, устроенный таким образом, что посреди обычных государств в мире основана специальная страна интеллектуалов — Касталия. Живущие в ней люди могут, не задумываясь о куске хлеба, посвятить себя ответам на лишенные практической пользы гуманитарные вопросы вроде трактовки какой-нибудь строки древнего стихотворения. Все остальные государства терпят существование Касталии и регулярно скидываются на ее содержание (ну чисто как ООН), а сама Касталия немного воспитывает учителей языков, литературы, музыки и математики для внешнего мира, но по большому счету никому ничего не должна. Предельным выражением оторванности от практической жизни служит как раз та самая игра в бисер — самая авторитетная внутри Касталии, но мало кому понятная за ее пределами деятельность.

Привыкшим к бодрому экшону роман будет читать трудновато: там мало что происходит. Герой Йозеф Кнехт учится в разных заведениях, ходит туда и сюда, разговаривает разговоры, и сначала добивается больших успехов, продвигаясь наверх внутренней иерархии Касталии, становится самым главным по игре в бисер (а это значит — самым главным вообще), но потом разочаровывается во всем и покидает страну, сочтя, что лучше жить рядом с простыми людьми. Мораль, в общем, простая, но сформулированная немецким писателем в разгар Второй мировой войны (1943 год на дворе), она становится социально значимым высказыванием: интеллектуалам, несмотря на соблазн отгородиться от мира и погрузиться в свои манускрипты, не следует терять контакта с происходящим вокруг.

Правда, беспомощный в обычной жизни Кнехт (спойлер!) довольно быстро погибает за пределами Касталии, но это уже совсем другая история.

Роман дожил до наших дней и еще не сдан в глубокий архив не благодаря заложенным в сюжете простым истинам и не благодаря занудным монологам персонажей Гессе. Жемчужина произведения — как раз идея той самой игры. Как она выглядит и в чем заключается, автор нигде не пишет. И в этом, по всей видимости, одна из причин ее привлекательности. Опиши Гессе все в подробностях, игра тут же лишилась своего ореола таинственности и креативного потенциала. А сейчас читатель сам должен придумать, что там к чему, и это весело.

Как все это должно выглядеть?

Я вижу игру в бисер как манипуляцию знаками (наличие собственно «бисера» в игре всего лишь метафора). Знаки — это такие объекты, у которых есть материальная репрезентация («означающее») и стоящие за ней смыслы («означаемое»). Означающее для буквы «А» — это то, как эта буква выглядит, а означаемое локализуется в пределах какой-нибудь конкретной семиотической системы, например, графической системы русского языка, где есть соответствующий этой букве звук.

Сам процесс игры скорее является игрой в том же значении, что и «игра на музыкальном инструменте», то есть это исполнение заранее составленного произведения, а не игра в смысле соперничества каких-то игроков. Хотя для Гессе первично то значение «игры», которое связано с деятельностью, не приносящей пользы, где процесс важнее результата.

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

Интерес игры, по всей видимости, в сочетаниях всех этих элементов и стоящей за ними традиции. Скажем, соединение какой-нибудь теоремы с мелодией сонаты ХѴІІ века должно восприниматься как остроумное, а пентатонический ряд с цитатой из Вергилия (пример условный) как нечто скучное и банальное. Некоторой аналогией могут служить правила рифмовки в русской поэзии: глагольная рифма типа «злиться — бриться» скучная, а «товарищи — товар ищи» звучит свежо, потому что каламбур. Кто сказал, что надо воспринимать именно так? Никто, просто сложилась такая традиция, и если ты с этой традицией не знаком, то разницы ты не видишь. Вот почему не понимали игру в бисер люди за пределами Касталии.

В процессе игры все эти сочетания знаков видоизменяются, преобразуются, перетасовываются, образуя новые неожиданные сочетания, а сами преобразования тоже подчиняются каким-то правилам, потому что нет ничего скучнее игры без правил.

Как это переложить в код?

Нужно всего лишь закодировать все культурное наследие человечества и придумать правила преобразования одного состояния разложенного на игровой доске «бисера» в другое. Есть ощущение, что это все-таки ту мач. Начнем с малого.

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

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

У китайцев эпохи Тан есть стихи, в которых ровно 8 строк, а иероглифов в строке обязательно 7. В современных изданиях в конце строки ставится знак препинания (,или 。), в результате получаем матрицу 8х8 знаков, что как раз соответствует игровому полю шахмат. Плюс иероглифы выглядят вполне квадратно, что усиливает ассоциации с клетками на доске. С уже существующими танскими стихотворениями и будем работать.

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

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

Пилим пакет

Берем руководство по созданию питоновских пакетов, отбираем из корпуса танских текстов такие, которые подходят нам по формату 8х8 (8 полноценных иероглифов в 8 строках, увы, не бывает), прикручиваем умение читать формат PGN, в котором записываются листинги шахматных партий — и вот, пакет готов. Роман Гессе называется по-английски «The Glass Bead Game», а у нас пока ограниченный по функциональности прототип, что мы и отразим в названии (тоже каламбурном): «Chess Bead Game».

Пакет умеет подгружать конкретное стихотворение (или случайное, если пользователь не знает, какое стихотворение ему нужно), знает, кто его написал и как оно называется:

import chess_bead as cb
g = cb.Game(poem_num=2000)

Пакет умеет подгружать шахматную партию в формате PGN:

import chess_bead as cb
g = cb.Game(pgn_file='/path/to/file.pgn', poem_num=2000)

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

Далее пакет может запустить игру и хранить все состояния «бисера», то есть положения иероглифов после каждого хода.

Вот стихотворение великого поэта Ду Фу до игры:

g = cb.Game(poem_num=1765)
verses = g.start_game()
verses[0].lines
initial_state =[]
for line in verses[0].lines:
    initial_state.append(''.join(line))
initial_text = '\n'.join(initial_state)
print(initial_text)

風急天高猿嘯哀,
渚清沙白鳥飛回。
無邊落木蕭蕭下,
不盡長江袞袞來。
萬里悲秋常作客,
百年多病獨登臺。
艱難苦恨繁霜鬢,
潦倒新停濁酒杯。

В переводе Наталии Азаровой:

Взбираясь наверх

ветром нервным взвивается к небу

обезьяний плач по умершим

у отмели белой брызги вращеньем

кругами птиц над водой

так беспрестанно теряют деревья

шуршанье шуршание листьев

так бесконечно катит янцзы

теченье течение встречи

в тысяче вёрст от дома чужой

печальной осенью долгой

годы прожиты болен и одинок

карабкаюсь всё же на башню

тяжко и трудно от горести нелюбви

на висках расцветает иней

странно гляжусь незадачливым старцем

но больше не пью вина

Другой перевод

Стремителен ветер, и небо высо́ко.

В лесу обезьяны вопят.

Над чистой, осенней водою потока

Осенние птицы летят.

Осенние листья кружат, опадая,

Багряны они и легки,

И тянутся вдаль от родимого края

Просторы Великой реки.

(перевод А. Гитовича)

Теперь перемешаем эти прекрасные стихи, руководствуясь классической партией из матча Спасский-Фишер 1972 года.

g = cb.Game(pgn_file='5152.pgn', chess_game=3, poem_num=1765)
verses = g.start_game()

В конце получилось так:

g.result # А чем закончилась партия?
'1/2-1/2' # ничья

final_state =[]
for line in verses[89].lines:
    final_state.append(''.join(line))
final_text = '\n'.join(final_state)
print(final_text)

倒落長潦蕭,霜盡
無來悲蕭停酒木。
不邊杯猿鳥新下,
渚哀苦江臺飛回袞
艱里繁沙袞白天。
萬年難濁急清嘯,
百高客秋常作鬢。
病多獨恨登,風。

Что все это значит? Вот с этим не ко мне. Китайского я не знаю, в Касталии не учился. Могу только воспользоваться онлайн-переводчиком. Он отлично берет на себя функцию оракула:

Мороз закончился

Никто не приходит оплакивать остановку винного дерева.

Чаши обезьян и птиц — новые.

И печальная платформа реки летит обратно в железную

Железо дня на твердом песке.

Миллиона лет недостаточно, чтобы создать свистящий звук.

У ста высоких посетителей осенью часто появляются бакенбарды.

Я болен и ненавижу ветер.

Честно говоря, я не удивлен, что никто не пришел оплакать остановку винного дерева, и про бакенбарды осенью тоже верю. Иными словами, я бы считал, что все сказанное в стихотворении — правда.

Но на буковки без визуализации смотреть скучновато. Прикрутим еще возможность создания картинок и анимации игры. Для этого нам нужен шрифт. Лицензия предполагает, что поставлять его можно только в составе программного обеспечения, что как раз наш случай. Получается так:

v = cb.Viz(verses, g.author, g.title)
v.gif()

Тут поле, на которое ходит фигура, обозначается красным, а поле, с которого она ходит, серым.

Теперь добавим документацию и пакет готов.

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