@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
77 lines (55 loc) • 2.54 kB
JavaScript
import { BinaryDataType } from "../binary/type/BinaryDataType.js";
import { Deque } from "../collection/queue/Deque.js";
import { SquareMatrix } from "../math/matrix/SquareMatrix.js";
/**
* Produce a distance matrix from an input graph, tracing distances from each node to every node specified in target vector
* @see "A Fast Algorithm to Find All-Pairs Shortest Paths in Complex Networks" by Wei Peng et Al. 2012
* @template T
* @param {Graph<T>} graph
* @param {T[]} node_array graph nodes as an array
* @param {number[]} targets node indices, distances to which need to be calculated
* @param {Map<T, number>} node_index_map
* @returns {SquareMatrix}
*/
export function graph_compute_distance_matrix(graph, node_array, targets, node_index_map) {
const node_count = node_array.length;
const m_distances = new SquareMatrix(node_count, BinaryDataType.Float32);
// initialize distances
m_distances.fill(Number.POSITIVE_INFINITY);
// fill diagonal
for (let i = 0; i < node_count; i++) {
// Distance to self is 0
m_distances.setCellValue(i, i, 0);
}
/**
*
* @type {Deque<number>}
*/
const queue = new Deque();
for (const target_index of targets) {
queue.addLast(target_index);
while (!queue.isEmpty()) {
const index_1 = queue.removeFirst();
const node_1 = node_array[index_1];
const node_1_container = graph.getNodeContainer(node_1);
const edges = node_1_container.getEdges();
const edge_count = edges.length;
for (let i = 0; i < edge_count; i++) {
const edge = edges[i];
const node_0 = edge.other(node_1);
if (!edge.validateTransition(node_0, node_1)) {
continue;
}
const index_0 = node_index_map.get(node_0);
// If we haven't visited this neighbor yet, its distance is the current distance + 1
if (m_distances.getCellValue(index_0, target_index) === Number.POSITIVE_INFINITY) {
const transition_cost = edge.weight;
const new_distance = m_distances.getCellValue(index_1, target_index) + transition_cost;
m_distances.setCellValue(index_0, target_index, new_distance);
queue.addLast(index_0);
}
}
}
}
return m_distances;
}