AAYMA
RU
Войти

Аким на 5 часов

Браузерный симулятор управления Астаной с двумя интерфейсами, игровым и классическим.

Доведённый продукт
Команда «Publish or Perish» 3💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: 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. Ограничения основного режима на пять решений и две меры направления в испытании не применяются.

Как работает решение

  1. Пользователь выбирает направление, мероприятие и район. Городские меры действуют сразу во всех районах.
  2. Модуль расчёта проверяет ограничения и показывает прогноз. Пользователь добавляет меру или пересматривает выбор.
  3. После подтверждения пяти допустимых решений сайт показывает итоговый балл, изменения показателей и код сценария.
  4. Код можно передать другому участнику или вставить чужие коды во вкладку сравнения.
  5. Сервер повторно проверяет коды и рассчитывает результаты. При настроенном ключе он передаёт в OpenAI рассчитанные показатели, формулы и варианты замен для текстового объяснения.
  6. Пользователь изучает рекомендации и сохраняет презентацию своего сценария.

Как считается балл

В основном режиме горизонт составляет восемь кварталов:

Эффект меры = полный эффект × (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.

Как проверить решение

Демонстрация для жюри

  1. Запустите сайт и откройте основной режим. Завершите или закройте обучение. Если в текущей вкладке восстановился прежний набор, нажмите «Заново». Исходный балл — 52,56.
  2. Выберите следующие меры и нажимайте «Реализовать инициативу» после каждой:
КодМероприятиеТерриторияСтоимость
M7Школа + детсадНура24
M8Центр семейного здоровья / поликлиникаНура20
M10Освещение и камерыНура12
M12Единая цифровая платформа обращенийВесь город14
M5Перевод частного сектора на чистое топливоСарыарка25
  1. Нажмите «Подвести итоги». Ожидаемый результат, закреплённый в score.checks.js: 56,54307 до округления (56,54 на экране), затраты 95, остаток 5, критических показателей 0. Действует синергия M10 + M12 в Нуре.

  2. Откройте «Показатели», выберите Нуру и социальную сферу, затем переключитесь на общий обзор города.

  3. Во вкладке «Сравнение» вручную вставьте один код и нажмите «Сравнить результаты»:

    A1:4.0,9.4,10.4,11.4,12
    

    Сайт покажет второй результат и различия без обращения к ИИ. Код вашего демонстрационного набора: A1:5.2,7.4,8.4,10.4,12.

  4. Откройте «Презентация», пролистайте четыре слайда и скачайте HTML-файл.

  5. Дополнительно: в новом наборе выберите M4 в Нуре. M7 для Нуры станет недоступной; после отмены M4 блокировка снимется, если нет других ограничений.

  6. Перейдите в режим «Испытание» и завершите первый квартал. Появятся два события и условия следующего хода.

Без ключа ИИ выведет сообщение о ненастроенном сервисе; расчёт, сравнение, рекомендации и презентация останутся доступны.

Автоматические проверки

При запущенном сервере откройте 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/ доступен на компьютере, где запущен сервер, и не является публичной ссылкой.

Звёзды
⭐ 0
Форки
0
Язык
JavaScript
Последний push
в прошлом месяце
Коммиты
23
Авторы
3
Файлы
76
Ветки
2

Авторы коммитов

ltybcs 9aknazar47 7Daniyar 7

История коммитов

  • 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 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.