문서 추가: 일반 AI 행동 및 정책 모델 설명

This commit is contained in:
2025-12-26 19:42:08 +00:00
parent acfb30bbb6
commit a0fd36765f
3 changed files with 193 additions and 0 deletions
+191
View File
@@ -0,0 +1,191 @@
# Legacy General AI (GeneralAI)
This document summarizes how `legacy/hwe/sammo/GeneralAI.php` selects nation and
general commands, which data fields it relies on, and how policies shape NPC
behavior. It also outlines considerations for an in-memory rewrite of the AI
loop.
## Entry Points
- `chooseNationTurn(NationCommand $reservedCommand)`
- `chooseInstantNationTurn(NationCommand $reservedCommand)`
- `chooseGeneralTurn(GeneralCommand $reservedCommand)`
All three call `updateInstance()` first, which caches current state and derives
key AI decisions (diplomacy state, general type, policy setup).
## Deterministic RNG
`GeneralAI` uses `LiteHashDRBG` seeded with:
```
hiddenSeed + "GeneralAI" + year + month + generalID
```
This makes AI choices reproducible per turn. All random choices (`choice`,
`choiceUsingWeight`, `nextBool`) flow through this RNG.
## State Snapshot and Derived Fields
`updateInstance()` pulls and caches:
- `game_env` (via `KVStorage`): year, month, startyear, turnterm, develcost,
init_year/init_month, killturn, global NPC policy defaults.
- `city` (current city row, from `general` -> `city`).
- `nation` (nation row, or fallback for neutral).
- `nation_env` (KVStorage): npc policy overrides, prev income, last attackable.
- `nation['aux']` decoded JSON.
- `general` primary stats (leadership/strength/intel; both full and adjusted).
- `baseDevelCost` and `maxResourceActionAmount`.
- `dipState`, `attackable`, `warTargetNation`.
- `genType` (type flags derived from stats + policy thresholds).
Derived groupings are computed lazily:
- `categorizeNationCities()` => `nationCities`, `frontCities`, `supplyCities`,
`backupCities` with per-city `dev` and `important` scores.
- `categorizeNationGeneral()` => user/NPC buckets, war/civil buckets,
troop leaders, lost generals, chief list.
## Diplomacy State (`calcDiplomacyState`)
Diplomacy state controls war/peace behavior:
- `d평화`: no war declarations, no active war.
- `d선포`: declaration in progress, no active war.
- `d징병`: pre-war recruitment window.
- `d직전`: immediate pre-war.
- `d전쟁`: active war, or recently lost a front (grace period).
Key inputs:
- `diplomacy` rows (`state`, `term`) for current nation.
- `front` cities with `supply=1`.
- `year/month` relative to `startyear` (early-game war lockout).
`warTargetNation` tracks eligible enemies:
- `2` = currently at war.
- `1` = declaration in progress / pre-war.
- `0` is used as "any neighbor" fallback when no active target exists.
## General Type (`calcGenType`)
General type is a bitmask:
- `t무장` (strength-leaning)
- `t지장` (intelligence-leaning)
- `t통솔장` (leadership threshold for war-capable NPCs)
Logic:
- Strength vs intel decides initial bias.
- If the weaker stat is within 80%, a probabilistic hybrid type can be added.
- `t통솔장` is set when `leadership >= nationPolicy->minNPCWarLeadership`.
## Policy Inputs (Autorun)
`AutorunNationPolicy` and `AutorunGeneralPolicy` are built from:
- per-user autorun options (`env['autorun_user']['options']`)
- `nation_env` overrides (`npc_nation_policy`, `npc_general_policy`)
- global defaults (`env['npc_nation_policy']`, `env['npc_general_policy']`)
- live nation + env snapshot
Policies provide:
- `priority` action lists
- `can{Action}` toggles
- thresholds (min crew, safe population ratio, resource floors, etc.)
## Nation Turn Behavior (`chooseNationTurn`)
Nation-level choices run only for NPCs (`npc >= 2`) or for autorun users:
1. Apply quarterly promotions and tax/bill adjustments.
2. Honor reserved nation commands if valid.
3. Iterate policy `priority`, invoking matching `do{Action}`.
4. Fall back to neutral (empty) nation command if all fail.
### Major Action Groups
- **Troop movement**
- `do부대전방발령`, `do부대후방발령`, `do부대구출발령`
- user/NPC versions to move generals between front/back/supply cities
- checks `frontCities`, `supplyCities`, `last발령`, and war route.
- **Resource distribution**
- `do유저장포상`, `doNPC포상`, `doNPC몰수`
- uses resource floors (`reqNation*`, `reqNPC*`, `reqHuman*`)
- weighted by target general's deficit and recent activity.
- **Diplomacy**
- `do불가침제의`: respond to assistance requests with NAP offer.
- `do선전포고`: probabilistic declaration when strong enough.
- **Capital relocation**
- `do천도`: moves capital based on population, dev, and connectivity.
## General Turn Behavior (`chooseGeneralTurn`)
General-level decisions are layered:
1. NPC message broadcast if `npcmsg` and RNG triggers.
2. Reserved command is honored if valid (unless `휴식`).
3. Immediate recovery if `injury > cureThreshold`.
4. Special cases:
- NPC troop leaders (type 5) always `집합`.
- wanderers decide on founding / moving / disbanding.
5. Iterate policy `priority`, invoking `do{Action}`.
6. Fallback to `do중립`.
### Major Action Groups
- **Domestic development**
- `do일반내정`, `do전쟁내정`, `do긴급내정`
- weighted by `city` dev rates and general type flags.
- **War preparation**
- `do징병`, `do전투준비`, `do출병`
- strict checks on crew, train, atmos, population and diplomacy state.
- **Mobility**
- `do전방워프`, `do후방워프`, `do내정워프`, `do귀환`
- uses `front/supply/backup` cities and population thresholds.
- **Resource handling**
- `do금쌀구매` (trade), `doNPC헌납` (donation).
- **Neutral behavior**
- `do중립` selects between `물자조달`, `인재탐색`, `견문`.
## Data Fields Accessed (Representative)
GeneralAI reads or writes:
- **Nation**: `nation`, `capital`, `gold`, `rice`, `tech`, `level`, `type`,
`chief_set`, `rate`, `bill`, `aux`.
- **City**: `city`, `nation`, `supply`, `front`, `pop`, `pop_max`, `trust`,
`agri/comm/secu/def/wall` and `*_max`, `trade`, `level`, `region`.
- **General**: `npc`, `officer_level`, `officer_city`, `killturn`, `injury`,
`troop`, `crew`, `train`, `atmos`, `defence_train`, `gold`, `rice`, `belong`,
`permission`, `npcmsg`, `dex1..dex5`, `armType`, `affinity`, `makelimit`.
- **KVStorage**: `npc_*_policy`, `prev_income_*`, `last_attackable`,
`last천도Trial`, `resp_assist*`.
## In-Memory Rewrite Considerations
To port the AI to an in-memory state model without behavior drift:
- **Snapshot-first**
- Build a per-turn `GameSnapshot` containing env, nation, cities, generals,
diplomacy, and nation_env. `GeneralAI` should read only from this snapshot.
- **Derived caches**
- Cache `DiplomacyState`, `CityBuckets`, `GeneralBuckets`, and `WarRoute`.
- Use lazy recalculation and invalidate only the affected region/city/general
after a command is applied.
- **Deterministic ordering**
- For candidate lists, sort by ID before weighted RNG to preserve parity.
- RNG seeding should keep the exact per-turn seed scheme to ensure replay.
- **Command evaluation**
- Keep `hasFullConditionMet()` semantics intact by providing the same
generalized context (`general`, `city`, `nation`, `dest*`).
- **Policy snapshots**
- Cache policy values per turn and avoid reading KVStorage per action.
- When policies change, treat it as an explicit state transition.
These guidelines mirror the current "derive once, then select via priority"
pattern and minimize resimulation deltas in the rewrite.
+1
View File
@@ -39,6 +39,7 @@ organization rather than endpoint-first routing.
- Turn execution pipeline: `docs/architecture/legacy-engine-execution.md`
- General model and action stack: `docs/architecture/legacy-engine-general.md`
- General AI behavior and policy model: `docs/architecture/legacy-engine-ai.md`
- Trigger system (iAction + trigger callers): `docs/architecture/legacy-engine-triggers.md`
- Battle and war resolution: `docs/architecture/legacy-engine-war.md`
- Command catalog: `docs/architecture/legacy-commands.md`
+1
View File
@@ -10,6 +10,7 @@ Move items into the main docs once they are finalized.
- In-memory state lifecycle and DBMS flush checkpoints
- Recovery behavior after partial flush or crash
- Observability: metrics, logs, and alerts for turn processing
- [AI suggestion] Define a stable in-memory AI state contract (snapshot + delta invalidation rules) aligned with `GeneralAI` inputs.
## Game Logic and Testing