"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Pathfinder = void 0;
const ngraph_graph_1 = __importDefault(require("ngraph.graph"));
const ngraph_path_1 = __importDefault(require("ngraph.path"));
const Constants_1 = require("./Constants");
const Game_1 = require("./Game");
const Tools_1 = require("./Tools");
const UNKNOWN = 1;
const UNWALKABLE = 2;
const WALKABLE = 3;
class Pathfinder {
    static doorDistance(a, b) {
        const doorX = b[0];
        const doorY = b[1];
        const doorWidth = b[2];
        const doorHeight = b[3];
        let closest = Number.MAX_VALUE;
        for (const x of [doorX - doorWidth / 2, doorX + doorWidth / 2]) {
            for (const y of [doorY - doorHeight / 2, doorY + doorHeight / 2]) {
                const distance = Tools_1.Tools.distance(a, { x: x, y: y });
                if (distance < closest)
                    closest = distance;
            }
        }
        return closest;
    }
    static addLinkToGraph(from, to, data) {
        return this.graph.addLink(from.id, to.id, data);
    }
    static addNodeToGraph(map, x, y) {
        return this.graph.addNode(`${map}:${x},${y}`, { map: map, x: x, y: y });
    }
    static canStand(location) {
        if (!this.G)
            throw new Error("Prepare pathfinding before querying canStand()!");
        const y = Math.trunc(location.y) - this.G.geometry[location.map].min_y;
        const x = Math.trunc(location.x) - this.G.geometry[location.map].min_x;
        try {
            const grid = this.getGrid(location.map);
            if (grid[y][x] == WALKABLE)
                return true;
        }
        catch (e) {
            return false;
        }
        return false;
    }
    static canWalkPath(from, to) {
        if (!this.G)
            throw new Error("Prepare pathfinding before querying canWalkPath()!");
        if (from.map !== to.map)
            return false;
        const grid = this.getGrid(from.map);
        let ystep, xstep;
        let error;
        let errorprev;
        let y = Math.trunc(from.y) - this.G.geometry[from.map].min_y, x = Math.trunc(from.x) - this.G.geometry[from.map].min_x;
        let dx = Math.trunc(to.x) - Math.trunc(from.x);
        let dy = Math.trunc(to.y) - Math.trunc(from.y);
        if (grid[y][x] !== WALKABLE)
            return false;
        if (dy < 0) {
            ystep = -1;
            dy = -dy;
        }
        else {
            ystep = 1;
        }
        if (dx < 0) {
            xstep = -1;
            dx = -dx;
        }
        else {
            xstep = 1;
        }
        const ddy = 2 * dy;
        const ddx = 2 * dx;
        if (ddx >= ddy) {
            errorprev = error = dx;
            for (let i = 0; i < dx; i++) {
                x += xstep;
                error += ddy;
                if (error > ddx) {
                    y += ystep;
                    error -= ddx;
                    if (error + errorprev < ddx) {
                        if (grid[y - ystep][x] !== WALKABLE)
                            return false;
                    }
                    else if (error + errorprev > ddx) {
                        if (grid[y][x - xstep] !== WALKABLE)
                            return false;
                    }
                    else {
                        if (grid[y - ystep][x] !== WALKABLE)
                            return false;
                        if (grid[y][x - xstep] !== WALKABLE)
                            return false;
                    }
                }
                if (grid[y][x] !== WALKABLE)
                    return false;
                errorprev = error;
            }
        }
        else {
            errorprev = error = dy;
            for (let i = 0; i < dy; i++) {
                y += ystep;
                error += ddx;
                if (error > ddy) {
                    x += xstep;
                    error -= ddy;
                    if (error + errorprev < ddy) {
                        if (grid[y][x - xstep] !== WALKABLE)
                            return false;
                    }
                    else if (error + errorprev > ddy) {
                        if (grid[y - ystep][x] !== WALKABLE)
                            return false;
                    }
                    else {
                        if (grid[y][x - xstep] !== WALKABLE)
                            return false;
                        if (grid[y - ystep][x] !== WALKABLE)
                            return false;
                    }
                }
                if (grid[y][x] !== WALKABLE)
                    return false;
                errorprev = error;
            }
        }
        return true;
    }
    static computePathCost(path) {
        let cost = 0;
        let current = path[0];
        for (let i = 1; i < path.length; i++) {
            const next = path[i];
            if (next.type == "move") {
                cost += Tools_1.Tools.distance(current, next);
            }
            else if (next.type == "leave" || next.type == "transport") {
                cost += this.TRANSPORT_COST;
            }
            else if (next.type == "town") {
                cost += this.TOWN_COST;
            }
            current = next;
        }
        return cost;
    }
    static getGrid(map) {
        if (this.grids[map])
            return this.grids[map];
        if (!this.G)
            throw new Error("Prepare pathfinding before querying getGrid()!");
        console.debug(`Preparing ${map}...`);
        const width = this.G.geometry[map].max_x - this.G.geometry[map].min_x;
        const height = this.G.geometry[map].max_y - this.G.geometry[map].min_y;
        const grid = Array(height);
        for (let y = 0; y < height; y++) {
            grid[y] = [];
            for (let x = 0; x < width; x++)
                grid[y][x] = UNKNOWN;
        }
        for (const yLine of this.G.geometry[map].y_lines) {
            for (let y = Math.max(0, yLine[0] - this.G.geometry[map].min_y - Constants_1.Constants.BASE.vn); y <= yLine[0] - this.G.geometry[map].min_y + Constants_1.Constants.BASE.v && y < height; y++) {
                for (let x = Math.max(0, yLine[1] - this.G.geometry[map].min_x - Constants_1.Constants.BASE.h); x <= yLine[2] - this.G.geometry[map].min_x + Constants_1.Constants.BASE.h && x < width; x++) {
                    grid[y][x] = UNWALKABLE;
                }
            }
        }
        for (const xLine of this.G.geometry[map].x_lines) {
            for (let x = Math.max(0, xLine[0] - this.G.geometry[map].min_x - Constants_1.Constants.BASE.h); x <= xLine[0] - this.G.geometry[map].min_x + Constants_1.Constants.BASE.h && x < width; x++) {
                for (let y = Math.max(0, xLine[1] - this.G.geometry[map].min_y - Constants_1.Constants.BASE.vn); y <= xLine[2] - this.G.geometry[map].min_y + Constants_1.Constants.BASE.v && y < height; y++) {
                    grid[y][x] = UNWALKABLE;
                }
            }
        }
        for (const spawn of this.G.maps[map].spawns) {
            let x = Math.trunc(spawn[0]) - this.G.geometry[map].min_x;
            let y = Math.trunc(spawn[1]) - this.G.geometry[map].min_y;
            if (grid[y][x] === WALKABLE)
                continue;
            const stack = [[y, x]];
            while (stack.length) {
                [y, x] = stack.pop();
                let x1 = x;
                while (x1 >= 0 && grid[y][x1] == UNKNOWN)
                    x1--;
                x1++;
                let spanAbove = 0;
                let spanBelow = 0;
                while (x1 < width && grid[y][x1] == UNKNOWN) {
                    grid[y][x1] = WALKABLE;
                    if (!spanAbove && y > 0 && grid[y - 1][x1] == UNKNOWN) {
                        stack.push([y - 1, x1]);
                        spanAbove = 1;
                    }
                    else if (spanAbove && y > 0 && grid[y - 1][x1] !== UNKNOWN) {
                        spanAbove = 0;
                    }
                    if (!spanBelow && y < height - 1 && grid[y + 1][x1] == UNKNOWN) {
                        stack.push([y + 1, x1]);
                        spanBelow = 1;
                    }
                    else if (spanBelow && y < height - 1 && grid[y + 1][x1] !== UNKNOWN) {
                        spanBelow = 0;
                    }
                    x1++;
                }
            }
        }
        this.grids[map] = grid;
        const walkableNodes = [];
        this.graph.beginUpdate();
        for (let y = 1; y < height - 1; y++) {
            for (let x = 1; x < width; x++) {
                if (grid[y][x] !== WALKABLE)
                    continue;
                if (grid[y - 1][x - 1] === UNWALKABLE
                    && grid[y - 1][x] === UNWALKABLE
                    && grid[y - 1][x + 1] === UNWALKABLE
                    && grid[y][x - 1] === UNWALKABLE
                    && grid[y + 1][x - 1] === UNWALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
                else if (grid[y - 1][x - 1] === UNWALKABLE
                    && grid[y - 1][x] === UNWALKABLE
                    && grid[y - 1][x + 1] === UNWALKABLE
                    && grid[y][x + 1] === UNWALKABLE
                    && grid[y + 1][x + 1] === UNWALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
                else if (grid[y - 1][x + 1] === UNWALKABLE
                    && grid[y][x + 1] === UNWALKABLE
                    && grid[y + 1][x - 1] === UNWALKABLE
                    && grid[y + 1][x] === UNWALKABLE
                    && grid[y + 1][x + 1] === UNWALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
                else if (grid[y - 1][x - 1] === UNWALKABLE
                    && grid[y][x - 1] === UNWALKABLE
                    && grid[y + 1][x - 1] === UNWALKABLE
                    && grid[y + 1][x] === UNWALKABLE
                    && grid[y + 1][x + 1] === UNWALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
                else if (grid[y - 1][x - 1] === UNWALKABLE
                    && grid[y - 1][x] === WALKABLE
                    && grid[y][x - 1] === WALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
                else if (grid[y - 1][x] === WALKABLE
                    && grid[y - 1][x + 1] === UNWALKABLE
                    && grid[y][x + 1] === WALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
                else if (grid[y][x + 1] === WALKABLE
                    && grid[y + 1][x] === WALKABLE
                    && grid[y + 1][x + 1] === UNWALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
                else if (grid[y][x - 1] === WALKABLE
                    && grid[y + 1][x - 1] === UNWALKABLE
                    && grid[y + 1][x] === WALKABLE) {
                    walkableNodes.push(this.addNodeToGraph(map, x + this.G.geometry[map].min_x, y + this.G.geometry[map].min_y));
                }
            }
        }
        const transporters = [];
        for (const npc of this.G.maps[map].npcs) {
            if (npc.id !== "transporter")
                continue;
            const closest = this.findClosestSpawn(map, npc.position[0], npc.position[1]);
            const fromNode = this.addNodeToGraph(map, closest.x, closest.y);
            walkableNodes.push(fromNode);
            transporters.push(npc);
        }
        const doors = [];
        for (const door of this.G.maps[map].doors) {
            if (door[7] || door[8])
                continue;
            const spawn = this.G.maps[map].spawns[door[6]];
            const fromDoor = this.addNodeToGraph(map, spawn[0], spawn[1]);
            walkableNodes.push(fromDoor);
            doors.push(door);
        }
        for (const spawn of this.G.maps[map].spawns) {
            walkableNodes.push(this.addNodeToGraph(map, spawn[0], spawn[1]));
        }
        for (let i = 0; i < walkableNodes.length; i++) {
            const fromNode = walkableNodes[i];
            for (let j = i + 1; j < walkableNodes.length; j++) {
                if (this.canWalkPath(fromNode.data, walkableNodes[j].data)) {
                    this.addLinkToGraph(fromNode, walkableNodes[j]);
                    this.addLinkToGraph(walkableNodes[j], fromNode);
                }
            }
            for (const door of doors) {
                if (door[4] == "test")
                    continue;
                if (this.doorDistance(walkableNodes[i].data, door) > Constants_1.Constants.DOOR_REACH_DISTANCE)
                    continue;
                const spawn2 = this.G.maps[door[4]].spawns[door[5]];
                const toDoor = this.addNodeToGraph(door[4], spawn2[0], spawn2[1]);
                this.graph.addLink(fromNode.id, toDoor.id, { type: "transport", map: toDoor.data.map, x: toDoor.data.x, y: toDoor.data.y, spawn: door[5] });
            }
            for (const npc of transporters) {
                if (Tools_1.Tools.distance(fromNode.data, { x: npc.position[0], y: npc.position[1] }) > Constants_1.Constants.TRANSPORTER_REACH_DISTANCE)
                    continue;
                for (const toMap in this.G.npcs.transporter.places) {
                    if (map == toMap)
                        continue;
                    if (map == "test")
                        continue;
                    const spawnID = this.G.npcs.transporter.places[toMap];
                    const spawn = this.G.maps[toMap].spawns[spawnID];
                    const toNode = this.addNodeToGraph(toMap, spawn[0], spawn[1]);
                    this.addLinkToGraph(fromNode, toNode, {
                        type: "transport",
                        map: toMap,
                        x: toNode.data.x,
                        y: toNode.data.y,
                        spawn: spawnID
                    });
                }
            }
        }
        const townNode = this.addNodeToGraph(map, this.G.maps[map].spawns[0][0], this.G.maps[map].spawns[0][1]);
        const townLinkData = { type: "town", map: map, x: townNode.data.x, y: townNode.data.y };
        const leaveLink = this.addNodeToGraph("main", this.G.maps.main.spawns[0][0], this.G.maps.main.spawns[0][1]);
        const leaveLinkData = { type: "leave", map: leaveLink.data.map, x: leaveLink.data.x, y: leaveLink.data.y };
        for (const node of walkableNodes) {
            if (node.id !== townNode.id)
                this.addLinkToGraph(node, townNode, townLinkData);
            if (map == "cyberland" || map == "jail")
                this.addLinkToGraph(node, leaveLink, leaveLinkData);
        }
        this.graph.endUpdate();
        return grid;
    }
    static findClosestNode(map, x, y) {
        let closest = { distance: Number.MAX_VALUE, node: undefined };
        let closestWalkable = { distance: Number.MAX_VALUE, node: undefined };
        const from = { map, x, y };
        this.graph.forEachNode((node) => {
            if (node.data.map == map) {
                const distance = Tools_1.Tools.distance(from, node.data);
                if (distance > closest.distance)
                    return;
                const walkable = this.canWalkPath(from, node.data);
                if (distance < closest.distance)
                    closest = { distance, node };
                if (walkable && distance < closestWalkable.distance)
                    closestWalkable = { distance, node };
                if (distance < 1)
                    return true;
            }
        });
        return closestWalkable.node ? closestWalkable.node : closest.node;
    }
    static findClosestSpawn(map, x, y) {
        const closest = {
            map: map,
            x: Number.MAX_VALUE,
            y: Number.MAX_VALUE,
            distance: Number.MAX_VALUE
        };
        for (const spawn of this.G.maps[map].spawns) {
            const distance = Tools_1.Tools.distance({ x, y }, { x: spawn[0], y: spawn[1] });
            if (distance < closest.distance) {
                closest.x = spawn[0];
                closest.y = spawn[1];
                closest.distance = distance;
            }
        }
        return closest;
    }
    static getPath(from, to, avoidTownWarps = false) {
        if (!this.G)
            throw new Error("Prepare pathfinding before querying getPath()!");
        if (from.map == to.map && this.canWalkPath(from, to)) {
            return [{ type: "move", map: from.map, x: from.x, y: from.y }, { type: "move", map: from.map, x: to.x, y: to.y }];
        }
        const fromNode = this.findClosestNode(from.map, from.x, from.y);
        const toNode = this.findClosestNode(to.map, to.x, to.y);
        const path = [];
        console.debug(`Looking for a path from ${fromNode.id} to ${toNode.id}...`);
        let rawPath;
        if (avoidTownWarps) {
            rawPath = this.pathWithoutTown.find(fromNode.id, toNode.id);
        }
        else {
            rawPath = this.pathWithTown.find(fromNode.id, toNode.id);
        }
        if (rawPath.length == 0) {
            throw new Error("We did not find a path...");
        }
        path.push({ type: "move", map: fromNode.data.map, x: fromNode.data.x, y: fromNode.data.y });
        for (let i = rawPath.length - 1; i > 0; i--) {
            const currentNode = rawPath[i];
            const nextNode = rawPath[i - 1];
            const link = this.graph.getLink(currentNode.id, nextNode.id);
            if (link.data) {
                path.push(link.data);
                if (link.data.type == "town") {
                    path.push({ type: "move", map: link.data.map, x: this.G.maps[link.data.map].spawns[0][0], y: this.G.maps[link.data.map].spawns[0][1] });
                }
            }
            else {
                const townNode = this.G.maps[nextNode.data.map].spawns[0];
                if (nextNode.data.x == townNode[0] && nextNode.data.y == townNode[1]) {
                    if (Tools_1.Tools.distance(currentNode.data, nextNode.data) > this.TOWN_COST) {
                        path.push({ type: "town", map: nextNode.data.map, x: nextNode.data.x, y: nextNode.data.y });
                        path.push({ type: "move", map: nextNode.data.map, x: nextNode.data.x, y: nextNode.data.y });
                    }
                    else {
                        path.push({ type: "move", map: nextNode.data.map, x: nextNode.data.x, y: nextNode.data.y });
                    }
                }
                else {
                    path.push({ type: "move", map: nextNode.data.map, x: nextNode.data.x, y: nextNode.data.y });
                }
            }
        }
        path.push({ type: "move", map: to.map, x: to.x, y: to.y });
        for (let i = 0; i < path.length - 1; i++) {
            const current = path[i];
            const next = path[i + 1];
            if (current.type !== next.type)
                continue;
            if (current.map !== next.map)
                continue;
            if (current.x !== next.x)
                continue;
            if (current.y !== next.y)
                continue;
            path.splice(i, 1);
        }
        console.debug(`Path from ${fromNode.id} to ${toNode.id} found!`);
        return path;
    }
    static getSafeWalkTo(from, to) {
        if (from.map !== to.map)
            throw new Error("We can't walk across maps.");
        if (!this.G)
            throw new Error("Prepare pathfinding before querying getSafeWalkTo()!");
        const grid = this.getGrid(from.map);
        let ystep, xstep;
        let error;
        let errorprev;
        let y = Math.trunc(from.y) - this.G.geometry[from.map].min_y, x = Math.trunc(from.x) - this.G.geometry[from.map].min_x;
        let dx = Math.trunc(to.x) - Math.trunc(from.x);
        let dy = Math.trunc(to.y) - Math.trunc(from.y);
        if (grid[y][x] !== WALKABLE) {
            console.error(`We shouldn't be able to be where we are in from (${from.map}:${from.x},${from.y}).`);
            return Pathfinder.findClosestNode(from.map, from.x, from.y).data;
        }
        if (dy < 0) {
            ystep = -1;
            dy = -dy;
        }
        else {
            ystep = 1;
        }
        if (dx < 0) {
            xstep = -1;
            dx = -dx;
        }
        else {
            xstep = 1;
        }
        const ddy = 2 * dy;
        const ddx = 2 * dx;
        if (ddx >= ddy) {
            errorprev = error = dx;
            for (let i = 0; i < dx; i++) {
                x += xstep;
                error += ddy;
                if (error > ddx) {
                    y += ystep;
                    error -= ddx;
                    if (error + errorprev < ddx) {
                        if (grid[y - ystep][x] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                    }
                    else if (error + errorprev > ddx) {
                        if (grid[y][x - xstep] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                    }
                    else {
                        if (grid[y - ystep][x] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                        if (grid[y][x - xstep] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                    }
                }
                if (grid[y][x] !== WALKABLE)
                    return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y + this.G.geometry[from.map].min_y };
                errorprev = error;
            }
        }
        else {
            errorprev = error = dy;
            for (let i = 0; i < dy; i++) {
                y += ystep;
                error += ddx;
                if (error > ddy) {
                    x += xstep;
                    error -= ddy;
                    if (error + errorprev < ddy) {
                        if (grid[y][x - xstep] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                    }
                    else if (error + errorprev > ddy) {
                        if (grid[y - ystep][x] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                    }
                    else {
                        if (grid[y][x - xstep] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                        if (grid[y - ystep][x] !== WALKABLE)
                            return { map: from.map, x: x - xstep + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                    }
                }
                if (grid[y][x] !== WALKABLE)
                    return { map: from.map, x: x + this.G.geometry[from.map].min_x, y: y - ystep + this.G.geometry[from.map].min_y };
                errorprev = error;
            }
        }
        return to;
    }
    static async prepare(startMap = this.FIRST_MAP) {
        if (!this.G)
            this.G = await Game_1.Game.getGData();
        const maps = [startMap];
        console.debug("Preparing pathfinding...");
        const start = Date.now();
        for (let i = 0; i < maps.length; i++) {
            const map = maps[i];
            for (const door of this.G.maps[map].doors) {
                if (door[7] || door[8])
                    continue;
                if (door[4] == "test")
                    continue;
                if (!maps.includes(door[4]))
                    maps.push(door[4]);
            }
        }
        for (const map in this.G.npcs.transporter.places) {
            if (map == "test")
                continue;
            if (!maps.includes(map))
                maps.push(map);
        }
        for (const map of maps) {
            if (map == "test")
                continue;
            this.getGrid(map);
        }
        this.getGrid("jail");
        console.debug(`Pathfinding prepared! (${((Date.now() - start) / 1000).toFixed(3)}s)`);
        console.debug(`  # Nodes: ${this.graph.getNodeCount()}`);
        console.debug(`  # Links: ${this.graph.getLinkCount()}`);
        return;
    }
}
exports.Pathfinder = Pathfinder;
Pathfinder.FIRST_MAP = "main";
Pathfinder.TRANSPORT_COST = 50;
Pathfinder.TOWN_COST = 500;
Pathfinder.grids = {};
Pathfinder.graph = ngraph_graph_1.default({ multigraph: true });
Pathfinder.pathWithoutTown = ngraph_path_1.default.nba(Pathfinder.graph, {
    distance(fromNode, toNode, link) {
        if (link.data && (link.data.type == "leave" || link.data.type == "transport")) {
            return Pathfinder.TRANSPORT_COST;
        }
        else if (link.data && link.data.type == "town") {
            return 999999;
        }
        if (fromNode.data.map == toNode.data.map) {
            return Tools_1.Tools.distance(fromNode.data, toNode.data);
        }
    },
    oriented: true
});
Pathfinder.pathWithTown = ngraph_path_1.default.nba(Pathfinder.graph, {
    distance(fromNode, toNode, link) {
        if (link.data && (link.data.type == "leave" || link.data.type == "transport")) {
            return Pathfinder.TRANSPORT_COST;
        }
        else if (link.data && link.data.type == "town") {
            return Pathfinder.TOWN_COST;
        }
        if (fromNode.data.map == toNode.data.map) {
            return Tools_1.Tools.distance(fromNode.data, toNode.data);
        }
    },
    oriented: true
});
//# sourceMappingURL=Pathfinder.js.map