namespace LivingVillage.Kernel.Tests open Microsoft.VisualStudio.TestTools.UnitTesting open LivingVillage.Kernel open LivingVillage.Kernel.Sim module private M6aHarness = let zeroInput = { Input = { MoveX = 0.0f; MoveY = 0.0f } } let atNpc (id: int) (world: World) : World = let npc = world.Npcs.[id] { world with Avatar = { world.Avatar with Pos = npc.Pos } } let readyForChat (world: World) : World = { world with Npcs = world.Npcs |> Array.map (fun npc -> { npc with Mind = { npc.Mind with Action = Wander Target = actionTarget Wander ActionAge = minActionTicks EffectDone = true } }) } let withDialogue (world: World) : World = match Sim.chooseDialogue (NpcId 0) SmallTalk (atNpc 0 world) with | DialogueSucceeded (_, next) -> next | DialogueRejected (failure, _) -> Assert.Fail($"dialogue rejected: {failure}"); Unchecked.defaultof let withChat (world: World) : World = match Sim.chat { Narrator = NpcId 0; Receiver = NpcId 1 } (readyForChat world) with | ChatSucceeded (Some _, next) -> next | ChatSucceeded (None, _) -> Assert.Fail("chat should create a rumor"); Unchecked.defaultof | ChatRejected (failure, _) -> Assert.Fail($"chat rejected: {failure}"); Unchecked.defaultof let withTrade (world: World) : World = match Sim.trade { Buyer = NpcId 0; Seller = NpcId 1; Item = Food; Quantity = 1 } world with | TradeSucceeded next -> next | TradeRejected (failure, _) -> Assert.Fail($"trade rejected: {failure}"); Unchecked.defaultof let advance (inputs: Input list) (world: World) : World = inputs |> List.fold (fun current input -> Sim.step { Input = input } current) world [] type M6aTests () = [] member _.SaveLoadPreservesWorldAndDeterministicContinuation () = let world = Sim.initialWorldN 7UL 4 |> M6aHarness.withDialogue |> M6aHarness.withChat |> M6aHarness.withTrade let encoded = WorldSave.save world match WorldSave.load encoded with | Error failure -> Assert.Fail($"save should load: {failure}") | Ok restored -> Assert.AreEqual(encoded, WorldSave.save restored) let inputs = [ { MoveX = 0.5f; MoveY = -0.25f } { MoveX = 0.0f; MoveY = 0.0f } { MoveX = -1.0f; MoveY = 0.75f } { MoveX = 0.25f; MoveY = 0.0f } ] let continued = M6aHarness.advance inputs world let restoredContinued = M6aHarness.advance inputs restored Assert.AreEqual(WorldSave.save continued, WorldSave.save restoredContinued) Assert.AreEqual(world.Tick, restored.Tick) Assert.AreEqual(world.Rng.State, restored.Rng.State) Assert.IsFalse(restored.Events.IsEmpty) Assert.IsFalse(restored.Rumors.IsEmpty) Assert.IsFalse(restored.Annals.IsEmpty) Assert.AreEqual(world.Avatar, restored.Avatar) CollectionAssert.AreEqual(world.Npcs, restored.Npcs) [] member _.SimulationClockSupportsPauseAndRequestedSpeeds () = let initial = SimulationControl.initial Assert.AreEqual(1, SimulationControl.stepsPerFrame initial) Assert.AreEqual(2, SimulationControl.stepsPerFrame (SimulationControl.setSpeed TwoX initial)) Assert.AreEqual(5, SimulationControl.stepsPerFrame (SimulationControl.setSpeed FiveX initial)) let paused = SimulationControl.togglePause initial Assert.IsTrue(paused.Paused) Assert.AreEqual(0, SimulationControl.stepsPerFrame paused) let resumed = SimulationControl.togglePause paused Assert.IsFalse(resumed.Paused) Assert.AreEqual(OneX, resumed.Speed) [] member _.ConfiguredLegacyStepCountsRemainExactUntilManualSpeedSelection () = let control, legacySteps = SimulationControl.initialForConfiguredSteps 7 Assert.AreEqual(Some 7, legacySteps) Assert.AreEqual(7, SimulationControl.stepsPerFrameWithLegacy legacySteps control) Assert.AreEqual(0, SimulationControl.stepsPerFrameWithLegacy legacySteps (SimulationControl.togglePause control)) let manuallySelected = SimulationControl.setSpeed TwoX control Assert.AreEqual(2, SimulationControl.stepsPerFrameWithLegacy None manuallySelected)