Гомоку против сильного движка, на тетрадном листе или на школьной доске. Ходы — крестики и нолики в клетках, а не камни на пересечениях.
Весь расчёт идёт в браузере. Сервер отдаёт только статические файлы: ни ходы, ни партии никуда не уходят.
| Движок | Rapfi 0.43.01, WebAssembly, один поток + SIMD128 |
| Оценка | NNUE mix9svq, сеть freestyle для всех размеров поля |
| Правила | freestyle: пять и больше в ряд, запрещённых ходов нет |
| Поле | 13×13, 15×15, 19×19 |
| Вес | ~9,6 МБ пакета весов + 1,1 МБ .wasm, качается один раз |
| Языки | русский, English, қазақша, Deutsch, español, français, Türkçe, فارسی (RTL), 中文 |
| PWA | ставится на домашний экран, играет полностью офлайн |
На обычном ноутбуке движок успевает просчитать 18–25 полуходов за пару секунд
в одном потоке. Многопоточная сборка требует заголовков COOP/COEP и
SharedArrayBuffer, которых статический хостинг не даёт — да и одного ядра
здесь с запасом.
docs/
index.html интерфейс
about.html страница «о движке»
assets/app.js отрисовка поля, правила, связка с движком
assets/i18n.js словари девяти языков и переключатель
assets/style.css две темы: тетрадь и доска
assets/pwa.js регистрация сервис-воркера
sw.js офлайн-кэш: оболочка, движок и шрифты порознь
manifest.webmanifest
icon-*.png иконки приложения, рисуются кодом
engine/worker.js обёртка над wasm: движок считает в воркере
engine/rapfi-*.js загрузчики emscripten (SIMD и запасной без SIMD)
engine/rapfi-*.wasm бинарники Rapfi
engine/rapfi.data веса и конфиг
tools/repack-engine.js пересборка пакета весов с 40 МБ до 9,6 МБ
tools/make-icons.js генерация иконок PWA
serve.js локальный сервер для разработки
Язык определяется по navigator.languages, запоминается в localStorage и
переключается в шапке. Разметка помечена атрибутами data-i18n; числа
форматирует Intl.NumberFormat с компактной записью, поэтому «53,4 тыс.»,
«53.4K» и «5.3万» получаются сами собой.
Персидский идёт справа налево: dir="rtl" переворачивает раскладку логическими
свойствами CSS, а поля тетрадного листа с красной чертой переезжают на правый
край. Caveat не знает арабицу, поэтому для фарси подгружается Vazirmatn — только
при выборе этого языка, остальные за него не платят.
Сайт — прогрессивное веб-приложение: ставится на домашний экран и после первого запуска работает без сети совсем. Это естественно ложится на архитектуру — считает движок и так на устройстве, сервер нужен ровно один раз.
Кэша в sw.js три, и это принципиально:
| Кэш | Что в нём | Когда наполняется |
|---|---|---|
xo5-shell |
HTML, CSS, JS, иконки, манифест — около 130 КБ | при установке воркера |
xo5-engine |
rapfi.data, .wasm, загрузчик — 11 МБ |
лениво, когда страница сама их запросит |
xo5-fonts |
Caveat и Vazirmatn с Google Fonts | при первом обращении |
Движок нельзя класть в предзагрузку: воркер начал бы качать те же 11 МБ параллельно со страницей, и первый визит стоил бы 22 МБ вместо 11.
Стратегии: переходы по страницам — сеть вперёд с откатом в кэш, свои файлы —
отдаём из кэша и молча освежаем, файлы движка и шрифты — только кэш, они
неизменяемы. Поэтому правки интерфейса доезжают до пользователя со второй
загрузки сами; принудительно сбросить кэш можно, подняв SHELL_CACHE в
sw.js. Версию ENGINE_CACHE трогать нужно, только если пересобран пакет
весов.
Иконки рисует tools/make-icons.js: PNG кодируется вручную через zlib,
сглаживание — суперсэмплингом. Так палитра гарантированно совпадает с тёмной
темой сайта, а внешних зависимостей у проекта по-прежнему нет.
node tools/make-icons.jsДвижок общается по протоколу Piskvork
с расширениями Yixin-Board. Перед каждым ходом ему отправляется полная позиция
командой BOARD … DONE, поэтому отмена ходов и смена настроек не могут
рассинхронизировать состояние.
Поиск в однопоточной сборке блокирует свой поток целиком, поэтому движок живёт
в Web Worker — интерфейс остаётся отзывчивым, а промежуточные INFO долетают
до панели анализа прямо во время счёта.
node serve.jsЗатем открыть http://localhost:5173.
Оригинальный веб-пакет Rapfi весит ~40 МБ: в нём четыре NNUE-сети — freestyle, standard и две рэндзю. Здесь нужна только freestyle:
node tools/repack-engine.jsСкрипт качает файлы с gomocalc.com, режет rapfi.data
по таблице смещений, оставляет одну сеть, правит config.toml и переписывает
таблицу в загрузчиках. .wasm не трогается вообще.
Движок Rapfi — GPL-3.0, автор dhbloo и участники проекта. Исходники: https://github.com/dhbloo/rapfi.
Файлы в docs/engine/ — это сборка Rapfi для WebAssembly, взятая из веб-версии
Gomocalc того же автора. .wasm распространяются без
изменений; изменены только состав пакета весов и config.toml, ровно так, как
это делает tools/repack-engine.js. Условия GPL-3.0 распространяются на эти
файлы и на любую их дальнейшую передачу.
Интерфейс (docs/index.html, docs/about.html, docs/assets/*,
docs/engine/worker.js, tools/*, serve.js) — MIT.