← На главную

Nix превращает атрибутный путь в нажатия кнопок Super Mario Bros. 3

07.08.2026 20:16 · hackernews

Nix — ленивый язык: вычисляются только те атрибуты, до которых реально дошёл. Поэтому pkgs.hello работает, даже если рядом лежит throw "never forced", а pkgs внутри Nixpkgs содержит сам себя — pkgs.pkgs.pkgs.hello даёт тот же store path. Раз ленивость позволяет бесконечную рекурсию, атрибутный путь можно представить как прогулку по лениво генерируемому дереву. Идея: сделать этот путь последовательностью нажатий кнопок в Super Mario Bros. 3.

Каждый узел дерева — кадр игры, каждый ребёнок — нажатие кнопки, которое даёт новый кадр. nix build '.#level1.rightb.rightb.rightab.rightb' собирает PNG-картинку: кадр, который вы бы увидели на реальном железе после такой последовательности нажатий. Префикс .#level1 — заранее записанные нажатия до начала уровня 1-1. Если добавить .play, получится запись всего прохождения.

Код лежит в fzakaria/nes-nix. ROM — flake input, можно подставить любую игру. Каждое нажатие — отдельная деривация. Она берёт savestate предыдущего нажатия и никогда не эмулирует предков заново. В итоге Nix store превращается в историю сохранений эмулятора: ответвление от середины сотни нажатий стоит одну деривацию, так же как добавление в конец. А nix-store --query --tree показывает, какие кнопки привели к конкретному кадру.

.play почти ничего не делает: каждый кадр уже лежит в store, и файл записи — просто симлинки для ffmpeg.

У такого подхода есть границы. Обычный nix eval падает на ~2400 нажатий: max-call-depth по умолчанию 10 000, а каждое нажатие стоит четырёх вложенных вызовов. Если поднять лимит до 10 000 000, получается 20 000 нажатий за ~14 секунд, примерно 0.7 мс на нажатие. Дальше упираешься в ядро Linux: атрибутный путь — это один элемент argv, MAX_ARG_STRLEN ограничивает аргумент 131 072 байтами, а каждое right. занимает шесть байт, итого максимум 21 845 нажатий. Обходной путь — читать последовательность из файла через --impure --expr и sequenceFile; получается байт-в-байт та же деривация.

Сборка тоже линейна: примерно 1.27 секунды на нажатие с включёнными substituters и 0.28 без них. Проверка кэша обходится дороже самой эмуляции.

Вывод: атрибутный путь в Nix — это не имя в каталоге, а программа. Nixpkgs использует этот механизм для описания софта, но ничто не мешает использовать его для воспроизводимого «менеджера пакетов», играющего в Mario.

Читать оригинал →