- PATTERNS: авианосец, длинная лодка, каноэ, MWSS, HWSS, Loafer, кролики, ружьё Симкина (22 → 30) - CAMPAIGN_LEVELS: ручные «Флотилия»/«Погоня»/«Кролики» после «Издалека» (100 → 103) - README: раздел «Интересные факты» и список ресурсов - tests: счётчики и проверки новых фигур/уровней синхронизированы
23 KiB
Life — территориальная борьба
Браузерная hot-seat игра-переосмысление Conway's Game of Life: двое игроков по очереди расставляют свои живые клетки, а дальше доска живёт по правилам Конвея — и чей цвет захватит поле, тот и победил. Один HTML-файл, без зависимостей: открой в браузере и играй.
Интересные факты
Наша игра — вариант классического автомата: у Конвея клетки одного цвета, бесконечное поле и «игра для нуля игроков», а у нас — территориальная борьба двух цветов, конечное поле, бюджет клеток и наследование цвета большинством. Вот несколько фактов о самой классике.
- Джон Хортон Конвей придумал игру в 1970 году как упрощение самовоспроизводящейся машины фон Неймана (1940-е). Публика сделала её знаменитой после колонки Мартина Гарднера в Scientific American (октябрь 1970).
- Это игра для нуля игроков: вся эволюция полностью задаётся начальной расстановкой. Автомат — B3/S23, окрестность Мура (8 соседей), состояния одновременны (тик).
- Конвей объявил приз $50 тому, кто найдёт пример неограниченного роста. В ноябре 1970 приз взяла команда MIT во главе с Биллом Госпером — так появилось ружьё Госпера (первое ружьё, 36 клеток, период 30).
- Игра тьюринг-полна: в 2002 году Пол Чапмен построил в ней универсальную регистровую машину (268 096 клеток). Всё, что вычислимо алгоритмически, вычислимо и в Life.
- Life омнипериодична: существуют осцилляторы любого периода. Последним, в июле 2023, был найден период 41.
- Алгоритм HashLife (Госпер, 1984) хранит подпаттерны в хеш-таблице и перескакивает тысячи поколений — им посчитано 6-октиллионное поколение машины Тьюринга Ренделла менее чем за 30 секунд.
- Garden of Eden — конфигурации без «родителя» — существуют по теореме Мура–Майхилла с самого рождения игры. «Проблема уникального отца» (1972) была решена лишь в 2022 (пример из 306 клеток).
- Конвей подбирал правила так, чтобы не было простого доказательства неограниченного роста, но такие растущие конфигурации всё же существовали, а простые «семена» долго и непредсказуемо развивались.
Ресурсы
- LifeWiki — главная энциклопедия игры:
https://conwaylife.com/wiki(может требовать обхода Cloudflare; страницы доступны черезhttps://web.archive.org). - Catagolue — перепись «естественно возникающих» паттернов, краудсорсинг-поиск:
https://catagolue.hatsya.com. - Life Lexicon (Stephen Silver) — словарь терминов:
https://conwaylife.com/ref/lexicon/lex.htm. - OEIS — числовые последовательности (стойкие фигуры
A019473, плотныеA055397и др.):https://oeis.org. - MathWorld — обзор с правилами и ссылками:
https://mathworld.wolfram.com/GameofLife.html. - Golly — эталонный симулятор с HashLife:
https://sourceforge.net/projects/golly/. - ibiblio — скан оригинальной статьи Гарднера 1970 года и коллекция паттернов:
https://www.ibiblio.org/lifepatterns/. - Rosetta Code — реализации Life на десятках языков:
https://rosettacode.org/wiki/Conway%27s_Game_of_Life.
Как играть
Игра на одном экране, игроки ходят по очереди, передавая устройство друг другу. На стартовом экране — краткое описание игры, выбор темы и две равноправные кнопки режимов: «Кампания» и «Игра на двоих» (а над ними выделенная «Продолжить партию», если есть отложенная). Нажав «Игра на двоих», вы попадаете на экран с настройками поля (размер, «замкнутая карта», бюджет) и справкой «Как играть»; партия стартует по кнопке «Начать». Сначала первый игрок расставляет свои клетки, затем устройство переходит второму — он расставляет вслепую, не видя расстановку соперника. Если первый игрок хочет что-то поправить, на экране передачи есть кнопка «Вернуться к игроку 1». После этого включается симуляция: живые клетки выживают при 2–3 живых соседях, а в пустой клетке рождается новая ровно при 3 соседях — и цвет новорождённой наследуется от большинства из своих соседей-родителей.
Каждый игрок может ставить клетки только в своей половине поля (первый — в левой, второй — в правой), а неактивная половина затемняется, чтобы было видно зону. На всю партию у каждого игрока есть бюджет клеток — счётчик остатка виден в HUD. Бюджет тратится на каждую новую поставленную клетку, ластик возвращает потраченное, а симуляция бюджет не расходует.
Когда поле перестало меняться — симуляция сама встаёт на паузу (и в HUD появляется метка «поле стабильно»), после чего каждый игрок может дорисовать клетки (уже видя всё поле): на паузе есть отдельные кнопки «Дорисовать красным» и «Дорисовать зелёным» (в любом порядке) и «Старт симуляции». Дорисовка доступна только на «застывшем» поле — это либо неподвижная структура, либо короткий цикл (например, мигалка). Если поле продолжает меняться (глайдеры, рост, хаос), дорисовки нет — такую партию можно только завершить вручную. Партия заканчивается при вымирании — как только у игрока не осталось ни одной клетки его цвета на доске (бюджет его уже не спасает), — тупиком по бюджету (поле стабильно, а отстающему игроку нечем ходить: его бюджет исчерпан, и ни поставить, ни стереть он не может; при равном счёте — когда бюджет кончился у обоих) либо ручным завершением кнопкой «Завершить партию» (с подтверждением, чтобы не завершить случайно). Победитель — у кого на доске больше живых клеток своего цвета.
Правила: окрестность Мура (8 соседей), классический автомат B3/S23. По умолчанию границы жёсткие (без заворота краёв); на экране «Игра на двоих» можно включить опцию «Замкнутая карта (torus)» — тогда соседи за краем берутся с противоположной стороны.
Кампания
В меню есть кнопка «Кампания» — это режим-испытание с отдельным экраном выбора уровня (справка «Как играть» — в сворачиваемом блоке на том же экране). На уровне заранее расставлены стабильные фигуры врага (зелёные клетки); вы играете красными и должны уничтожить все клетки врага (добиться нуля зелёных). Враг сам не ходит — поле живёт обычной детерминированной симуляцией Конвея, поэтому врага уничтожают, подводя его фигуры под смерть/перерождение по правилам B3/S23.
- Зона рисования на уровне — прямоугольник (может быть меньше поля или совпадать с ним); неактивная область затемняется, как и половины в обычной партии.
- Бюджет клеток — свой на каждый уровень, виден в HUD; при нуле остатка метка краснеет.
- Врага нельзя трогать напрямую: краска и штамп не перезаписывают зелёные клетки (и не тратят за них бюджет), ластик их не стирает и бюджет не возвращает.
- Вымирание игрока — не проигрыш: даже если красных клеток не осталось, можно продолжать, пока есть бюджет.
- Победа — на доске не осталось клеток врага. Поражение — бюджет исчерпан, а враг ещё жив (фиксируется, когда поле стабилизировалось и симуляция сама встала на паузу).
- HUD показывает «Уровень N/T» и остаток бюджета; обычный счёт скрыт.
- Прогресс (сколько уровней открыто) сохраняется, победа открывает следующий. Всего 103 уровня: ручные («Разминка» — блок, «Каравай», «Рой» — много фигур, «Издалека» — враг вне зоны игрока, а сразу за ним showcase-уровни «Флотилия»/«Погоня»/«Кролики» с новыми фигурами), остальные 96 расставлены генератором
tools/gen-campaign-levels.mjs(детерминированно, фиксированный seed) и вшиты вindex.htmlстатически. Размер поля у сгенерированных уровней постепенно растёт до 300×300; у ручных вставок (в т.ч. «Издалека» и showcase) размер свой. Зоны рисования разнообразны (половина, центр, углы, узкие полосы, произвольный прямоугольник); зона на всё поле есть только у ручных «Разминки» и «Роя» — у сгенерированных её нет. Список уровней прокручивается. Решаемость уровней намеренно не проверяется: среди них есть заведомо почти непроходимые (например с ружьём Госпера) — это задумка. - Когда поле уровня стабилизировалось, игра сама открывает фазу дорисовки — жать «Дорисовать» не нужно: дорисуйте свои клетки и нажмите «Готов» — симуляция запустится сразу (цикл «нарисовал → побежало»). Кнопка «Заново» в панели действий перезапускает уровень в любой момент (с подтверждением).
- Уровень можно отложить в меню (кнопка «В меню»/⚙️ посреди уровня) и вернуться к нему кнопкой «Продолжить партию»; из финала — «Следующий уровень», «К уровням» или «Заново».
- Настройки уровня (размер поля, бюджет) действуют только внутри уровня и не меняют ваши настройки из меню: обычная партия после кампании стартует с прежним размером и бюджетом.
Управление
- Инструменты: карандаш 1×1, кисть 3×3, ластик 1×1, ластик 4×4. Правая кнопка мыши — ластик: удерживайте её, чтобы стирать, не переключая инструмент (если активен ластик, ПКМ сохраняет его размер, иначе стирает 1×1).
- Готовые паттерны (штампы): дропдаун «Паттерн» в тулбаре, сгруппированный по категориям — Стойкие (блок, улей, ванна, лодка, кораблик, каравай, пожиратель, пруд, авианосец, длинная лодка, каноэ), Осцилляторы (мигалка, жаба, маяк, часы, пульсар, пентадекатлон), Корабли (глайдер, LWSS, MWSS, HWSS, Loafer), Долгожители (R-пентамино, жёлудь, Diehard, громовая птица, кролики) и Ружья (ружьё Госпера, ружьё Симкина). Выберите фигуру и кликните: она встанет целиком, левый верхний угол — в точке клика. Клетки вне вашей половины не ставятся (в превью они подсвечены серым), бюджет тратится только за поставленные. Одно нажатие — одна постановка (перетаскивание фигуру не повторяет); ПКМ по-прежнему стирает. Поворот фигуры на 90° — кнопкой «↻» в тулбаре (видна при выбранном паттерне) или колесом мыши над доской. Выбор паттерна и его поворот не сохраняются между сессиями.
- Режим «постановка по отпусканию» (для сенсорных экранов): кнопка «👆 тап» в тулбаре. Когда режим включён, нажатие/касание только подсвечивает будущее место, а клетка (или фигура) ставится в момент отпускания — палец не закрывает точку постановки, а перетаскивание не рисует линию. Ластик и ПКМ работают так же — по отпусканию. Режим не сохраняется между сессиями и не сбрасывается при новой партии.
- Поле: 40 / 60 / 80 / 100 / 120 / 150 / 200 / 250 / 300 клеток в стороне (по умолчанию 60×60) плюс прямоугольные 60×100 и 100×60; размер выбирается дропдауном на экране «Игра на двоих»; правила партии открываются там же по кнопке «Как играть».
- Бюджет клеток на партию (по умолчанию 100): комбобокс на экране «Игра на двоих» — можно выбрать пресет из списка (100/250/500) или ввести любое своё число.
- «Замкнутая карта (torus)» — опция на экране «Игра на двоих» (по умолчанию выключена, границы жёсткие).
- Тема оформления — селект в стартовом меню: «Тёмная» (по умолчанию) или «Светлая». Выбор сохраняется и применяется после перезагрузки.
- Зоны рисования: первый игрок ставит клетки только в левой половине, второй — только в правой.
- Скорость симуляции задаётся константой
STEPS_PER_SEC(~8 шагов/сек) в кодеindex.html. Во время симуляции в панели действий есть ряд из четырёх кнопок 1× / 2× / 4× / 8× — клик выбирает множитель скорости (выбранная кнопка подсвечена); множитель не сохраняется и сбрасывается при новой партии. - Клавиатура: пробел ставит и снимает паузу во время симуляции (как у медиаплеера) — то же, что кнопки «Пауза»/«Старт симуляции». В меню, фазах расстановки/дорисовки, при передаче устройства, в финале и при открытом диалоге подтверждения пробел ничего не делает; в поле ввода (бюджет) работает как обычный пробел.
- «Сброс» сбрасывает только текущий ход — возвращает поле и бюджет к началу фазы рисования.
Сохранение и резюм партии
Игра сама сохраняет прогресс в localStorage браузера (ключ life-save-v1) — без сервера и аккаунтов. Сохраняются:
- настройки: размер поля, активный инструмент, скорость симуляции, опция «Замкнутая карта», тема оформления, бюджет клеток;
- текущая партия: состояние (чей ход / симуляция / пауза / передача устройства), поле целиком и счёт;
- кампания: прогресс (сколько уровней открыто) и незавершённый уровень кампании (с полем врага и зоной рисования) — он резюмится так же, как обычная партия.
Поэтому после перезагрузки страницы незавершённая партия продолжается с того же места (включая фазу расстановки и идущую симуляцию). Если партия завершена или сейва нет — игра открывается в меню. Если сохранённые данные битые или устаревшего формата, игра просто стартует в меню, не падая. Кнопка «В меню» (и ⚙️) не теряет партию: она откладывает её, и в меню появляется кнопка «Продолжить партию» для возврата. Кнопка «Игра на двоих» (а также «Реванш») при наличии незавершённой партии сначала спрашивает подтверждение, чтобы случайно её не потерять.
⚠️
localStorageпривязан к origin, поэтому сейв/резюм не переносятся междуfile://иhttp://localhost:8000— для проверки резюма используйте один и тот же способ открытия.
Запуск
Просто открой index.html в браузере (десктоп или телефон) — игра работает с file://. Для локальной разработки:
python3 -m http.server 8000
# → http://localhost:8000
Тесты
Сначала проверка синтаксиса JS, встроенного в index.html:
node tools/check.mjs
Затем headless-суита на puppeteer-core в Chromium (нужен установленный Chromium; путь при необходимости правится переменной CHROMIUM):
cd tests
npm install
npm test
Ждать все PASS и exit 0. Суита также включает проверки персистентности/резюма, миграции сейва, resize и проводки DOM-кнопок.
Отдельно — паритет с прототипом (harness в tools/old-ref/, опционально): сборка g++ и дифтест, подробности в tools/old-ref/README.md.
Структура
index.html # вся игра: HTML + CSS + один <script>
tests/ # headless-тесты (puppeteer-core): test.js, parity-fixture.json, package.json
tools/check.mjs # проверка синтаксиса JS из index.html
tools/gen-campaign-levels.mjs # генератор 96 уровней кампании (seeded PRNG, без Math.random)
tools/old-ref/ # harness паритета с прототипом (C++ + генераторы; см. README там)
AGENTS.md # правила разработки и тестирования
README.md # этот файл
old/ # референс старого C++/Qt4 прототипа (не часть продукта, не трогать)