О проекте
Команда: Publish or Perish
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Браузерный симулятор управления Астаной с двумя интерфейсами, игровым и классическим. Основной режим — пять решений при бюджете 100, режим испытания — восемь кварталов со случайными событиями. Есть сравнение сценариев по кодам и ИИ-разбор выбора.
Как устроено
В score.js лежат данные, веса, ограничения и синергии. Эффект меры = полный эффект × (8 − лаг)/8; балл района = сумма(показатель × вес); Score = 0,7 × средний балл по населению + 0,3 × минимальный балл района − N (число показателей ниже 40). Рекомендации строятся перебором допустимых одиночных замен с пересчётом всего набора, показывается до трёх улучшений. Сервер повторно проверяет коды сценариев и отправляет рассчитанные показатели в OpenAI Responses API (gpt-4.1-mini) за текстовым объяснением. Режим испытания (challenge.js): бюджет 40 плюс 15 за квартал, рука из карт, события между кварталами, турнирные seed.
Ключевые решения
- weighted scoring with lags
- synergies
- single-swap search for recommendations
- scenario codes
- seeded tournament events
- SVG maps
Особенности
Есть режим испытания с колодой карт, событиями между кварталами и воспроизводимыми турнирными seed. Коды сценариев позволяют сравнивать решения разных участников. Рекомендации даёт перебор одиночных замен без ИИ, результаты экспортируются как автономная HTML-презентация.
Стек
JavaScript ES modules · HTML · CSS · Deno · Node.js · Docker · OpenAI Responses API · SVG
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-24299c5d-publish-or-perish.
README
README.mdАким на 5 часов
Интерактивный симулятор управления городом · команда Publish or Perish
Как распределить ограниченный бюджет между транспортом, экологией, социальной сферой, безопасностью и городскими сервисами? «Аким на 5 часов» позволяет собрать набор городских мероприятий, увидеть последствия для пяти районов Астаны и понять, за счёт чего меняется итоговый балл.
Проект предназначен для участников и жюри хакатона, а также для пользователей, которые хотят исследовать компромиссы городского управления в игровой модели. Он делает правила, ограничения и результаты выбора наглядными. Это симулятор на синтетических данных, а не система принятия реальных муниципальных решений.
Содержание
- Что реализовано
- Как работает решение
- Технологии
- Архитектура
- Установка и запуск
- Как проверить решение
- Данные и интеграции
- Ограничения
- Развёрнутая версия
Что реализовано
Интерфейс и навигация
- Два оформления: игровое (
index.html) и классическое (classic.html). Оба поддерживают основной режим и испытание. - Переключатель «Интерфейс» переносит прогресс в пределах текущей вкладки через
sessionStorage; он также восстанавливается при перезагрузке этой вкладки, если браузер разрешает хранение. - Пошаговое обучение и кнопка «Как играть ?». Отметка о просмотре обучения хранится в
localStorage. - Игровая карта использует локальный снимок архивных географических границ пяти районов и рек. Классическое оформление сохраняет схематическую карту.
- Иллюстрации мероприятий, отдельные SVG-значки проектов и компактные элементы управления.
Основной режим: пять решений
- Каталог из 14 мероприятий для пяти районов: Есиль, Алматы, Сарыарка, Байконур и Нура.
- Выбор ровно пяти мер при бюджете 100 единиц, не более двух мер одного направления.
- Предпросмотр результата добавления, отмена выбора с пересчётом и прогноз балла после удаления.
- Проверка несовместимостей, повторов, бюджета и допустимости района. Недоступные карты блокируются; после отмены доступность пересчитывается.
- Подсказки о потенциальных и действующих синергиях.
- Итоги в виде карусели с кнопками, точками навигации и свайпами.
- Вкладка «Показатели»: значения до и после, пять направлений и общий обзор для каждого района и города с учётом населения.
- Вкладка «Сравнение»: один или несколько введённых вручную кодов, до десяти. Баллы, бюджет, критические показатели и различия по районам рассчитываются без ИИ.
- Разбор выбора на русском языке через OpenAI и рекомендации по допустимым одиночным заменам.
- Вкладка «Презентация»: четыре слайда с иллюстрациями и диаграммами. Скачивание автономного HTML-файла с возможностью печати в PDF.
Режим испытания: восемь кварталов
- Стартовый бюджет 40 единиц, пополнение на 15 при переходах в кварталы 2–8.
- Базовая рука из пяти карт и два разных события между кварталами: изменения бюджета, цен или размера руки.
- Прогноз учитывает квартал покупки и задержку эффекта. Покупки окончательны; можно завершить квартал без покупки.
- Код турнира задаёт воспроизводимые события и приоритеты колоды. При разных решениях доступные карты могут отличаться.
- Текущие показатели, прогноз на финал и итоговый экран.
Правила испытания и контракт модуля описаны в CHALLENGE.md. Ограничения основного режима на пять решений и две меры направления в испытании не применяются.
Как работает решение
- Пользователь выбирает направление, мероприятие и район. Городские меры действуют сразу во всех районах.
- Модуль расчёта проверяет ограничения и показывает прогноз. Пользователь добавляет меру или пересматривает выбор.
- После подтверждения пяти допустимых решений сайт показывает итоговый балл, изменения показателей и код сценария.
- Код можно передать другому участнику или вставить чужие коды во вкладку сравнения.
- Сервер повторно проверяет коды и рассчитывает результаты. При настроенном ключе он передаёт в OpenAI рассчитанные показатели, формулы и варианты замен для текстового объяснения.
- Пользователь изучает рекомендации и сохраняет презентацию своего сценария.
Как считается балл
В основном режиме горизонт составляет восемь кварталов:
Эффект меры = полный эффект × (8 − лаг) / 8
Балл района = сумма(показатель × вес)
Средний балл = сумма(балл района × доля населения)
Score = 0,7 × средний балл + 0,3 × минимальный балл района − N
N — число показателей ниже 40, подсчитанное по всем районам. После применения эффектов и синергий показатели ограничиваются диапазоном 0–100. Неизрасходованный бюджет не даёт бонуса. Веса, исходные данные и правила находятся в score.js.
Рекомендации перебирают допустимые замены одной из пяти мер, включая перенос в другой район, и пересчитывают весь набор. Показываются до трёх улучшений. Каждое относится к исходному сценарию: их приросты нельзя складывать. Итоговый балл определяет код, а ИИ объясняет рассчитанные результаты.
Технологии
| Часть | Используется |
|---|---|
| Интерфейс | HTML, CSS, обычный JavaScript, ES-модули, DOM API |
| Визуализация | SVG-карты и значки проектов, CSS-диаграммы, локальные PNG-иллюстрации |
| Расчёт и состояние | Собственные JavaScript-модули без внешних библиотек |
| Сервер | Deno или Node.js 22+ для локального запуска; общие Request, Response и fetch |
| ИИ | OpenAI Responses API; модель по умолчанию gpt-4.1-mini, настраивается через OPENAI_MODEL |
| Развёртывание | Deno или Docker; в Dockerfile закреплён образ denoland/deno:2.9.7 |
| Проверки | Браузерные проверки, скрипты Deno; тест испытания использует совместимый модуль node:assert/strict |
React, Vue, сборщик и установка npm-зависимостей не требуются. Для приложения достаточно Deno либо Node.js 22+. Скрипт пересборки географической карты использует Node.js. База данных в текущей версии не используется.
Архитектура
flowchart LR
UI[Интерфейс основного режима] --> Score[score.js: расчёт и ограничения]
UI --> Compare[comparison.js: сравнение кодов]
UI --> Report[scenario-report.js: поиск замен]
Compare --> Score
Report --> Score
UI --> Client[analysis.js]
Client --> API[POST /api/analyze]
API --> Score
API --> Report
API --> OpenAI[OpenAI Responses API]
Challenge[Интерфейс испытания] --> Engine[challenge.js]
Engine --> Score
| Компоненты | Назначение |
|---|---|
index.html, assets/game.js, assets/results.js | Игровое оформление, выбор мер, вкладки результатов, графики и презентация |
classic.html, classic-challenge.html, assets/classic-*.js | Классическое оформление обоих режимов |
assets/interface-switch.js, assets/tutorial.js | Переключение оформления, сохранение прогресса вкладки и обучение |
assets/tabletop.js, assets/tabletop.css, assets/project-icons.js | Игровая графика, изображения карт и значки проектов |
data/, assets/astana-map-data.js | Снимки геоданных, преобразование и подготовленные контуры карты |
score.js | Данные, формулы, ограничения, синергии, состояние выбора и коды A1 |
comparison.js, scenario-report.js | Сравнение наборов и расчёт рекомендаций |
analysis.js, analysis-api.js | Клиент API и серверный запрос к OpenAI |
serve-local.js, serve-node.mjs, start-local.ps1 | Общие маршруты сайта и API, локальный запуск через Deno или Node.js |
serve-hosted.js, Dockerfile | Запуск на сервере с настройками из окружения |
challenge-demo.html, challenge.js, assets/challenge-ui.js | Отдельный режим кварталов и событий |
scenario-picker.js, example.html | Переиспользуемый компонент выбора и пример подключения |
assets/art/, ruiling-city/images/ | Игровые иллюстрации, изображения направлений и сохранённая иллюстрация Есиля |
Локальный и серверный режимы используют общий обработчик сайта. Браузер обращается к относительному пути /api/analyze на том же домене. Ключ OpenAI хранится на сервере и не передаётся браузеру.
Установка и запуск
Требования
- Git и доступ к репозиторию.
- Для локального приложения: Deno 2 или Node.js 22+. Dockerfile использует Deno 2.9.7; серверные проверки ниже запускаются через Deno.
- Современный браузер с поддержкой ES-модулей.
- Для текстового анализа ИИ — ключ OpenAI с доступом к выбранной модели и интернет на сервере. Остальные функции основного режима работают без ключа.
1. Получите проект
git clone https://github.com/BAITC-Hacks/hack-24299c5d-publish-or-perish.git
cd hack-24299c5d-publish-or-perish
deno --version
Если используете Node.js, вместо deno --version проверьте node --version (22 или новее). Установленная среда должна быть доступна в PATH. Локальная папка .tools/ не входит в репозиторий.
2. Подготовьте настройки
PowerShell:
Copy-Item .env.example .env.local
Linux/macOS:
cp .env.example .env.local
При повторном запуске сохраните существующий .env.local. Для анализа ИИ заполните файл:
OPENAI_API_KEY=ваш_секретный_ключ
OPENAI_MODEL=gpt-4.1-mini
Для демонстрации без ИИ оставьте OPENAI_API_KEY пустым. .env.local исключён из Git и не раздаётся сервером. Настройки локального режима перечитываются при запросах.
3. Запустите сайт
На Windows в PowerShell скрипт выбирает Deno, если он доступен, иначе запускает Node.js:
.\start-local.ps1
Прямой запуск через Deno на любой из указанных систем:
deno run --no-config --no-lock --no-prompt --allow-read=. --allow-net=127.0.0.1:8765,api.openai.com:443 serve-local.js
Альтернативный локальный запуск через Node.js 22+:
node serve-node.mjs
Откройте http://127.0.0.1:8765/. Режим испытания доступен через кнопки режимов над картой или по пути /challenge-demo.html. Классическое оформление: /classic.html и /classic-challenge.html. Остановить сервер можно сочетанием Ctrl+C.
Открытие index.html через file:// не заменяет сервер. Обычная статическая раздача также не реализует API анализа.
4. Проверьте настройки API
Откройте http://127.0.0.1:8765/api/status. Поле configured показывает наличие настроек, но не подтверждает действительность ключа. Реальный запрос выполняется при подтверждении сценария или обновлении разбора ИИ.
Запуск на хостинге
docker build -t akim-city .
docker run --rm -p 8000:8000 -e OPENAI_API_KEY -e OPENAI_MODEL -e PUBLIC_ORIGIN akim-city
Перед запуском задайте переменные в окружении сервера или панели хостинга:
| Переменная | Назначение |
|---|---|
OPENAI_API_KEY | Серверный секрет OpenAI |
OPENAI_MODEL | Модель; по умолчанию gpt-4.1-mini |
PUBLIC_ORIGIN | Обязательный внешний адрес сайта без пути, например https://city.example.com |
PORT | Порт приложения, по умолчанию 8000 |
city.example.com — пример настройки, а не адрес работающей версии. Направьте HTTPS-прокси на порт приложения и задайте таймаут не менее 75 секунд. Подробности и вариант без Docker — в DEPLOY.md.
Как проверить решение
Демонстрация для жюри
- Запустите сайт и откройте основной режим. Завершите или закройте обучение. Если в текущей вкладке восстановился прежний набор, нажмите «Заново». Исходный балл — 52,56.
- Выберите следующие меры и нажимайте «Реализовать инициативу» после каждой:
| Код | Мероприятие | Территория | Стоимость |
|---|---|---|---|
| M7 | Школа + детсад | Нура | 24 |
| M8 | Центр семейного здоровья / поликлиника | Нура | 20 |
| M10 | Освещение и камеры | Нура | 12 |
| M12 | Единая цифровая платформа обращений | Весь город | 14 |
| M5 | Перевод частного сектора на чистое топливо | Сарыарка | 25 |
-
Нажмите «Подвести итоги». Ожидаемый результат, закреплённый в
score.checks.js: 56,54307 до округления (56,54 на экране), затраты 95, остаток 5, критических показателей 0. Действует синергия M10 + M12 в Нуре. -
Откройте «Показатели», выберите Нуру и социальную сферу, затем переключитесь на общий обзор города.
-
Во вкладке «Сравнение» вручную вставьте один код и нажмите «Сравнить результаты»:
A1:4.0,9.4,10.4,11.4,12Сайт покажет второй результат и различия без обращения к ИИ. Код вашего демонстрационного набора:
A1:5.2,7.4,8.4,10.4,12. -
Откройте «Презентация», пролистайте четыре слайда и скачайте HTML-файл.
-
Дополнительно: в новом наборе выберите M4 в Нуре. M7 для Нуры станет недоступной; после отмены M4 блокировка снимется, если нет других ограничений.
-
Перейдите в режим «Испытание» и завершите первый квартал. Появятся два события и условия следующего хода.
Без ключа ИИ выведет сообщение о ненастроенном сервисе; расчёт, сравнение, рекомендации и презентация останутся доступны.
Автоматические проверки
При запущенном сервере откройте checks.html: страница проверяет расчёт, взаимодействие с интерфейсом, сравнение, вкладки и обработку ответов API.
Отдельные проверки из корня проекта:
deno run --no-config --no-lock --allow-read=. server.checks.js
deno run --no-config --no-lock challenge.test.mjs
Первая команда проверяет локальный и серверный обработчики, маршруты обоих режимов, сравнение, рекомендации и защиту файлов с настройками. Вторая проверяет правила испытания, включая воспроизводимость событий и полные партии. Проверки API подменяют ответы OpenAI и не выполняют платных запросов; они не подтверждают работоспособность конкретного ключа или внешнего хостинга.
Данные и интеграции
- Исходные данные находятся в
score.js: доли населения пяти районов, десять показателей, их веса, стоимость и лаги 14 мер, эффекты и три синергии. В прежней документации проекта источником указан хакатонный PDF «Датасет районов»; сам PDF в текущий состав репозитория не входит. Приложение использует зафиксированные значения из кода. - Показатели: T1/T2 — транспорт, E1/E2 — экология, S1/S2 — социальная сфера, B1/B2 — безопасность, C1/C2 — городские сервисы.
- События испытания заданы в
challenge.jsи генерируются по коду турнира, без внешнего источника новостей. - OpenAI Responses API: сервер отправляет запрос на
https://api.openai.com/v1/responsesс рассчитанными сценариями, формулами и рекомендациями. В запросе заданоstore: false; ожидание ответа ограничено 60 секундами. При отсутствии чужих кодов инструкция исключает раздел сравнения. - API сайта:
POST /api/analyzeпринимает{ "code": "A1:…", "otherCodes": [] };GET /api/statusвозвращает состояние настройки без ключа. - Географическая карта игрового оформления использует сохранённые снимки муниципального геопортала: границы
Adm_raionyи рекиhydrography_12092022. Файлы находятся вdata/, источники и ограничения описаны в data/MAP-SOURCES.md. При запуске обращения к геопорталу не нужны. Пересборка модуля карты:node data/build-map.cjs. - Иллюстрации загружаются из репозитория. Описание графики — в ART.md. Показатели города не обновляются из внешних источников в реальном времени.
Ограничения
- Показатели синтетические. Игровая карта отражает архивные границы пяти районов до выделения Сарайшыка и не заявляется актуальной административной картой 2026 года. Классическая карта схематическая. Значки проектов не обозначают реальные адреса строительства.
- Рекомендации ищут улучшения одиночной заменой и не гарантируют глобально лучший набор.
- Текст ИИ зависит от внешнего сервиса и может содержать ошибки. Проверяемые баллы рассчитываются собственным модулем.
- ИИ, сравнение по кодам
A1и экспорт презентации подключены к основному режиму. В испытании они пока не реализованы; результаты двух режимов не предназначены для прямого сравнения. - Нет регистрации, базы результатов и общей таблицы лидеров. Прогресс хранится только в текущей сессии вкладки через
sessionStorage, без серверной синхронизации. При запрете браузерного хранения сохранение недоступно. Код сценария не подтверждает личность участника. - Презентация скачивается в HTML, не в
.pptx; PDF создаётся средствами печати браузера. - Встроенных авторизации и ограничения частоты запросов к платному API нет.
- Для локального анализа нужен сервер Deno или Node.js 22+. Размещение на хостинге настроено через Deno/Docker. Статический хостинг, включая GitHub Pages, сам по себе API не запускает.
Развёрнутая версия
Подтверждённая ссылка на публичную deployed-версию в репозитории не указана.
Для демонстрации используйте локальный запуск. Адрес http://127.0.0.1:8765/ доступен на компьютере, где запущен сервер, и не является публичной ссылкой.
Авторы коммитов
История коммитов
- 2026-09-23 18:00Fit classic interface into desktop viewportltybcs
- 2026-09-23 17:56Merge remote-tracking branch 'origin/main' into codex/tabletop-artltybcs
- 2026-09-23 17:56Style game tutorial, results and exported presentationltybcs
- 2026-09-23 17:55Обновить README под два интерфейса, карту и Node.jsaknazar47
- 2026-09-23 17:51Merge latest main preserving both interfaces and integrated reportsltybcs
- 2026-09-23 17:50Add selectable game and classic interfaces with maps and result presentationltybcs
- 2026-09-23 17:43Удалить неиспользуемые файлы и изображенияaknazar47
- 2026-09-23 17:34Merge remote-tracking branch 'origin/main'Daniyar
Все коммиты (23)
- 2026-09-23 17:33Объединить обучение и компактный интерфейс с API и результатамиDaniyar
- 2026-09-23 17:28Подготовить README для жюри хакатонаaknazar47
- 2026-09-23 17:22Add guided tutorial and compact game controlsDaniyar
- 2026-09-23 17:18Интегрировать результаты, сравнение и API с режимом испытанияaknazar47
- 2026-09-23 16:32Add eight-quarter challenge mode with events and tournament seedsltybcs
- 2026-09-23 15:23Merge remote-tracking branch 'origin/main' into codex/project-foundationltybcs
- 2026-09-23 15:21Add playable city simulator interfaceltybcs
- 2026-09-23 15:09Add transparent card assetsDaniyar
- 2026-09-23 14:55Добавлены коды сценариев и анализ ИИ после подтверждения выбораaknazar47
- 2026-09-23 14:45Remove obsolete district asset and processing scriptDaniyar
- 2026-09-23 14:43Add city simulator and transparent district assetsDaniyar
- 2026-09-23 14:42Добавлен браузерный выбор мероприятий с прогнозами, ограничениями и синергиямиaknazar47
- 2026-09-23 14:07Добавлен калькулятор качества жизни города с документацией на русскомaknazar47
- 2026-09-23 12:21Add poop text and Jason Statham ASCII artDaniyar
- 2026-09-23 12:07Add test text fileltybcs
Структура репозитория (76 файлов)
.dockerignore .env.example .gitignore ART.md CHALLENGE.md DEPLOY.md Dockerfile README.md analysis-api.js analysis.checks.js analysis.js assets/art/M1.png assets/art/M11.png assets/art/M12.png assets/art/M14.png assets/art/M2.png assets/art/M5.png assets/art/M6.png assets/art/M8.png assets/art/M9.png assets/art/city.png assets/art/ecology.png assets/art/safety.png assets/art/services.png assets/art/social.png assets/art/transport.png assets/astana-map-data.js assets/challenge-ui.js assets/challenge.css assets/classic-challenge-ui.js assets/classic-compact.css assets/classic-game.js assets/game-dialogs.css assets/game.css assets/game.js assets/interface-switch.css assets/interface-switch.js assets/modes.css assets/project-icons.js assets/results-tabletop.css assets/results.css assets/results.js assets/tabletop.css assets/tabletop.js assets/tutorial.css assets/tutorial.js challenge-demo.html challenge.js challenge.test.mjs checks.html classic-challenge.html classic.html comparison.js data/MAP-SOURCES.md data/astana-districts-source.json data/astana-rivers-source.json data/build-map.cjs example.html game.checks.js index.html ruiling-city/images/card-ecology.png ruiling-city/images/card-safety.png ruiling-city/images/card-services.png ruiling-city/images/card-social.png ruiling-city/images/card-transport.png ruiling-city/images/esil.png scenario-picker.css scenario-picker.js scenario-report.js score.checks.js score.js serve-hosted.js serve-local.js serve-node.mjs server.checks.js start-local.ps1
Ветки (2)
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.