AAYMA
RU
Войти

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

Симулятор управления условной Астаной: игрок с бюджетом 100 выбирает ровно 5 из 14 инициатив по 5 направлениям для 5 районов.

Рабочий MVP
Команда «MindForge» 3💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: MindForge
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Рабочий MVP

Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам

Суть

Симулятор управления условной Астаной: игрок с бюджетом 100 выбирает ровно 5 из 14 инициатив по 5 направлениям для 5 районов. Детерминированный движок на Go считает Astana Quality of Life Score, а LLM объясняет уже рассчитанный результат.

Как устроено

Go HTTP API проверяет сценарий: бюджет, ровно 5 решений, не больше 2 в одном направлении, несовместимые пары. Движок применяет эффекты с поправкой на лаг (effect × (8−L)/8) и фиксированные синергии, ограничивает 10 метрик районов диапазоном 0–100 и считает взвешенный District Score. Итог: Score = 0.7×D_avg (по доле населения) + 0.3×min(D_d) − N_crit (метрики ниже 40). Необязательный слой OpenAI поверх результата объясняет сильные решения и риски, но на числа не влияет.

Ключевые решения

  • детерминированный simulation engine
  • лаг эффекта (8−L)/8
  • синергии инициатив
  • взвешенный score со штрафом за худший район
  • валидация правил совместимости

Метрики

Baseline Score ≈ 52.56 → ≈ 56.5 на эталонном сценарии (подтверждено go test)

Особенности

Жёсткое разделение: числа считает только детерминированная формула, LLM их не пересчитывает и эффектов не придумывает. В формулу Score входит минимум по районам, поэтому выиграть за счёт одного сильного центра нельзя. Эталонный сценарий закреплён в Go-тесте.

Стек

Go · статический HTML/JS · Python (ai-заготовка)

Модели

OpenAI


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-052c857d-mindforge.

README

README.md

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

By Assem Kumarbekova and Alisher Bugubay.

AI-симулятор управления городом.

Представьте: у вас есть 100 условных единиц бюджета, ровно 5 решений, 5 районов города и десятки дискуссионных приоритетов. Где лучше вложить деньги, чтобы не развалить одну часть города ради другой? Этот проект помогает ответить на этот вопрос в формализованной, быстро повторяемой модели условной Астаны.

Пользователь выбирает инициативы, сервер валидирует сценарий, а детерминированный engine рассчитывает эффект на инфраструктуру, экологию, городские сервисы, безопасность и социальную сферу. Результат превращается в Astana Quality of Life Score — число, которое отражает итоговое состояние города, а не просто сумму красивых обещаний.

AI в проекте не заменяет математику. Он — слой анализа поверх уже рассчитанного сценария: объясняет, куда уходит бюджет, какие решения сильные, где скрытые риски и что можно улучшить дальше.

Проблема

Городскому управленцу приходится распределять ограниченный бюджет между несколькими направлениями развития:

  • транспорт;
  • экология и озеленение;
  • социальная инфраструктура;
  • безопасность;
  • городские сервисы.

Инвестиции в одно направление сокращают возможности для другого. Синтетическая модель города позволяет экспериментировать с разными стратегиями и видеть последствия решений без необходимости опираться на реальные данные о текущем состоянии столицы.

Продукт не претендует на прогноз реального развития Астаны. Он моделирует условную городскую систему с заданными эффектами и синергиями.

Решение

Основной цикл выглядит так:

Исходное состояние города → бюджет 100 → выбор 5 инициатив → валидация → симуляция → применение эффектов и синергий → пересчёт проблемных показателей → Astana Quality of Life Score → результат и объяснение.

Именно здесь проект раскрывает свою идею: он не обещает “магический” прогноз, а показывает, как небольшая серия управленческих решений меняет состояние города в заданной синтетической модели. Это и есть основной продукт — безопасный, быстрый, прозрачный способ тестировать стратегии без риска для реальной городской политики.

