summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/LivingVillage.Desktop.Tests/MapGenTests.fs15
-rw-r--r--src/LivingVillage.Desktop/MapGen.fs23
2 files changed, 29 insertions, 9 deletions
diff --git a/src/LivingVillage.Desktop.Tests/MapGenTests.fs b/src/LivingVillage.Desktop.Tests/MapGenTests.fs
index 6486dd7..b737707 100644
--- a/src/LivingVillage.Desktop.Tests/MapGenTests.fs
+++ b/src/LivingVillage.Desktop.Tests/MapGenTests.fs
@@ -256,6 +256,21 @@ type MapGenTests () =
Assert.IsTrue(a.Buildings = b.Buildings)
Assert.AreEqual<string>(MapGen.serialize a, MapGen.serialize b)
+ /// P28:512 沿河民居由 10 -> 16 增密(+6),并出现 2/3/4 三档宽度(附属小筑/民居/大宅),
+ /// 形成聚落层次;默认图仍为 0,不消耗 RNG,故 64/256 checksum 锁定不变。
+ [<TestMethod>]
+ member _.LargeMapHouseDensityHierarchyOnlyGrowsLargeMaps () =
+ Assert.AreEqual<int>(16, (MapGen.paramsForSize 512 384 (uint64 1)).ExtraRiversideHouses)
+ Assert.AreEqual<int>(0, (MapGen.paramsForSize 64 48 (uint64 1)).ExtraRiversideHouses)
+ Assert.AreEqual<int>(0, (MapGen.paramsForSize 256 192 (uint64 1)).ExtraRiversideHouses)
+ let map = MapGen.generateWithSize 512 384 (uint64 4242)
+ Assert.IsTrue(map.Buildings.Length >= 22, sprintf "P28 512 must place >=22 houses, saw %d" map.Buildings.Length)
+ let widths = map.Buildings |> List.map (fun b -> b.Width) |> Set.ofList
+ Assert.IsTrue(widths.Contains 2, "outbuilding width 2 must appear")
+ Assert.IsTrue(widths.Contains 3, "house width 3 must appear")
+ Assert.IsTrue(widths.Contains 4, "hall width 4 must appear")
+ Assert.AreEqual<int>(24, map.Buildings.Length)
+
[<TestMethod>]
member _.DefaultSizeHouseCountUnchanged () =
Assert.AreEqual<int>(4, (MapGen.generateWithSize 64 48 (uint64 4242)).Buildings.Length)
diff --git a/src/LivingVillage.Desktop/MapGen.fs b/src/LivingVillage.Desktop/MapGen.fs
index ce9fb3a..3705635 100644
--- a/src/LivingVillage.Desktop/MapGen.fs
+++ b/src/LivingVillage.Desktop/MapGen.fs
@@ -97,6 +97,7 @@ module MapGen =
/// P23 尺寸自适应参数:河道数量随高度增长(约每 96 行一条),其余沿用默认。
/// 64x48 / 256x192 仍得到 2 条河道,与既有输出逐字节一致;512x384 得到 4 条。
/// P24:仅对大于 256x192 的图追加沿河民居(泊松散布),保证既有 checksum 不变。
+ /// P28:大图沿河民居由 10 增至 16(+6 座,宽度 2/3/4 变化),默认图仍为 0、不消耗 RNG。
let paramsForSize (width: int) (height: int) (seed: uint64) : Params =
let base_ = defaultParams seed
let large = width > 256 || height > 192
@@ -104,7 +105,7 @@ module MapGen =
Width = width
Height = height
RiverCount = max base_.RiverCount (max 1 (height / 96))
- ExtraRiversideHouses = (if large then 10 else 0)
+ ExtraRiversideHouses = (if large then 16 else 0)
DecorativeStones = not large
RiverDecorations = large }
@@ -307,18 +308,20 @@ module MapGen =
// 5b) P24:大图沿河民居加密。从既有路网瓦片出发,向四邻定向落位 3x2 白墙黛瓦民居,
// 门开向相邻路格并接入路网(BFS 可达);仅在 ExtraRiversideHouses>0 时执行,
// 且只在核心区外的草地落位,故 64x48/256x192 输出逐字节不变。
+ // P28:宽度按 2/3/4 加权变化(2=附属小筑、4=大宅),形成聚落层次而非等距重复;
+ // 数量 10 -> 16(沿河再增 6 座)。仍只在大图分支执行,默认图 RNG 不消耗,checksum 不变。
if p.ExtraRiversideHouses > 0 then
- let footprintFree (left: int) (top: int) =
- left >= 1 && left + 2 <= w - 2 && top >= 1 && top + 1 <= h - 2
- && [ for dx in 0 .. 2 do
+ let footprintFree (left: int) (top: int) (width: int) =
+ left >= 1 && left + width - 1 <= w - 2 && top >= 1 && top + 1 <= h - 2
+ && [ for dx in 0 .. width - 1 do
for dy in 0 .. 1 -> (left + dx, top + dy) ]
|> List.forall (fun (x, y) ->
tiles.[idx x y] = int GroundTile.Grass
&& not (inCore x y))
- let overlaps (left: int) (top: int) =
+ let overlaps (left: int) (top: int) (width: int) =
buildings
|> List.exists (fun b ->
- left < b.Left + b.Width && b.Left < left + 3
+ left < b.Left + b.Width && b.Left < left + width
&& top < b.Top + b.Height && b.Top < top + 2)
let directions = [ (0, -1); (0, 1); (-1, 0); (1, 0) ]
let mutable extraPlaced = 0
@@ -331,15 +334,17 @@ module MapGen =
if paths.Length > 0 then
let pathX, pathY = List.item (int (raw % uint64 paths.Length)) paths
let dirX, dirY = directions.[int ((raw >>> 32) % 4UL)]
+ let widthRoll = int ((raw >>> 40) % 10UL)
+ let buildingWidth = if widthRoll < 5 then 3 elif widthRoll < 8 then 2 else 4
let doorX = pathX + dirX
let doorY = pathY + dirY
- let left = doorX - 1
+ let left = doorX - buildingWidth / 2
let top = doorY - 1
- if footprintFree left top && not (overlaps left top) then
+ if footprintFree left top buildingWidth && not (overlaps left top buildingWidth) then
let building =
{ Left = left
Top = top
- Width = 3
+ Width = buildingWidth
Height = 2
DoorX = doorX
DoorY = doorY }