module Snake.Tests.M04Spawn open Expecto open Snake open Snake.Model open Snake.Tests.Fixtures // 3x2 board, one-cell snake, about to eat the apple at (1,0) let private eating: GameState = { Width = 3 Height = 2 Snake = [ { X = 0; Y = 0 } ] Dir = Right NextDir = Right Apple = Some { X = 1; Y = 0 } Seed = 0u Score = 0 Status = Playing Frame = 0 } [] let tests = testList "M04 Spawn" [ yield! fixtureTests "m04-free-cells" "freeCells" (fun c -> Expect.equal (Spawn.freeCells (gameState (arg 0 c))) (list point (expected c)) "freeCells") yield! fixtureTests "m04-spawn" "spawnApple" (fun c -> Expect.equal (Spawn.spawnApple (gameState (arg 0 c))) (gameState (expected c)) "spawnApple") yield! fixtureTests "m04-new-game" "newGame" (fun c -> Expect.equal (Spawn.newGame (u32 (arg 0 c))) (gameState (expected c)) "newGame") yield! fixtureTests "m04-tick" "tick" (fun c -> Expect.equal (Spawn.tick (gameState (arg 0 c))) (gameState (expected c)) "tick") testCase "tick: eating the apple spawns a new one in the same step" (fun () -> // snake becomes (1,0),(0,0); free cells are (2,0),(0,1),(1,1),(2,1); seed 0 draws 1144304738 % 4 = 2 -> (1,1) Expect.equal (Spawn.tick eating) { eating with Snake = [ { X = 1; Y = 0 }; { X = 0; Y = 0 } ] Apple = Some { X = 1; Y = 1 } Score = 1 Seed = 1831565813u } "tick") testCase "tick is spawnApple after advance" (fun () -> Expect.equal (Spawn.tick eating) (Spawn.spawnApple (Rules.advance eating)) "tick") testCase "tick leaves the seed alone when no apple needs spawning" (fun () -> Expect.equal (Spawn.tick { eating with Apple = Some { X = 2; Y = 1 } }).Seed 0u "seed") testCase "newGame is reproducible: same seed, same game" (fun () -> Expect.equal (Spawn.newGame 42u) (Spawn.newGame 42u) "newGame 42") ]