Ключевое правило проекта: численные показатели рассчитываются детерминированным алгоритмом. LLM не считается источником баллов, не придумывает эффекты инициатив и не пересчитывает Score.

Как работает симулятор

  1. Пользователь видит исходное состояние пяти районов города.
  2. Пользователь получает бюджет в 100 условных единиц.
  3. Пользователь выбирает ровно 5 мероприятий.
  4. Для районных мер выбирается район, в котором эффект применяется.
  5. Система валидирует сценарий по правилам бюджета и совместимости.
  6. Если стратегия невалидна, возвращается понятная причина ошибки.
  7. Если стратегия валидна, запускается simulation engine.
  8. Эффекты корректируются с учётом лага мероприятия.
  9. При наличии соответствующих пар инициатив активируются синергии.
  10. Показатели районов пересчитываются и ограничиваются диапазоном 0–100.
  11. Считается районный Score по весам показателей.
  12. Считается Astana Quality of Life Score по итоговой формуле.
  13. Результат отображается в интерфейсе с изменением относительно базового состояния.
  14. Если AI доступен, LLM объясняет уже рассчитанный результат, но не влияет на числа.

Модель города

В текущей реализации используются пять районов условной Астаны:

IDРайонДоля населенияКраткое описание
esilЕсиль0.27Пробки на мостах и перегруженные школы
almatyАлматы0.24Старый ЖКХ и пробки
saryarkaСарыарка0.20Смог от частного сектора, слабое озеленение
baikonyurБайконур0.13Сбалансированный район без выраженных перекосов
nuraНура0.16Главный аутсайдер по социальной инфраструктуре и транспорту

Показатели города представлены в форме десяти метрик на шкале 0–100. Чем выше значение, тем лучше состояние показателя.

Транспорт

  • T1 — разгрузка дорог
  • T2 — доступность общественного транспорта

Экология

  • E1 — озеленение
  • E2 — качество воздуха

Социальная инфраструктура

  • S1 — школы и детские сады
  • S2 — поликлиники и первичная медицинская помощь

Безопасность

  • B1 — безопасность улиц
  • B2 — безопасность дорожного движения

Городские сервисы

  • C1 — надежность ЖКХ
  • C2 — скорость решения обращений жителей

Данные о районах и инициативах находятся в backend/internal/simulation/data/city.json.

Управленческие инициативы

В проекте реализованы 14 инициатив. Ниже — фактическая таблица из embedded dataset.

IDНаправлениеМероприятиеТипСтоимостьЛаг
M1transportВыделенные полосы для автобусовdistrict182
M2transportУмные светофорыcity222
M3transportЛиния ЛРТ / расширениеdistrict304
M4greenПарк / скверdistrict152
M5greenЧистое топливо для частного сектораdistrict253
M6greenОзеленение и ветрозащитные полосыcity204
M7socialШкола + детсадdistrict243
M8socialЦентр семейного здоровья / поликлиникаdistrict203
M9socialДворовые спорт-хабыdistrict101
M10safetyОсвещение и камеры Safe Citydistrict121
M11safetyБезопасные переходы и школьные зоныdistrict101
M12servicesЦифровая платформа обращенийcity141
M13servicesМодернизация тепло- и водосетейdistrict284
M14servicesАварийные бригады ЖКХcity161

Пояснение к типу:

  • district — эффект применяется к конкретному району выбранной инициативы;
  • city — эффект применяется ко всем районам.

Правила

Фактически реализованные правила в backend/internal/simulation/simulation.go:

  • бюджет равен 100;
  • пользователь выбирает ровно 5 решений;
  • повтор одной и той же инициативы запрещён;
  • для районной инициативы район обязателен;
  • для городской инициативы район не указывается;
  • не более 2 мероприятий в одном направлении;
  • M1 и M3 несовместимы;
  • M4 и M7 нельзя размещать в одном районе;
  • M5 и M13 нельзя размещать в одном районе;
  • порядок выбора решений не влияет на итоговый расчёт, поскольку эффекты суммируются и синергии проверяются по набору выбранных инициатив.

