diff options
Diffstat (limited to 'src/LivingVillage.Desktop.Tests/MapGenTests.fs')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/MapGenTests.fs | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop.Tests/MapGenTests.fs b/src/LivingVillage.Desktop.Tests/MapGenTests.fs index 4454b33..b0b58e7 100644 --- a/src/LivingVillage.Desktop.Tests/MapGenTests.fs +++ b/src/LivingVillage.Desktop.Tests/MapGenTests.fs @@ -18,6 +18,24 @@ type MapGenTests () = let checksum (map: MapGen.Result) : int64 = map.Tiles |> Array.mapi (fun i v -> int64 i * int64 (v + 1)) |> Array.sum + let waterRunsInColumn (map: MapGen.Result) (x: int) : int list = + let runs = ResizeArray<int>() + let mutable run = 0 + for y in 0 .. map.Height - 1 do + if map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.Water then + run <- run + 1 + elif run > 0 then + runs.Add run + run <- 0 + if run > 0 then runs.Add run + List.ofSeq runs + + let waterNeighbourCount (map: MapGen.Result) (x: int) (y: int) : int = + [ (1, 0); (-1, 0); (0, 1); (0, -1) ] + |> List.sumBy (fun (dx, dy) -> + let nx, ny = x + dx, y + dy + if nx >= 0 && nx < map.Width && ny >= 0 && ny < map.Height && map.Tiles.[ny * map.Width + nx] = int MapGen.GroundTile.Water then 1 else 0) + [<TestMethod>] member _.SameSeedGeneratesByteIdenticalTerrain () = let a = MapGen.generateWithSize 64 48 (uint64 4242) @@ -71,6 +89,64 @@ type MapGenTests () = Assert.AreEqual<int>(1280 / Sim.tilePixels + 1, ox1) Assert.AreEqual<int>(720 / Sim.tilePixels + 1, oy1) + // ---- P20 第二步:河道连续性 + 桥/路/建筑 + 交通可达 ---- + + [<TestMethod>] + member _.RiversAreContinuousWithoutGapsOrIsolatedTiles () = + let map = MapGen.generateWithSize 256 192 (uint64 4242) + Assert.IsTrue(map.Rivers.Length >= 1, "at least one river band") + let minWidth = map.Rivers |> List.map (fun river -> river.Width) |> List.min + Assert.IsTrue(minWidth >= 3, "river width lower bound") + for x in 1 .. map.Width - 2 do + let runs = waterRunsInColumn map x + if runs.Length <> map.Rivers.Length then + Assert.Fail(sprintf "column %d must hold exactly %d contiguous runs, saw %d" x map.Rivers.Length runs.Length) + for run in runs do + Assert.IsTrue(run >= minWidth, sprintf "column %d has a run of %d < min width %d" x run minWidth) + for y in 0 .. map.Height - 1 do + for x in 0 .. map.Width - 1 do + if map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.Water then + Assert.IsTrue(waterNeighbourCount map x y >= 2, sprintf "water tile (%d,%d) is isolated" x y) + + [<TestMethod>] + member _.StructuresContainBridgesRoadsAndBuildingsAlongRivers () = + let map = MapGen.generateWithSize 256 192 (uint64 4242) + Assert.IsTrue(map.Bridges.Length >= map.Rivers.Length, "at least one bridge per river") + Assert.IsTrue(map.Paths.Length > 0, "stone road network exists") + Assert.IsTrue(map.Buildings.Length >= 4, "at least four riverside building blocks") + for building in map.Buildings do + Assert.IsTrue(MapGen.isWalkable map building.DoorX building.DoorY, sprintf "door (%d,%d) must be walkable" building.DoorX building.DoorY) + let nearWater = + [ for y in max 0 (building.Top - 12) .. min (map.Height - 1) (building.Top + building.Height + 12) do + for x in max 0 (building.Left - 12) .. min (map.Width - 1) (building.Left + building.Width + 12) -> + map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.Water ] + |> List.exists id + Assert.IsTrue(nearWater, "building block must sit along a river") + + [<TestMethod>] + member _.BridgesKeepBothRiverBanksReachableFromSpawns () = + let map = MapGen.generateWithSize 256 192 (uint64 4242) + let startX, startY = map.Spawns.Head + let visited = MapGen.floodFill map startX startY + for (x, y) in map.Spawns do + Assert.IsTrue(visited.[y * map.Width + x], sprintf "spawn (%d,%d) unreachable" x y) + for building in map.Buildings do + Assert.IsTrue(visited.[building.DoorY * map.Width + building.DoorX], "building door unreachable via bridge/road") + for (x, y) in map.Bridges do + Assert.IsTrue(visited.[y * map.Width + x], sprintf "bridge tile (%d,%d) unreachable" x y) + Assert.IsTrue(map.BridgeCrossingsOk, "each bridge must connect both river banks") + + [<TestMethod>] + member _.StructuresAreDeterministicAcrossRuns () = + let a = MapGen.generateWithSize 256 192 (uint64 4242) + let b = MapGen.generateWithSize 256 192 (uint64 4242) + Assert.IsTrue(a.Rivers = b.Rivers) + Assert.IsTrue(a.Bridges = b.Bridges) + Assert.IsTrue(a.Paths = b.Paths) + Assert.IsTrue(a.Buildings = b.Buildings) + let c = MapGen.generateWithSize 256 192 (uint64 7) + Assert.IsTrue(a.Buildings <> c.Buildings || a.Bridges <> c.Bridges, "different seeds must relocate structures") + [<TestMethod>] member _.VisibleRangeClampsAtLegacyMapEdges () = let x0, y0, x1, y1 = MapGen.visibleTileRange 64 48 0 0 2048 1536 |
