From 4627a29302aa780ba8de1e537a869650601debc3 Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Sat, 19 Sep 2026 02:24:26 +0800 Subject: feat: M2a NPC 心智基础 — Needs 衰减 + Personality(seed) + 决策层v1(需求缺口×性格权重) + 四语义点直线移动 + headless NPC 摘要 + 对拍/衰减测试 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/LivingVillage.Kernel.Tests/DeterminismTests.fs | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'src/LivingVillage.Kernel.Tests') 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' + + [] + member _.NpcDecisionTraceIsTickByTickDeterministic () = + let runNpc (seed: uint64) (ticks: int64) : World list = + let mutable world = Sim.initialWorld seed + let acc = ResizeArray (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) + + [] + 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 20000 + let seqB = ResizeArray 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") -- cgit v1.2.3