summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Kernel.Tests')
-rw-r--r--src/LivingVillage.Kernel.Tests/DeterminismTests.fs61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/LivingVillage.Kernel.Tests/DeterminismTests.fs b/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
index aba794e..0e1766e 100644
--- a/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
+++ b/src/LivingVillage.Kernel.Tests/DeterminismTests.fs
@@ -180,3 +180,64 @@ type DeterminismTests () =
seqB.Add tb.Npcs.[0].Mind.Action
if Seq.compareWith compare seqA seqB = 0 then
Assert.Fail("npc action sequence must diverge across seeds")
+
+ [<TestMethod>]
+ member _.NpcActionPersistsAtLeastMinTicks () =
+ let zero = { Input = { MoveX = 0.0f; MoveY = 0.0f } }
+ let mutable w = Sim.initialWorld 42UL
+ let total = 30000
+ let mutable current = w.Npcs.[0].Mind.Action
+ let mutable prevNeeds = w.Npcs.[0].Mind.Needs
+ let mutable age = 0
+ let mutable minStickyAge = System.Int32.MaxValue
+ let mutable switches = 0
+ let mutable urgentSwitches = 0
+ for _ in 1 .. total do
+ w <- Sim.step zero w
+ let npc = w.Npcs.[0]
+ let a = npc.Mind.Action
+ if a <> current then
+ let decayed =
+ { Hunger = prevNeeds.Hunger - Sim.hungerDecayPerTick
+ Energy = prevNeeds.Energy - Sim.energyDecayPerTick
+ Social = prevNeeds.Social - Sim.socialDecayPerTick
+ Money = prevNeeds.Money - Sim.moneyDecayPerTick }
+ if Sim.needsUrgent decayed then urgentSwitches <- urgentSwitches + 1
+ else minStickyAge <- min minStickyAge age
+ current <- a
+ age <- 0
+ switches <- switches + 1
+ else
+ age <- age + 1
+ prevNeeds <- npc.Mind.Needs
+ Assert.IsTrue(switches > 0, "expected at least one action switch in 30000 ticks")
+ Assert.IsTrue(minStickyAge >= 600, $"non-urgent action must persist >= 600 ticks, got min {minStickyAge}")
+
+ [<TestMethod>]
+ member _.NpcRecordsValenceMemoryOnActionEffect () =
+ let zero = { Input = { MoveX = 0.0f; MoveY = 0.0f } }
+ let mutable w = Sim.initialWorld 42UL
+ let mutable sawEmpty = false
+ let mutable sawEvent = false
+ for _ in 1 .. 6000 do
+ w <- Sim.step zero w
+ let npc = w.Npcs.[0]
+ if npc.Mind.Memory.IsEmpty then sawEmpty <- true
+ if npc.Mind.Memory.Length > Sim.memoryCapacity then
+ Assert.Fail("memory exceeds ring capacity")
+ match List.tryHead npc.Mind.Memory with
+ | Some e ->
+ let expected =
+ match e.Kind with
+ | Meal -> 0.5f
+ | Rest -> 0.4f
+ | Pay -> 0.2f
+ | Hungry -> -0.4f
+ if e.Valence <> expected then
+ Assert.Fail($"valence/kind mismatch: {e.Kind} -> {e.Valence}")
+ if e.Valence < -1.0f || e.Valence > 1.0f then
+ Assert.Fail($"valence out of [-1,1]: {e.Valence}")
+ if e.Tick >= 1L && e.Tick <= 6000L then sawEvent <- true
+ | None -> ()
+ Assert.IsTrue(sawEmpty, "memory must start empty")
+ Assert.IsTrue(sawEvent, "expected a valence memory event within 6000 ticks")