From 4c776629f373c0afe2c72ad8ec4cc30e5d39dba1 Mon Sep 17 00:00:00 2001 From: Aotumuri Date: Thu, 3 Apr 2025 02:22:37 +0900 Subject: [PATCH] Optimize Water Tile Distance Calculation with BFS (Manhattan Distance) (#396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Replaced with BFS from shoreline tiles to propagate Manhattan distances efficiently in O(W) time. I’ve confirmed that the results match the previous implementation, but please double-check on your end as well just to be safe. I’d also like to get input from aPuddle. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: aotumuri --- src/scripts/TerrainMapGenerator.ts | 56 +++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/scripts/TerrainMapGenerator.ts b/src/scripts/TerrainMapGenerator.ts index 6ee6b74d9..1154fd16c 100644 --- a/src/scripts/TerrainMapGenerator.ts +++ b/src/scripts/TerrainMapGenerator.ts @@ -120,19 +120,49 @@ function processShore(map: Terrain[][]): Coord[] { } function processDistToLand(shorelineWaters: Coord[], map: Terrain[][]) { - console.log("Setting Water tiles magnitude = distance from land"); - for (let x = 0; x < map.length; x++) { - for (let y = 0; y < map[0].length; y++) { - const tile = map[x][y]; - if (tile.type == TerrainType.Water) { - if (shorelineWaters.some((coord) => coord.x == x && coord.y == y)) { - tile.magnitude = 0; - } else { - const dist = shorelineWaters.map( - (coord) => Math.abs(x - coord.x) + Math.abs(y - coord.y), - ); - tile.magnitude = Math.min(...dist); - } + console.log( + "Setting Water tiles magnitude = Manhattan distance from nearest land", + ); + + const width = map.length; + const height = map[0].length; + + const visited = Array.from({ length: width }, () => + Array(height).fill(false), + ); + const queue: { x: number; y: number; dist: number }[] = []; + + for (const { x, y } of shorelineWaters) { + queue.push({ x, y, dist: 0 }); + visited[x][y] = true; + map[x][y].magnitude = 0; + } + + const directions = [ + { dx: 0, dy: 1 }, + { dx: 1, dy: 0 }, + { dx: 0, dy: -1 }, + { dx: -1, dy: 0 }, + ]; + + while (queue.length > 0) { + const { x, y, dist } = queue.shift()!; + + for (const { dx, dy } of directions) { + const nx = x + dx; + const ny = y + dy; + + if ( + nx >= 0 && + ny >= 0 && + nx < width && + ny < height && + !visited[nx][ny] && + map[nx][ny].type === TerrainType.Water + ) { + visited[nx][ny] = true; + map[nx][ny].magnitude = dist + 1; + queue.push({ x: nx, y: ny, dist: dist + 1 }); } } }