diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-19 02:37:20 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-19 02:37:20 +0800 |
| commit | 2f46d1789088eb165271bd915844376aa5a84768 (patch) | |
| tree | feeb8acc35333660652d9fe1052d6ea536d43bbf /src/LivingVillage.Headless/Program.fs | |
| parent | 4627a29302aa780ba8de1e537a869650601debc3 (diff) | |
| download | living-village-2f46d1789088eb165271bd915844376aa5a84768.tar.gz | |
feat: M2b NPC 记忆与行为稳定化 — 环形记忆(≤64: tick/kind/valence) + 行动粘性(最小600tick, urgent<20豁免) + 夜间(22-6)sleep权重x3 + Desktop蓝色NPC与标题行动名 + headless摘要(mem_count/last_valence/行动平均持续/昼夜sleep占比) + 粘性与valence测试
Diffstat (limited to 'src/LivingVillage.Headless/Program.fs')
| -rw-r--r-- | src/LivingVillage.Headless/Program.fs | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/src/LivingVillage.Headless/Program.fs b/src/LivingVillage.Headless/Program.fs index 8c2b6d6..6f86f45 100644 --- a/src/LivingVillage.Headless/Program.fs +++ b/src/LivingVillage.Headless/Program.fs @@ -57,6 +57,14 @@ let runSimulation (days: int64) (seed: uint64) : int = let mutable nonFinite = 0L let mutable outOfBounds = 0L let mutable t = 0L + let mutable lastAction = (List.head world.Npcs).Mind.Action + let mutable lastStart = 0L + let mutable switchCount = 0L + let mutable switchDurSum = 0L + let mutable sleepNight = 0L + let mutable sleepDay = 0L + let mutable nightTicks = 0L + let mutable dayTicks = 0L while t < totalTicks do let d, input = if t < driver.Until then driver, driver.Input @@ -66,21 +74,48 @@ let runSimulation (days: int64) (seed: uint64) : int = driver <- d world <- Sim.step { Input = input } world t <- t + 1L + let nightNow = Sim.isNightTick t + if nightNow then nightTicks <- nightTicks + 1L else dayTicks <- dayTicks + 1L + let head = List.head world.Npcs + if head.Mind.Action = Sleep then + if nightNow then sleepNight <- sleepNight + 1L else sleepDay <- sleepDay + 1L + if head.Mind.Action <> lastAction then + switchCount <- switchCount + 1L + switchDurSum <- switchDurSum + (t - lastStart) + lastStart <- t + lastAction <- head.Mind.Action let p = world.Avatar.Pos if Single.IsNaN p.X || Single.IsNaN p.Y || Single.IsInfinity p.X || Single.IsInfinity p.Y then nonFinite <- nonFinite + 1L if p.X < 0.0f || p.X > maxX || p.Y < 0.0f || p.Y > maxY then outOfBounds <- outOfBounds + 1L if t % 2000L = 0L then let day = float t / float ticksPerDay - let mem = GC.GetTotalMemory(true) + let memTotal = GC.GetTotalMemory(true) for npc in world.Npcs do let n = npc.Mind.Needs let p' = npc.Pos - printfn "npc=%A tick=%d day=%.4f pos=(%.1f,%.1f) hunger=%.2f energy=%.2f social=%.2f money=%.2f action=%s" - npc.Id t day p'.X p'.Y n.Hunger n.Energy n.Social n.Money (actionName npc.Mind.Action) + let memCount = List.length npc.Mind.Memory + let lastValence = + match List.tryHead npc.Mind.Memory with + | Some e -> e.Valence + | None -> 0.0f + printfn "npc=%A tick=%d day=%.4f pos=(%.1f,%.1f) hunger=%.2f energy=%.2f social=%.2f money=%.2f action=%s mem_count=%d last_valence=%.2f" + npc.Id t day p'.X p'.Y n.Hunger n.Energy n.Social n.Money (actionName npc.Mind.Action) memCount lastValence if t % 1000L = 0L && t % 2000L <> 0L then let day = float t / float ticksPerDay printfn "tick=%d time=%.4fs day=%.4f pos=(%.1f,%.1f) rng=%016x" t world.Time day p.X p.Y world.Rng.State + let segments = switchCount + 1L + let avgActionTicks = float (switchDurSum + (totalTicks - lastStart)) / float segments + let nightPct = if nightTicks > 0L then 100.0 * float sleepNight / float nightTicks else 0.0 + let dayPct = if dayTicks > 0L then 100.0 * float sleepDay / float dayTicks else 0.0 + let npc0 = List.head world.Npcs + let memCount = List.length npc0.Mind.Memory + let lastValence = + match List.tryHead npc0.Mind.Memory with + | Some e -> e.Valence + | None -> 0.0f + printfn "npc=%A action_switches=%d avg_action_ticks=%.1f sleep_night_ticks=%d sleep_day_ticks=%d sleep_night_pct=%.2f sleep_day_pct=%.2f mem_count=%d last_valence=%.2f" + npc0.Id switchCount avgActionTicks sleepNight sleepDay nightPct dayPct memCount lastValence printfn "done tick=%d non-finite=%d out-of-bounds=%d" world.Tick nonFinite outOfBounds if nonFinite > 0L || outOfBounds > 0L then 1 else 0 |
