summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Desktop.Tests')
-rw-r--r--src/LivingVillage.Desktop.Tests/MapGenTests.fs76
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