Если стратегия невалидна, сервер возвращает читаемое сообщение и не считает Score.

Математическая модель

Горизонт симуляции

Горизонт симуляции равен 8 кварталам.

Лаг и реализация эффекта

Для мероприятия с лагом L фактическая доля эффекта рассчитывается так:

realized_fraction = (8 - L) / 8

Реализованный эффект от инициативы:

realized_effect = full_effect × (8 - L) / 8

Пример из реализации: для M7 эффект по S1 равен +16, а лаг равен 3.

16 × (8 - 3) / 8 = 16 × 5/8 = 10

То есть при выборе M7 к соответствующему показателю добавляется +10 в текущем расчёте, а не полный +16.

Синергии

В проекте реализованы три фиксированные синергии:

СинергияЭффектГде активируется
M1 + M2T1 +2в районе M1
M10 + M12B1 +2в районе M10
M5 + M6E2 +2в районе M5

Эти бонусы фиксированные, применяются после индивидуальных эффектов и не масштабируются лагом.

District Score

Для района рассчитывается агрегированный Score по формуле:

D_d = Σ w_k × I_dk

Где веса текущей реализации такие:

  • T1 = 0.10
  • T2 = 0.10
  • E1 = 0.09
  • E2 = 0.11
  • S1 = 0.11
  • S2 = 0.11
  • B1 = 0.09
  • B2 = 0.09
  • C1 = 0.10
  • C2 = 0.10

То есть формула в коде выглядит так:

districtScore(m Metrics) float64 {
    return .10*m.T1 + .10*m.T2 + .09*m.E1 + .11*m.E2 + .11*m.S1 + .11*m.S2 + .09*m.B1 + .09*m.B2 + .10*m.C1 + .10*m.C2
}

Это означает, что итоговый районный балл — это взвешенная сумма показателей. Слабые показатели в одном районе влияют на итог сильнее, поскольку в формуле общего Score учтён минимум по районам.

Astana Quality of Life Score

Итоговый городской балл рассчитывается следующим образом:

Score = 0.7 × D_avg + 0.3 × min(D_d) − N_crit

Где:

  • D_avg — средневзвешенный районный Score с учётом доли населения;
  • min(D_d) — наихудший район по Score;
  • N_crit — число пар район × показатель, где итоговое значение строго меньше 40.

В текущей реализации это соответствует коду:

func cityScore(ms []Metrics) (float64, int) {
    avg, minScore := 0.0, math.Inf(1)
    crit := 0
    for i, m := range ms {
        s := districtScore(m)
        avg += Districts[i].Population * s
        if s < minScore {
            minScore = s
        }
        crit += critical(m)
    }
    return .7*avg + .3*minScore - float64(crit), crit
}

Смысл формулы:

  • 70% веса у среднего по городу состояния;
  • 30% веса у самого слабого района;
  • штраф за критические показатели ниже 40;
  • формула не позволяет «победить» только за счёт сильного центра, если в другом районе показатели падают слишком низко.

Проверка корректности

В текущем репозитории есть проверка эталонного сценария в backend/internal/simulation/simulation_test.go.

Фактически проверяются следующие значения:

  • Baseline Score ≈ 52.56;
  • сценарий:
    • M7 → nura
    • M8 → nura
    • M10 → nura
    • M12 → city
    • M5 → saryarka
  • стоимость сценария = 95;
  • активируется синергия M10 + M12;
  • итоговый Score ≈ 56.5.

Эти цифры подтверждены тестом в коде. Для фактической проверки проекта используется команда:

cd backend
go test ./...

На текущем состоянии репозитория эта команда проходит успешно.

Архитектура

Frontend (static HTML/JS)
   |
   v
Go HTTP API
   |
   v
