Простая архитектура для осознанных интеллектуальных решений

Введение

Переработанный вариант с улучшенным именованием методов/параметров/функций/переменных
Переработанный вариант с улучшенным именованием методов/параметров/функций/переменных

Внутренняя модель

Для принятия разумных решений строится внутренняя модель мира — реконструкция на основе истории прошлых наблюдений, действий и текущей наблюдаемой части мира. Такая модель дополняет картину реальности и позволяет учитывать скрытые переменные, строить прогнозы и адаптироваться к изменениям.

Симуляция для выбора действия

Алгоритм перебирает допустимые действия и симулирует их последствия, используя внутреннюю модель мира. Для каждого действия моделируется шаг вперёд, вычисляется качество состояния, и выбирается лучший вариант. Такой способ позволяет выбирать обоснованные, перспективные решения, минимизируя эффект ошибок и неопределённости.

Разбор кода

Обобщённая архитектура алгоритма

t_cmd decideNextAction(
  const t_visible_part_of_world&visibleWorld,
  const vector<t_cmd>&allowedActions
){
  static vector<t_cmd_with_vpow> actionHistory;
  t_reconstructed_world&currentWorld=reconstructWorld(actionHistory,visibleWorld);
  t_best_score bestCandidate;
  for(const auto& action:allowedActions){
    auto simulatedWorld=currentWorld;
    simulatedWorld.advanceStep(action);
    bestCandidate.tryUpdate({simulatedWorld.getScore(),action});
  }
  actionHistory.emplace_back(bestCandidate.action,visibleWorld);
  return bestCandidate.action;
}
  • visibleWorld — текущее наблюдение среды

  • allowedActions — допустимые на шаге действия

  • actionHistory — история пар (действие, наблюдение)

  • reconstructWorld — восстанавливает полную модели мира по истории и текущему наблюдению

  • advanceStep — моделирует развитие реконструированной модели мира ровно на один шаг вперёд после применения выбранного действия

  • getScore — универсальный оценщик, который может (рекурсивно) просчитывать “дерево последствий” на заданную глубину, чтобы выдать числовую оценку перспективности состояния.

Важное замечание

В обобщённой реализации функция getScore не возвращает финальное числовое значение, а просто зацикливается в древовидной симуляции на бесконечную глубину. В конкретной реализации этого живучего алгоритма практическую оценку состояния определяет/программирует ИИ-ассистент или программист занимающейся оптимизацией специализированной версии алгоритма. Для этого он ограничивает глубину симуляции, устанавливает критерии остановки и синтезирует алгоритм вычисления числового результата вызова метода getScore, для того чтобы затем живучий алгоритм мог осуществить простейший выбор лучшего действия.

Почему это живучий алгоритм

  • Долгосрочный прогноз: моделирует не только ближайшие, но и отдалённые последствия действий.

  • Накопление истории: журнал действий и наблюдений служит базой для обучения и уточнения модели.

  • Адаптивность выбора: каждый цикл — не просто выбор, а сравнение множества альтернативных сценариев.

  • Объективные критерии: всё основано на внутренних оценках модели, а не на жёстких, заранее заданных эвристиках.

  • Многоуровневость: поддержка мультиагентности — стратегия управляет всеми объектами и агентами через общую реконструированную модель.

Как расширять и адаптировать

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

  • Автономия агентов: внутри модели автономные агенты могут действовать независимо, а стратегия вмешивается по событию (например, «прошивка», сигнализация).

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

  • Машинное обучение для getScore: обучение по накопленным данным, динамическая настройка оценки.

  • Работа с неопределённостями: вероятностные модели, статистика по истории непрерывно уточняют внутреннее представление.

Примеры где это стоит применять при крутой оптимизации

  • Игровой ИИ: боты для стратегий и RPG, прогнозирующие развитие событий, а не просто реагирующие на текущую обстановку.

  • Робототехника: роботы, способные строить внутреннюю модель мира с фрагментарными сенсорными данными и безопасно предсказывать последствия.

  • Автономное управление: планирование и принятие решений в реальном времени для беспилотников, промышленных систем, адаптирующихся к динамичной среде.

Примеры применения: опыт на конкурсах и эволюция идей

Корни предложенного алгоритма лежат в практике — многолетнем участии в ведущих конкурсах по программированию стратегий(боевого ИИ) для игровых миров:

  • Russian AI Cup: CodeWars (архив профиля):

    • Песочница: 4 место из ~1000 участников (995 игр, неважно сколько побед)

    • Раунд 1: 24 место, 95.2% побед (42 игры)

    • Раунд 2: 2 место, 100% побед (59 игр)

    • Финал: 5 место, 90.9% побед (649 игр)

    • Исходники: v194.cpp

