summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 08:35:11 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 08:35:11 +0800
commit09310370365220bc9b9c560d8947cd7abc36d14f (patch)
treece638afd60d38461d20cf725549c7b12b7eed85b /src/LivingVillage.Desktop
parent91d3e7dc95981f92f56a82c19334b5c26d52c226 (diff)
downloadliving-village-09310370365220bc9b9c560d8947cd7abc36d14f.tar.gz
feat(mapgen): 512x384 沿河民居加密到 18 座且门全部可达(P24)
- Params.ExtraRiversideHouses(默认 0);paramsForSize 仅对 >256x192 设为 10, 从既有路网泊松散布 3x2 民居并接门入网(structureRng 确定性),512x384 共 18 座。 - 64x48/256x192 仍 4 座、checksum 6042052/1284656962 不变(新增用例锁定)。 - 新增 512 民居数量/可达/确定性用例;Desktop 130 -> 134。
Diffstat (limited to 'src/LivingVillage.Desktop')
-rw-r--r--src/LivingVillage.Desktop/MapGen.fs55
1 files changed, 52 insertions, 3 deletions
diff --git a/src/LivingVillage.Desktop/MapGen.fs b/src/LivingVillage.Desktop/MapGen.fs
index ce9bccf..1e63ed2 100644
--- a/src/LivingVillage.Desktop/MapGen.fs
+++ b/src/LivingVillage.Desktop/MapGen.fs
@@ -30,7 +30,9 @@ module MapGen =
RiverWidth: int
CoreSide: int
SpawnColumns: int
- SpawnRows: int }
+ SpawnRows: int
+ /// P24:大图额外沿河民居数量(沿现有路网泊松散布)。默认 0,64x48/256x192 不受影响。
+ ExtraRiversideHouses: int }
/// P20 第二步:一条贯穿全图的东西向河道(每列恰好一段,宽度下限 RiverWidth)。
type River =
@@ -70,16 +72,20 @@ module MapGen =
RiverWidth = 3
CoreSide = 14
SpawnColumns = 5
- SpawnRows = 6 }
+ SpawnRows = 6
+ ExtraRiversideHouses = 0 }
/// P23 尺寸自适应参数:河道数量随高度增长(约每 96 行一条),其余沿用默认。
/// 64x48 / 256x192 仍得到 2 条河道,与既有输出逐字节一致;512x384 得到 4 条。
+ /// P24:仅对大于 256x192 的图追加沿河民居(泊松散布),保证既有 checksum 不变。
let paramsForSize (width: int) (height: int) (seed: uint64) : Params =
let base_ = defaultParams seed
+ let large = width > 256 || height > 192
{ base_ with
Width = width
Height = height
- RiverCount = max base_.RiverCount (max 1 (height / 96)) }
+ RiverCount = max base_.RiverCount (max 1 (height / 96))
+ ExtraRiversideHouses = (if large then 10 else 0) }
// ---- splitmix64 与 value noise(无外部依赖、无时钟) ----
@@ -275,6 +281,49 @@ module MapGen =
buildings <- building :: buildings
addPath building.DoorX building.DoorY
+ // 5b) P24:大图沿河民居加密。从既有路网瓦片出发,向四邻定向落位 3x2 白墙黛瓦民居,
+ // 门开向相邻路格并接入路网(BFS 可达);仅在 ExtraRiversideHouses>0 时执行,
+ // 且只在核心区外的草地落位,故 64x48/256x192 输出逐字节不变。
+ 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
+ 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) =
+ buildings
+ |> List.exists (fun b ->
+ left < b.Left + b.Width && b.Left < left + 3
+ && top < b.Top + b.Height && b.Top < top + 2)
+ let directions = [ (0, -1); (0, 1); (-1, 0); (1, 0) ]
+ let mutable extraPlaced = 0
+ let mutable extraAttempts = 0
+ let maxAttempts = p.ExtraRiversideHouses * 400
+ while extraPlaced < p.ExtraRiversideHouses && extraAttempts < maxAttempts && paths.Length > 0 do
+ extraAttempts <- extraAttempts + 1
+ let nextState, raw = splitmix structureRng
+ structureRng <- nextState
+ 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 doorX = pathX + dirX
+ let doorY = pathY + dirY
+ let left = doorX - 1
+ let top = doorY - 1
+ if footprintFree left top && not (overlaps left top) then
+ let building =
+ { Left = left
+ Top = top
+ Width = 3
+ Height = 2
+ DoorX = doorX
+ DoorY = doorY }
+ buildings <- building :: buildings
+ addPath building.DoorX building.DoorY
+ extraPlaced <- extraPlaced + 1
+
// 6) 30 个 spawn:核心区内的规则网格。
let sc = max 2 p.SpawnColumns
let sr = max 2 p.SpawnRows