summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-19 03:20:56 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-19 03:20:56 +0800
commit4993bc37cb00356b83cb4f8a2e4a92fc2fe77922 (patch)
tree5b08f5fde9c420c30a588c113b78c421f828d0ab /src/LivingVillage.Kernel.Tests/DeterminismTests.fs
parent2f46d1789088eb165271bd915844376aa5a84768 (diff)
downloadliving-village-4993bc37cb00356b83cb4f8a2e4a92fc2fe77922.tar.gz
feat: M3a 30 NPC 社区 — initialWorldN 网格布局 + Wander 寻伴闲聊 v1(ChatInit 事件队列 + 双方 Chatted 记忆 valence+0.3 + Social+40) + headless 聊天统计; 修复 clamp 泛型比较装箱(30npc 1天 63.5s→15.7s, 输出逐字节一致) + M3a 对拍/闲聊对称测试
Diffstat (limited to 'src/LivingVillage.Kernel.Tests/DeterminismTests.fs')
-rw-r--r--src/LivingVillage.Kernel.Tests/DeterminismTests.fs60
1 files changed, 58 insertions, 2 deletions
diff --git a/src/LivingVillage.Kernel.Tests/DeterminismTests.fs b/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
index 0e1766e..972ce19 100644
--- a/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
+++ b/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
@@ -153,12 +153,12 @@ type DeterminismTests () =
[<TestMethod>]
member _.NpcNeedsDecayOverTimeAndActionsDifferAcrossSeeds () =
let w0 = Sim.initialWorld 42UL
- let npc0 = List.exactlyOne w0.Npcs
+ let npc0 = w0.Npcs |> Array.exactlyOne
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 npc1 = w.Npcs |> Array.exactlyOne
let n0 = npc0.Mind.Needs
let n1 = npc1.Mind.Needs
Assert.IsTrue(n1.Hunger < n0.Hunger, "hunger must decay")
@@ -241,3 +241,59 @@ type DeterminismTests () =
| None -> ()
Assert.IsTrue(sawEmpty, "memory must start empty")
Assert.IsTrue(sawEvent, "expected a valence memory event within 6000 ticks")
+
+ [<TestMethod>]
+ member _.Npc30SameSeedTracesAreTickByTickEqualAndEventsDrain () =
+ let zero = { Input = { MoveX = 0.0f; MoveY = 0.0f } }
+ let mutable a = Sim.initialWorldN 42UL 30
+ let mutable b = Sim.initialWorldN 42UL 30
+ for t in 1L .. 30000L do
+ a <- Sim.step zero a
+ b <- Sim.step zero b
+ if a <> b then Assert.Fail($"30-npc worlds diverged at tick {t}")
+ if not a.Events.IsEmpty then Assert.Fail($"Events queue not drained at tick {t}")
+ Assert.IsTrue(30000L = a.Tick)
+
+ [<TestMethod>]
+ member _.Npc30ChatsRecordSymmetricPositiveMemories () =
+ let zero = { Input = { MoveX = 0.0f; MoveY = 0.0f } }
+ let mutable w = Sim.initialWorldN 42UL 30
+ let mutable prev0 = w.Npcs.[0].Mind.Action
+ let mutable symmetryChecked = false
+ let mutable chatObserved = 0
+ let total = 600000L
+ for _ in 1L .. total do
+ w <- Sim.step zero w
+ for npc in w.Npcs do
+ if npc.Mind.Action = Chat then chatObserved <- chatObserved + 1
+ let npc0 = w.Npcs.[0]
+ if not symmetryChecked && npc0.Mind.Action = Chat && prev0 <> Chat then
+ match List.tryHead npc0.Mind.Memory with
+ | Some entry ->
+ match entry.Kind with
+ | Chatted partner ->
+ if partner = npc0.Id then Assert.Fail("chat partner must differ from self")
+ let partnerNpc = w.Npcs |> Array.find (fun n -> n.Id = partner)
+ let partnerAlsoChatted =
+ partnerNpc.Mind.Memory
+ |> List.exists (fun e -> match e.Kind with Chatted p -> p = npc0.Id | _ -> false)
+ if not partnerAlsoChatted then
+ Assert.Fail("chat memory must be recorded symmetrically for both partners")
+ symmetryChecked <- true
+ | _ -> Assert.Fail($"chat start must record a Chatted memory, got {entry.Kind}")
+ | None -> Assert.Fail("chat start must record a Chatted memory")
+ prev0 <- npc0.Mind.Action
+ Assert.IsTrue(symmetryChecked, "expected npc0 to start at least one chat within the run")
+ Assert.IsTrue(chatObserved > 0, "expected some NPC to be chatting during the run")
+ let mutable chattedMemories = 0
+ for npc in w.Npcs do
+ Assert.IsTrue(npc.Mind.Memory.Length <= Sim.memoryCapacity, "memory exceeds ring capacity")
+ for e in npc.Mind.Memory do
+ match e.Kind with
+ | Chatted partner ->
+ chattedMemories <- chattedMemories + 1
+ if partner = npc.Id then Assert.Fail("chat partner must differ from self")
+ if e.Valence <> Sim.chatValence then
+ Assert.Fail($"chat valence must be {Sim.chatValence}, got {e.Valence}")
+ | _ -> ()
+ Assert.IsTrue(chattedMemories > 0, "expected Chatted memories after the run")