Validator
   |
   v
Simulation Engine
   |
   +--> Budget checks
   +--> Effects / Lag
   +--> Synergies
   +--> District Score
   +--> Astana Quality of Life Score
   |
   v
Simulation Result
   |
   +--> API response to UI
   |
   +--> Optional AI layer
             |
             v
       OpenAI API
             |
             v
       AI Analysis

В текущем коде AI является необязательным слой поверх уже рассчитанного результата. Если OPENAI_API_KEY отсутствует, сервер логирует предупреждение и продолжает работать в обычном режиме.

Структура проекта

.
├── .env                     # локальный .env, не коммитится
├── .gitignore              # игнорирует .env
├── README.md               # документация проекта
├── ai/
│   └── pyproject.toml      # минимальная конфигурация Python-модуля
├── backend/
│   ├── cmd/
│   │   └── api/
│   │       ├── env.go      # загрузка переменных окружения
│   │       ├── main.go     # HTTP API и точка входа
│   │       └── web/
│   │           └── index.html  # UI
│   ├── go.mod
│   └── internal/
│       ├── domain/         # доменные сущности и связанные тесты
│       ├── openai/         # клиент OpenAI для AI-анализа
│       └── simulation/      # данные, валидатор и математическая модель
├── config/
├── data/
├── tests/
└── .gitignore

Технологии

  • Go — backend и simulation engine;
  • embedded static HTML/JS — пользовательский интерфейс, отдаваемый сервером;
  • JSON — данные по районам и мерам;
  • OpenAI API — дополнительный AI-слой для объяснения результата;
  • Git — контроль версий.

В проекте нет отдельного React/Vue/Next.js frontend. Веб-интерфейс сервится статическим файлом через Go.

Запуск проекта

Требования

  • Go 1.22 или выше;
  • доступ к Интернету только при использовании AI-анализа;
  • локальный файл .env в корне проекта для OPENAI_API_KEY при необходимости.

Клонирование

git clone <repo-url>
cd hack-052c857d-mindforge

Переменные окружения

Для AI-режима создайте файл .env в корне проекта:

OPENAI_API_KEY=your_openai_key_here
OPENAI_MODEL=gpt-4.1-mini

Файл .env уже добавлен в .gitignore, поэтому он не попадёт в Git.

Запуск

cd backend
go run ./cmd/api

После запуска приложение будет доступно по адресу:

http://localhost:8080

AI-анализ

AI-слой в проекте реализован как анализ уже рассчитанной симуляции. Он не должен:

  • рассчитывать Score;
  • менять бюджет;
  • пересчитывать эффекты мер;
  • генерировать численные показатели.

Он делает следующее:

  • объясняет итоговые результаты;
  • выделяет сильные стороны сценария;
  • перечисляет ключевые риски;
  • описывает компромиссы;
  • предлагает следующие шаги и альтернативные направления.

Примечание: в текущем коде AI-путь зависит от корректной настройки OPENAI_API_KEY и доступности OpenAI API. Если ключ отсутствует, функция анализа считается недоступной, а основной симулятор продолжает работать без её участия.

Отказоустойчивость AI

Даже если OpenAI недоступен, пользователь должен иметь возможность:

  • выбрать инициативы;
  • получить валидный сценарий;
  • увидеть Budget, Score, изменения по районам и синергии;
  • пользоваться детерминированной моделью без внешнего сервиса.

Это реализовано в текущем проекте: AI не является обязательным компонентом.

Тестирование

В проекте есть unit-тесты на симуляцию и AI-клиент. Проверка выполняется командой:

cd backend
go test ./...

На текущем состоянии репозитория тесты проходят успешно.

Демо за 5 минут

