Files
novafarma/src/workers/pathfinding.worker.js
2025-12-07 21:31:44 +01:00

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;
}