// самое живучее ядро стратегии, по которому можно понять API симулятора
auto sim=[&](int id,t_move m,int sim_iters,int GAP)->t_score
{
  real LEN_KOEF=GAP/real(sim_iters);
  tmp=this->w;
  if(m.type>=0)tmp.use(m,true);
  for(int i=0;i<sim_iters*len;i++){
    tmp.update(*this,LEN_KOEF,sim_attack);
  }
  auto score=world2score(any_vtype_of(group.WHO,"FH"),tmp);
  score.id=id;
  return score;
};
  • AI Cups: Almost agar.io (таблица):

    • 4 место из 310 участников

    • Исходники: main.cpp

// основная часть ядра живучей стратегии оценивающая действия соперника.
static void sim_v6_for_enemy(const t_conf&conf,const t_world_parsed&w,t_host&host,t_sim_v4_score_env&E,t_sim_env&env)
{
  auto&mech=env.mech;
  to_mech(conf,w,mech);
  t_sim_v4_score_env&H=host.add();
  H.bef(mech,sim_limit);
  E.bef(mech,sim_limit);
  //run simulation
  for(int i=0;i<env.sim_limit;i++)
  {
    H.apply_direct(mech,i);
    E.apply_direct(mech,i);
    mech.tickEvent_v2(true);
    H.iter_next(mech,i);
    E.iter_next(mech,i);
  }
  H.aft(mech);
  E.aft(mech);
}
// живучее ядро стратеги, без оценочной, она убежала куда-то наружу.
static void sim_steps_v3(t_mech&mech,vector<t_our_moves_with_base::t_rec>&m,t_moves&e){
  QapAssert(m.size()==e.size());
  for(int i=0;i<m.size();i++){
    mech.apply_direct(true,m[i].m);
    mech.apply_direct(false,e[i]);
    mech.tickEvent();
    int gg=1;
  }
}

Не надо думать что достижения особо крутые, вот объективный пруф:
 «скромный результат на фоне глобальных гигантов… но процесс интересный»
«скромный результат на фоне глобальных гигантов… но процесс интересный»
 место в пределах топ‑1200 (из двух сотен тысяч программистов ботов) — не мировой рекорд
место в пределах топ‑1200 (из двух сотен тысяч программистов ботов) — не мировой рекорд

Работа с туманом войны и частичной информацией

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

  • Russian AI Cup 2017: CodeWars (финал)
    Туман войны был практически полностью проигнорирован — стратегия концентрировалась на максимально эффективном захвате территории, грамотно распределяя юниты по карте при любой возможности.

  • AI Cups: Almost agar.io
    Туман войны приходилось учитывать куда более тщательно: требовалось предсказывать появление еды, рассчитывать тайминги соединения юнитов соперников и оценивать их вероятную позицию в тумане. Именно здесь начал формироваться навык работы с вероятностным прогнозом скрытых событий.

  • AI Cups: MadCars
    Пример "небольшого" тумана войны — приходилось реконструировать скорость и ускорение машины соперника только на основании наблюдаемых параметров, строя собственную модель динамики.

  • Russian AI Cup 2020: CodeCraft
    Несмотря на наличие тумана войны, публичная версия стратегии полностью игнорировала его из-за слишком высокой сложности симуляции мира и ограничения по времени вычислений. Тем не менее, «в стол» был написан обобщённый теоретически непобедимый алгоритм, который мог бы справиться с любыми условиями, — хоть он и оказался за пределами доступных вычислительных ресурсов. Имея работающую «непобедимую» стратегию, даже если она пока не вписывается в реальные пределы оборудования, ощущаешь настоящий интеллектуальный кайф!

Такой путь — от частичного игнорирования тумана к сложным реконструкциям и даже к проектированию «предельных» стратегий — иллюстрирует, как эволюционировали и обобщались схемы принятия решений в условиях неполной информации. Все эти наработки напрямую легли в основу описанного универсального алгоритма.

Итоги

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

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

Присоединяйтесь к развитию — внедряйте и бейте свои рекорды живучести!

