Переводчик Z-Machine в Go

Перевод статьи Z-Machine interpreter in Go, автор Maciej Sinilo

Недавно у меня была вдохновляющая дискуссия с другими программистами. Мы говорили о интересных сторонних проектах и программах, которые позволили бы быстро «опробовать» новые задания по программированию. Один из проектов - интерпретатор Z-машины, способный играть в Zork I. Z-machine - это виртуальная машина, разработанная Джоэлом Березом и Марком Бланком, используемая для многочисленных игр Infocom, в частности серии Zork. Честно говоря, мне не пришлось играть в «Зорк», когда он был большой (я играл в старые сьерра-приключения, где нужно было вводить команды, хотя одна из причин, по которым я начал - изучение английского. Это был Police Quest I. Мне понадобилось более 3 месяцев, чтобы закончить эту игру).

Несколько недель спустя у меня был целый уикенд, и я решил попробовать. Как оказалось - на самом деле было очень весело. Я также больше зауважал ребят из Infocom, там есть некоторые действительно творческие идеи, особенно учитывая ограничения диска / памяти (файл zork1.dat, который я нашел, был ~ 90k). Сначала я хотел сделать это в Rust (язык, на котором я хотел поэкспериментировать), но в итоге решил играть в безопасно, ограничил количество неизвестных и отправился с Go (мой второй раз). Это на самом деле оказалось хорошим выбором, базовая реализация - 1500 строк Go и поставляется с некоторыми хорошими функциями бесплатно (например, циклическое использование прошлых команд со стрелкой вверх). Пошел довольно гладко, споткнулся несколько раз, в основном из-за того, что я пропустил некоторые небольшие детали (например, call 0 == return false или некоторые ошибки «за-1» при индексировании свойств). Тот, который занимал меня, вероятно, больше всего времени, был тонкой ошибкой в ​​рутине «change parent», которая заставила бы игру разделиться после того, как я что-то подхватил. К счастью, я нашел простой пример для воспроизведения, если бы я не взял бутылку с водой, я мог бы пошевелить ковровым покрытием, иначе он пожаловался бы, что ковер не будет там. Я не хотел тратить время на создание полномасштабного отладчика, ведь это был проект для выходных), поэтому потратил некоторое время на сравнение инструкций для «хороших» и «плохих» запусков, пытаясь увидеть, где они дрейфуют друг от друга. В конце концов было закодировано приложение быстрого сравнения (сравнение его в блокноте было слишком медленным) и выяснилось, что происходит, после этого было довольно плавно.

Хорошо, что очень легко начать с базовой структуры, которая ничего не делает, только продвигает IP соответственно, а затем продолжает заполнять пробелы, добавляя реализацию для требуемых кодов операций. Я просто начал с NOP повсюду (с базовым вызовом реализации "паники" («NOP»)), а затем продолжалась, пока, наконец, не увидели сообщение «вы стоите в открытом поле к западу от белого дома». Хорошо, что достижение этой цели требует реализации большинства базовых функций, в основном это добавление опкодов.

Большие части, которые все еще отсутствуют, - это сохранение / восстановление, кроме того, что он должен быть достаточно полным (это только версия 3).

Хотите попробовать - вот полезные ссылки

  1. Документация: Z-Machine Standards Document, Learning ZIL (оригинальный документ Infocom, PDF), описание ZIP (документ Infocom, PDF)
  2. Ztools (набор инструментов Infocom) - набор инструментов Z-machine. Очень полезно для обеспечения того, чтобы ваш собственный интерпретатор работал так, как следует. Я просто разобрал Zork I с TxD и, выведя IP из своей собственной программы, смог быстро проверить, какая инструкция не сработала (или что там должно быть).
  3. Мой пример реализации в Go. Как уже упоминалось, это не полный проект на выходные в течение 100% и может содержать ошибки.