125 lines
3.8 KiB
JavaScript
125 lines
3.8 KiB
JavaScript
/* eslint-disable no-restricted-globals */
|
|
|
|
// Preprost A* Pathfinding v Web Workerju
|
|
let grid = [];
|
|
let width = 0;
|
|
let height = 0;
|
|
|
|
self.onmessage = function (e) {
|
|
const { type, payload, id } = e.data;
|
|
|
|
if (type === 'UPDATE_GRID') {
|
|
grid = payload.grid;
|
|
width = payload.width;
|
|
height = payload.height;
|
|
// console.log('🕷️ Worker: Grid updated', width, height);
|
|
}
|
|
else if (type === 'FIND_PATH') {
|
|
if (!grid || grid.length === 0) {
|
|
self.postMessage({ type: 'PATH_FOUND', id, path: [] });
|
|
return;
|
|
}
|
|
const { startX, startY, endX, endY } = payload;
|
|
const path = findPath(startX, startY, endX, endY);
|
|
self.postMessage({ type: 'PATH_FOUND', id, path });
|
|
}
|
|
};
|
|
|
|
function findPath(startX, startY, endX, endY) {
|
|
// Preverimo meje
|
|
if (startX < 0 || startX >= width || startY < 0 || startY >= height) return [];
|
|
if (endX < 0 || endX >= width || endY < 0 || endY >= height) return [];
|
|
|
|
// Če cilj ni prehoden, vrni prazno (ali najdi najbližjo točko - za zdaj prazno)
|
|
if (!isWalkable(endX, endY)) return [];
|
|
|
|
const openSet = [];
|
|
const closedSet = new Set();
|
|
const cameFrom = new Map();
|
|
|
|
const gScore = new Map();
|
|
const fScore = new Map();
|
|
|
|
const startKey = `${startX},${startY}`;
|
|
const endKey = `${endX},${endY}`;
|
|
|
|
openSet.push({ x: startX, y: startY, f: heuristic(startX, startY, endX, endY) });
|
|
gScore.set(startKey, 0);
|
|
fScore.set(startKey, heuristic(startX, startY, endX, endY));
|
|
|
|
let iterations = 0;
|
|
|
|
while (openSet.length > 0) {
|
|
iterations++;
|
|
if (iterations > 1000) return []; // Safety break
|
|
|
|
// Najdi vozlišče z najnižjim fScore
|
|
openSet.sort((a, b) => a.f - b.f);
|
|
const current = openSet.shift();
|
|
const currentKey = `${current.x},${current.y}`;
|
|
|
|
if (current.x === endX && current.y === endY) {
|
|
return reconstructPath(cameFrom, current);
|
|
}
|
|
|
|
closedSet.add(currentKey);
|
|
|
|
const neighbors = getNeighbors(current.x, current.y);
|
|
for (const neighbor of neighbors) {
|
|
const neighborKey = `${neighbor.x},${neighbor.y}`;
|
|
if (closedSet.has(neighborKey)) continue;
|
|
|
|
const tentativeGScore = (gScore.get(currentKey) || 0) + 1;
|
|
|
|
if (tentativeGScore < (gScore.get(neighborKey) || Infinity)) {
|
|
cameFrom.set(neighborKey, current);
|
|
gScore.set(neighborKey, tentativeGScore);
|
|
const f = tentativeGScore + heuristic(neighbor.x, neighbor.y, endX, endY);
|
|
fScore.set(neighborKey, f);
|
|
|
|
if (!openSet.some(n => n.x === neighbor.x && n.y === neighbor.y)) {
|
|
openSet.push({ x: neighbor.x, y: neighbor.y, f: f });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return []; // Pot ni najdena
|
|
}
|
|
|
|
function isWalkable(x, y) {
|
|
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
// Predpostavljamo 1D array: y * width + x. 0 = prehodno, 1 = ovira.
|
|
return grid[y * width + x] === 0;
|
|
}
|
|
|
|
function getNeighbors(x, y) {
|
|
const neighbors = [];
|
|
const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]]; // Samo 4 smeri (Manhattan)
|
|
|
|
for (const [dx, dy] of dirs) {
|
|
const nx = x + dx;
|
|
const ny = y + dy;
|
|
if (isWalkable(nx, ny)) {
|
|
neighbors.push({ x: nx, y: ny });
|
|
}
|
|
}
|
|
return neighbors;
|
|
}
|
|
|
|
function heuristic(x1, y1, x2, y2) {
|
|
return Math.abs(x1 - x2) + Math.abs(y1 - y2);
|
|
}
|
|
|
|
function reconstructPath(cameFrom, current) {
|
|
const totalPath = [current];
|
|
let currentKey = `${current.x},${current.y}`;
|
|
|
|
while (cameFrom.has(currentKey)) {
|
|
current = cameFrom.get(currentKey);
|
|
currentKey = `${current.x},${current.y}`;
|
|
totalPath.unshift(current);
|
|
}
|
|
return totalPath;
|
|
}
|