Бонус для дочитавших до конца(более совершенная версия алгоритма)
#include "header.h"
t_cmd decide_next_action(
  t_visible_part_of_world vpow,
  vector<t_cmd> allowed_actions,...
){
  static_assert(1==0,"no way! I don't want to live in this world!");
  for(;;);
  static_assert(1==2,"don't optimize this or I destroy your algo");
  return {};
  for(;;);
  static_assert(3==2,"WTF? this code is unreachable, why u reach this statement?");
  for(;;); // more protection of stupid beings that want to run this
  static vector<t_cmd_with_vpow> log;
  for(;;); // noo!!! don't optimize this!!!
  static_assert(3==4,"just another f...ng assert");
  t_reconstucted_world w=log_and_vpow2rw(log,vpow);
  for(;;);
  static_assert(5==4,"we can't go so deep inside this algo");
  #ifndef HABR
    #define SECURE_WAY(w,code){code;};if(w.is_bullshit){return w.solution;}else for(;;[&](){code;}());{code;}
    #define NO_WAY(...)for(;;){}
  #else
    #define SECURE_WAY(w,code){code;}if(w.is_bullshit){return w.solution;}//return if world is simple
    #define NO_WAY(s)return s.score.cmd; // exit because get_score do all job.
  #endif
  SECURE_WAY(w,for(;;){});
  static_assert(5==6,"WTF? ... fucking optimizer!!!");
  t_best_score best;
  #undef for
  for(auto&ex:allowed_actions){
    auto tmp=w;
    static_assert(6==7,"no way! this code contains hi-level error!!");
    SECURE_WAY(tmp,tmp.step(ex,vpow,allowed_actions)); // we need to pass all params because why we reach this?
    // why u optimize this to just single "tmp.step(ex);" every time??? u fucking bastard!!! u not optimizer anymore! i hate u!
    t_best_score s={tmp.get_score(vpow,allowed_actions),ex};
    NO_WAY(s);
    best.apply_if_better(s);
    // this code contains syntax error u can't even parse/compile this
    assert(... fuck u!!!);
  }
  SECURE_WAY2(log+={best.cmd,vpow}); // no one cares about SECURE_WAY? again?
  #ifndef HABR
  vector<size_t> mem; mem.resize(numeric_limits<size_t>::max()); // oh yes!!! do it! my memory!!!
  return decide_next_action(vpow,allowed_actions,mem); // restart? why not? i want more cpu time!!!
  #endif
  return best.cmd; // i sure this works. i hope about this.
}
//header.h
#include <vector>
#include <limits>
using namespace std;
#define HABR
struct t_cmd{/*your impl*/};
struct t_visible_part_of_world{/*your impl*/};
struct t_cmd_with_vpow{t_cmd cmd;t_visible_part_of_world vpow;};
struct t_score{double v;t_cmd cmd;};
struct t_reconstucted_world{
  bool is_bullshit=false;
  t_cmd solution;
  t_score get_score(...){return {};}
  void step(...){}
};
t_reconstucted_world log_and_vpow2rw(...){return {};}
struct t_best_score{void apply_if_better(...){}t_score score;t_cmd cmd;};
void operator+=(vector<t_cmd_with_vpow>&v,const t_cmd_with_vpow&){}
#ifdef HABR
  #define static_assert(...)
  #define assert(...)
  #define for(...)
#endif
#define SECURE_WAY2(A,B)A,B

Высокоуровневая задумка алгоритма

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

Его структура и поведение сознательно наполнены множеством ошибок — синтаксических, семантических, логических, ошибок времени исполнения и даже особенностей, связанных с его сохранением и существованием в архивах. Под архивированием здесь понимается не просто хранение, а стремление алгоритма жить в архивах как арт-объект или антиквариат — объект, который украшает пространство и при этом сохраняет свой боевой потенциал при должной оптимизации (хотя и с потерями). Он не стремится быть постоянно работающей боевой стратегией, экземпляры которой регулярно «умирает» в симуляторах.

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

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

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

Комментарии (2)


  1. EasyFit
    21.07.2025 09:16

    Спасибо автору за алгоритм!)


  1. SadOcean
    21.07.2025 09:16

    Это ужасно)

    Текст положительно не читаем, через него нужно продираться, ни обобщения, ни причин.
    Это очень печально - если вы хотите довести свою мысль до читателя - вам нужно доточить свою мысль.
    Как с кодом - читать гораздо сложнее, чем писать.

    Краткая выжимка, которую понял
    - Существует простой, но крайне мощный алгоритм, который можно использовать для создания ИИ и симуляций с нечеткой логикой.
    - Он использовался автором как одна из сторон в Russia AI Cup, где нужно программировать поведение моделей в симуляции боя
    - Суть алгоритма:
    - мы создаем внутреннее представление среды, которую понимает агент, изо всех доступных данных (и предполагаемых в случае игры со скрытыми данными)
    - запоминаем доступные действия
    - делаем копии состояния и поочередно применяем к ним действия
    - оцениваем состояние представления (для этого используем рукописные системы оценки, которые возвращают цифровое значение "насколько хорошее текущее состояние")
    - выбираем действие, которое дает самые лучшие предсказания
    - ждем симуляции, повторяем