summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-19 02:24:26 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-19 02:24:26 +0800
commit4627a29302aa780ba8de1e537a869650601debc3 (patch)
treefe9639ce194298372bb59a80244698cbee7811c0 /src/LivingVillage.Kernel.Tests/DeterminismTests.fs
parent59458d149d7cecf73e708faa6d9e6db2bcd89dfd (diff)
downloadliving-village-4627a29302aa780ba8de1e537a869650601debc3.tar.gz
feat: M2a NPC 心智基础 — Needs 衰减 + Personality(seed) + 决策层v1(需求缺口×性格权重) + 四语义点直线移动 + headless NPC 摘要 + 对拍/衰减测试
Diffstat (limited to 'src/LivingVillage.Kernel.Tests/DeterminismTests.fs')
-rw-r--r--src/LivingVillage.Kernel.Tests/DeterminismTests.fs47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/LivingVillage.Kernel.Tests/DeterminismTests.fs b/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
index 2e2663b..aba794e 100644
--- a/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
+++ b/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
@@ -133,3 +133,50 @@ type DeterminismTests () =
let f, rng' = Rng.nextFloat32 rng
if f < 0.0f || f >= 1.0f then Assert.Fail($"out of range: {f}")
rng <- rng'
+
+ [<TestMethod>]
+ member _.NpcDecisionTraceIsTickByTickDeterministic () =
+ let runNpc (seed: uint64) (ticks: int64) : World list =
+ let mutable world = Sim.initialWorld seed
+ let acc = ResizeArray<World> (int ticks + 1)
+ acc.Add world
+ let zero = { Input = { MoveX = 0.0f; MoveY = 0.0f } }
+ for _ in 1L .. ticks do
+ world <- Sim.step zero world
+ acc.Add world
+ List.ofSeq acc
+ let a = runNpc 42UL 20000L
+ let b = runNpc 42UL 20000L
+ Assert.IsTrue(20001 = List.length a)
+ CollectionAssert.AreEqual(Array.ofList a, Array.ofList b)
+
+ [<TestMethod>]
+ member _.NpcNeedsDecayOverTimeAndActionsDifferAcrossSeeds () =
+ let w0 = Sim.initialWorld 42UL
+ let npc0 = List.exactlyOne w0.Npcs
+ let zero = { Input = { MoveX = 0.0f; MoveY = 0.0f } }
+ let mutable w = w0
+ for _ in 1 .. 500 do
+ w <- Sim.step zero w
+ let npc1 = List.exactlyOne w.Npcs
+ let n0 = npc0.Mind.Needs
+ let n1 = npc1.Mind.Needs
+ Assert.IsTrue(n1.Hunger < n0.Hunger, "hunger must decay")
+ Assert.IsTrue(n1.Energy < n0.Energy, "energy must decay")
+ Assert.IsTrue(n1.Social < n0.Social, "social must decay")
+ Assert.IsTrue(n1.Money < n0.Money, "money must decay")
+ let wa = Sim.initialWorld 42UL
+ let wb = Sim.initialWorld 43UL
+ Assert.IsTrue(wa.Npcs.[0].Mind.Personality <> wb.Npcs.[0].Mind.Personality,
+ "personalities must differ across seeds")
+ let mutable ta = wa
+ let mutable tb = wb
+ let seqA = ResizeArray<NpcActionKind> 20000
+ let seqB = ResizeArray<NpcActionKind> 20000
+ for _ in 1 .. 20000 do
+ ta <- Sim.step zero ta
+ tb <- Sim.step zero tb
+ seqA.Add ta.Npcs.[0].Mind.Action
+ seqB.Add tb.Npcs.[0].Mind.Action
+ if Seq.compareWith compare seqA seqB = 0 then
+ Assert.Fail("npc action sequence must diverge across seeds")