diff --git a/modules/resample.js b/modules/resample.js index a7496e13..8174a349 100644 --- a/modules/resample.js +++ b/modules/resample.js @@ -109,17 +109,23 @@ window.Resample = (function () { pack.cells.conf = new Uint8Array(pack.cells.i.length); const offset = grid.spacing * 2; + const getCellCost = cellId => { + if (pack.cells.h[cellId] < 20) return Infinity; + return pack.cells.h[cellId]; + }; + pack.rivers = parentMap.pack.rivers .map(river => { const parentPoints = river.points || river.cells.map(cellId => parentMap.pack.cells.p[cellId]); - const points = parentPoints + const newPoints = parentPoints .map(([parentX, parentY]) => { const [x, y] = projection(parentX, parentY); return isInMap(x, y, offset) ? [rn(x, 2), rn(y, 2)] : null; }) .filter(Boolean); - if (points.length < 2) return null; + if (newPoints.length < 2) return null; + const points = addIntermidiatePoints(newPoints, getCellCost); const cells = points.map(point => findCell(...point)); cells.forEach(cellId => { if (pack.cells.r[cellId]) pack.cells.conf[cellId] = 1; @@ -327,6 +333,23 @@ window.Resample = (function () { ); } + // fill gaps in points array with intermidiate points + function addIntermidiatePoints(points, getCellCost) { + const newPoints = []; + + for (let i = 0; i < points.length; i++) { + newPoints.push(points[i]); + if (points[i + 1]) { + const start = findCell(...points[i]); + const exit = findCell(...points[i + 1]); + const pathCells = findPath(start, exit, getCellCost); + if (pathCells) newPoints.push(...pathCells.map(cellId => pack.cells.p[cellId])); + } + } + + return newPoints; + } + function isWater(graph, cellId) { return graph.cells.h[cellId] < 20; } diff --git a/modules/routes-generator.js b/modules/routes-generator.js index 91728e32..318ea7c6 100644 --- a/modules/routes-generator.js +++ b/modules/routes-generator.js @@ -290,8 +290,8 @@ window.Routes = (function () { const connectionModifier = connections.has(`${next}-${neibCellId}`) ? 1 : 2; const burgModifier = cells.burg[neibCellId] ? 1 : 3; - const cellsCost = distanceCost * habitabilityModifier * heightModifier * connectionModifier * burgModifier; - const totalCost = priority + cellsCost; + const cellCost = distanceCost * habitabilityModifier * heightModifier * connectionModifier * burgModifier; + const totalCost = priority + cellCost; if (totalCost >= cost[neibCellId]) continue; from[neibCellId] = next; diff --git a/utils/pathUtils.js b/utils/pathUtils.js index a81720a4..8c717314 100644 --- a/utils/pathUtils.js +++ b/utils/pathUtils.js @@ -176,3 +176,66 @@ function connectVertices({vertices, startingVertex, ofSameType, addToChecked, cl if (closeRing) chain.push(startingVertex); return chain; } + +/** + * Finds the shortest path between two cells using a cost-based pathfinding algorithm. + * @param {number} start - The ID of the starting cell. + * @param {number} exit - The ID of the destination cell. + * @param {function} getCellCost - A function that returns the cost of a cell. Should return Infinity for impassable cells. + * @returns {number[]|null} An array of cell IDs of the path from start to exit, or null if no path is found or start and exit are the same. + */ +function findPath(start, exit, getCellCost) { + if (start === exit) return null; + + const from = []; + const cost = []; + const queue = new FlatQueue(); + queue.push(start, 0); + + let iteration = 0; + + while (queue.length) { + const priority = queue.peekValue(); + const next = queue.pop(); + iteration++; + console.log(iteration, next); + + for (const neibCellId of pack.cells.c[next]) { + if (neibCellId === exit) { + from[neibCellId] = next; + return restorePath(start, exit, from); + } + + const cellCost = getCellCost(neibCellId); + if (cellCost === Infinity) continue; // impassable cell + + const distanceCost = dist2(pack.cells.p[next], pack.cells.p[neibCellId]); + const totalCost = priority + distanceCost + getCellCost(neibCellId); + + if (totalCost >= cost[neibCellId]) continue; + from[neibCellId] = next; + cost[neibCellId] = totalCost; + queue.push(neibCellId, totalCost); + } + } + + return null; +} + +// supplementary function for findPath +function restorePath(start, exit, from) { + const pathCells = []; + + let current = exit; + let prev = exit; + + while (current !== start) { + pathCells.push(current); + prev = from[current]; + current = prev; + } + + pathCells.push(current); + + return pathCells; +}