Вот короткий, эффектный сценарий, который удобно показать на живой демонстрации:

  1. Запустите backend через go run ./cmd/api.
  2. Откройте http://localhost:8080.
  3. Убедитесь, что интерфейс показывает бюджет в 100 единиц.
  4. Выберите 5 инициатив, например:
    • M7 → nura
    • M8 → nura
    • M10 → nura
    • M12 → city
    • M5 → saryarka
  5. Нажмите кнопку расчёта.
  6. Посмотрите, как базовый и итоговый Score расходятся: это уже заметное “до/после”.
  7. Проверьте, что синергия M10 + M12 активируется — на глаз это очень видно в итоговом результате.
  8. Если OPENAI_API_KEY настроен, запустите AI-анализ и покажите, как модель объясняет логику решения без вмешательства в сами числа.

Эта демонстрация хорошо работает для жюри: она показывает не только цифры, но и управленческую логику проекта.

Ограничения

  • Данные синтетические и служат для демонстрации логики;
  • эффекты инициатив заданы заранее;
  • модель не является прогнозом реальной городской политики;
  • результат описывает игру внутри симулятора, а не реальное состояние Астаны;
  • AI-объяснение не влияет на математические расчёты и не заменяет модель;
  • проект соответствует хакатонной реализации и пока не является полноценной системой городского планирования.

Возможное развитие

Не реализовано в текущем коде, но может быть логичным продолжением проекта:

  • сравнение нескольких сценариев и стратегий;
  • сохранение сценариев и история решений;
  • более развитая визуализация по районам;
  • карта города с выделением проблемных зон;
  • учебные рекомендации по улучшению стратегии;
  • более сложная модель городских зависимостей;
  • расширенный AI-советник на основе уже рассчитанных результатов;
  • экспорт результатов в PDF/CSV.

Финальная проверка

README подготовлен на основе реального состояния репозитория. В нём отражены только те компоненты, которые реально существуют в проекте:

  • детерминированная симуляция;
  • валидаторы и ограничения;
  • city dataset;
  • Go backend;
  • API и UI;
  • опциональная OpenAI интеграция;
  • тестовый сценарий с проверяемыми числами.

README не утверждает, что AI работает без настройки ключа, и не описывает несуществующие API-эндпоинты или технологии.

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

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

akumarbe 7assrakhimova 3Assem Kumarbekova 2

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

  • 2026-09-23 17:57Update .env.example to use placeholder API keyAssem Kumarbekova
  • 2026-09-23 17:56Change OPENAI_API_KEY to a placeholderAssem Kumarbekova
  • 2026-09-23 17:42Add READMEassrakhimova
  • 2026-09-23 17:35style: refresh simulator design and remove empty placeholdersakumarbe
  • 2026-09-23 17:30fix: complete OpenAI scenario analysisakumarbe
  • 2026-09-23 16:59feat: load OpenAI credentials from local env fileakumarbe
  • 2026-09-23 16:25Add OpenAI analysis integrationassrakhimova
  • 2026-09-23 15:30fix: load dataset and handle simulator errorsakumarbe
Все коммиты (12)
  • 2026-09-23 15:07docs: add simulator usage guideakumarbe
  • 2026-09-23 15:04feat: add city management simulator MVPakumarbe
  • 2026-09-23 14:42Add Go city simulator domainassrakhimova
  • 2026-09-23 13:49Create Akim 5 Hours simulator structureakumarbe
Структура репозитория (20 файлов)
.env.example
.gitignore
README.md
ai/pyproject.toml
ai/src/akim_ai/__init__.py
backend/.env.example
backend/cmd/api/env.go
backend/cmd/api/main.go
backend/cmd/api/web/index.html
backend/go.mod
backend/internal/domain/budget.go
backend/internal/domain/budget_test.go
backend/internal/domain/city.go
backend/internal/domain/initiative.go
backend/internal/openai/client.go
backend/internal/openai/client_test.go
backend/internal/simulation/data/city.json
backend/internal/simulation/simulation.go
backend/internal/simulation/simulation_test.go
config/app.example.yaml

Обсуждение 0 комментариев

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

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