summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel.Tests/M6aTests.fs
blob: 8a318be8dd4ed9b6240e40f1d862fd36dae61a49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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<World>

    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<World>
        | ChatRejected (failure, _) -> Assert.Fail($"chat rejected: {failure}"); Unchecked.defaultof<World>

    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<World>

    let advance (inputs: Input list) (world: World) : World =
        inputs |> List.fold (fun current input -> Sim.step { Input = input } current) world

[<TestClass>]
type M6aTests () =

    [<TestMethod>]
    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<string>(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<string>(WorldSave.save continued, WorldSave.save restoredContinued)
            Assert.AreEqual<int64>(world.Tick, restored.Tick)
            Assert.AreEqual<uint64>(world.Rng.State, restored.Rng.State)
            Assert.IsFalse(restored.Events.IsEmpty)
            Assert.IsFalse(restored.Rumors.IsEmpty)
            Assert.IsFalse(restored.Annals.IsEmpty)
            Assert.AreEqual<Avatar>(world.Avatar, restored.Avatar)
            CollectionAssert.AreEqual(world.Npcs, restored.Npcs)

    [<TestMethod>]
    member _.SimulationClockSupportsPauseAndRequestedSpeeds () =
        let initial = SimulationControl.initial
        Assert.AreEqual<int>(1, SimulationControl.stepsPerFrame initial)
        Assert.AreEqual<int>(2, SimulationControl.stepsPerFrame (SimulationControl.setSpeed TwoX initial))
        Assert.AreEqual<int>(5, SimulationControl.stepsPerFrame (SimulationControl.setSpeed FiveX initial))
        let paused = SimulationControl.togglePause initial
        Assert.IsTrue(paused.Paused)
        Assert.AreEqual<int>(0, SimulationControl.stepsPerFrame paused)
        let resumed = SimulationControl.togglePause paused
        Assert.IsFalse(resumed.Paused)
        Assert.AreEqual<SimulationSpeed>(OneX, resumed.Speed)

    [<TestMethod>]
    member _.ConfiguredLegacyStepCountsRemainExactUntilManualSpeedSelection () =
        let control, legacySteps = SimulationControl.initialForConfiguredSteps 7
        Assert.AreEqual<int option>(Some 7, legacySteps)
        Assert.AreEqual<int>(7, SimulationControl.stepsPerFrameWithLegacy legacySteps control)
        Assert.AreEqual<int>(0, SimulationControl.stepsPerFrameWithLegacy legacySteps (SimulationControl.togglePause control))
        let manuallySelected = SimulationControl.setSpeed TwoX control
        Assert.AreEqual<int>(2, SimulationControl.stepsPerFrameWithLegacy None manuallySelected)