@graphty/algorithms 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/README.md +1259 -61
  2. package/dist/algorithms.d.ts +2 -0
  3. package/dist/algorithms.d.ts.map +1 -0
  4. package/dist/algorithms.js +2 -0
  5. package/dist/algorithms.js.map +1 -0
  6. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  7. package/dist/src/algorithms/centrality/betweenness.js +22 -7
  8. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  9. package/dist/src/algorithms/centrality/closeness.js +7 -7
  10. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  11. package/dist/src/algorithms/centrality/degree.js +1 -1
  12. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  13. package/dist/src/algorithms/centrality/eigenvector.d.ts +27 -0
  14. package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -0
  15. package/dist/src/algorithms/centrality/eigenvector.js +113 -0
  16. package/dist/src/algorithms/centrality/eigenvector.js.map +1 -0
  17. package/dist/src/algorithms/centrality/hits.d.ts +35 -0
  18. package/dist/src/algorithms/centrality/hits.d.ts.map +1 -0
  19. package/dist/src/algorithms/centrality/hits.js +146 -0
  20. package/dist/src/algorithms/centrality/hits.js.map +1 -0
  21. package/dist/src/algorithms/centrality/index.d.ts +6 -0
  22. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  23. package/dist/src/algorithms/centrality/index.js +3 -0
  24. package/dist/src/algorithms/centrality/index.js.map +1 -1
  25. package/dist/src/algorithms/centrality/katz.d.ts +30 -0
  26. package/dist/src/algorithms/centrality/katz.d.ts.map +1 -0
  27. package/dist/src/algorithms/centrality/katz.js +85 -0
  28. package/dist/src/algorithms/centrality/katz.js.map +1 -0
  29. package/dist/src/algorithms/centrality/pagerank.js +3 -3
  30. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  31. package/dist/src/algorithms/community/girvan-newman.d.ts +23 -0
  32. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -0
  33. package/dist/src/algorithms/community/girvan-newman.js +297 -0
  34. package/dist/src/algorithms/community/girvan-newman.js.map +1 -0
  35. package/dist/src/algorithms/community/index.d.ts +12 -0
  36. package/dist/src/algorithms/community/index.d.ts.map +1 -0
  37. package/dist/src/algorithms/community/index.js +12 -0
  38. package/dist/src/algorithms/community/index.js.map +1 -0
  39. package/dist/src/algorithms/community/label-propagation.d.ts +42 -0
  40. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -0
  41. package/dist/src/algorithms/community/label-propagation.js +307 -0
  42. package/dist/src/algorithms/community/label-propagation.js.map +1 -0
  43. package/dist/src/algorithms/community/leiden.d.ts +33 -0
  44. package/dist/src/algorithms/community/leiden.d.ts.map +1 -0
  45. package/dist/src/algorithms/community/leiden.js +434 -0
  46. package/dist/src/algorithms/community/leiden.js.map +1 -0
  47. package/dist/src/algorithms/community/louvain.d.ts +19 -0
  48. package/dist/src/algorithms/community/louvain.d.ts.map +1 -0
  49. package/dist/src/algorithms/community/louvain.js +219 -0
  50. package/dist/src/algorithms/community/louvain.js.map +1 -0
  51. package/dist/src/algorithms/components/connected.js +7 -7
  52. package/dist/src/algorithms/components/connected.js.map +1 -1
  53. package/dist/src/algorithms/index.d.ts +7 -0
  54. package/dist/src/algorithms/index.d.ts.map +1 -1
  55. package/dist/src/algorithms/index.js +14 -0
  56. package/dist/src/algorithms/index.js.map +1 -1
  57. package/dist/src/algorithms/matching/bipartite.d.ts +37 -0
  58. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -0
  59. package/dist/src/algorithms/matching/bipartite.js +127 -0
  60. package/dist/src/algorithms/matching/bipartite.js.map +1 -0
  61. package/dist/src/algorithms/matching/index.d.ts +8 -0
  62. package/dist/src/algorithms/matching/index.d.ts.map +1 -0
  63. package/dist/src/algorithms/matching/index.js +6 -0
  64. package/dist/src/algorithms/matching/index.js.map +1 -0
  65. package/dist/src/algorithms/matching/isomorphism.d.ts +32 -0
  66. package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -0
  67. package/dist/src/algorithms/matching/isomorphism.js +291 -0
  68. package/dist/src/algorithms/matching/isomorphism.js.map +1 -0
  69. package/dist/src/algorithms/mst/index.d.ts +4 -0
  70. package/dist/src/algorithms/mst/index.d.ts.map +1 -0
  71. package/dist/src/algorithms/mst/index.js +3 -0
  72. package/dist/src/algorithms/mst/index.js.map +1 -0
  73. package/dist/src/algorithms/mst/kruskal.d.ts +9 -0
  74. package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -0
  75. package/dist/src/algorithms/mst/kruskal.js +43 -0
  76. package/dist/src/algorithms/mst/kruskal.js.map +1 -0
  77. package/dist/src/algorithms/mst/prim.d.ts +5 -0
  78. package/dist/src/algorithms/mst/prim.d.ts.map +1 -0
  79. package/dist/src/algorithms/mst/prim.js +63 -0
  80. package/dist/src/algorithms/mst/prim.js.map +1 -0
  81. package/dist/src/algorithms/shortest-path/bellman-ford.js +2 -2
  82. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  83. package/dist/src/algorithms/shortest-path/dijkstra.js +5 -5
  84. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  85. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +14 -0
  86. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -0
  87. package/dist/src/algorithms/shortest-path/floyd-warshall.js +129 -0
  88. package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -0
  89. package/dist/src/algorithms/shortest-path/index.d.ts +2 -0
  90. package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
  91. package/dist/src/algorithms/shortest-path/index.js +1 -0
  92. package/dist/src/algorithms/shortest-path/index.js.map +1 -1
  93. package/dist/src/algorithms/traversal/bfs.js +2 -2
  94. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  95. package/dist/src/algorithms/traversal/dfs.js +11 -11
  96. package/dist/src/algorithms/traversal/dfs.js.map +1 -1
  97. package/dist/src/clustering/hierarchical.d.ts +48 -0
  98. package/dist/src/clustering/hierarchical.d.ts.map +1 -0
  99. package/dist/src/clustering/hierarchical.js +439 -0
  100. package/dist/src/clustering/hierarchical.js.map +1 -0
  101. package/dist/src/clustering/index.d.ts +7 -0
  102. package/dist/src/clustering/index.d.ts.map +1 -0
  103. package/dist/src/clustering/index.js +5 -0
  104. package/dist/src/clustering/index.js.map +1 -0
  105. package/dist/src/clustering/k-core.d.ts +63 -0
  106. package/dist/src/clustering/k-core.d.ts.map +1 -0
  107. package/dist/src/clustering/k-core.js +377 -0
  108. package/dist/src/clustering/k-core.js.map +1 -0
  109. package/dist/src/clustering/mcl.d.ts +36 -0
  110. package/dist/src/clustering/mcl.d.ts.map +1 -0
  111. package/dist/src/clustering/mcl.js +343 -0
  112. package/dist/src/clustering/mcl.js.map +1 -0
  113. package/dist/src/clustering/spectral.d.ts +28 -0
  114. package/dist/src/clustering/spectral.d.ts.map +1 -0
  115. package/dist/src/clustering/spectral.js +551 -0
  116. package/dist/src/clustering/spectral.js.map +1 -0
  117. package/dist/src/core/graph.d.ts +9 -0
  118. package/dist/src/core/graph.d.ts.map +1 -1
  119. package/dist/src/core/graph.js +31 -11
  120. package/dist/src/core/graph.js.map +1 -1
  121. package/dist/src/data-structures/priority-queue.js +0 -2
  122. package/dist/src/data-structures/priority-queue.js.map +1 -1
  123. package/dist/src/data-structures/union-find.js +2 -5
  124. package/dist/src/data-structures/union-find.js.map +1 -1
  125. package/dist/src/flow/ford-fulkerson.d.ts +53 -0
  126. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -0
  127. package/dist/src/flow/ford-fulkerson.js +355 -0
  128. package/dist/src/flow/ford-fulkerson.js.map +1 -0
  129. package/dist/src/flow/index.d.ts +3 -0
  130. package/dist/src/flow/index.d.ts.map +1 -0
  131. package/dist/src/flow/index.js +3 -0
  132. package/dist/src/flow/index.js.map +1 -0
  133. package/dist/src/flow/min-cut.d.ts +49 -0
  134. package/dist/src/flow/min-cut.d.ts.map +1 -0
  135. package/dist/src/flow/min-cut.js +383 -0
  136. package/dist/src/flow/min-cut.js.map +1 -0
  137. package/dist/src/index.d.ts +2 -1
  138. package/dist/src/index.d.ts.map +1 -1
  139. package/dist/src/index.js +2 -0
  140. package/dist/src/index.js.map +1 -1
  141. package/dist/src/link-prediction/adamic-adar.d.ts +56 -0
  142. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -0
  143. package/dist/src/link-prediction/adamic-adar.js +256 -0
  144. package/dist/src/link-prediction/adamic-adar.js.map +1 -0
  145. package/dist/src/link-prediction/common-neighbors.d.ts +50 -0
  146. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -0
  147. package/dist/src/link-prediction/common-neighbors.js +155 -0
  148. package/dist/src/link-prediction/common-neighbors.js.map +1 -0
  149. package/dist/src/link-prediction/index.d.ts +7 -0
  150. package/dist/src/link-prediction/index.d.ts.map +1 -0
  151. package/dist/src/link-prediction/index.js +6 -0
  152. package/dist/src/link-prediction/index.js.map +1 -0
  153. package/dist/src/pathfinding/astar.d.ts +50 -0
  154. package/dist/src/pathfinding/astar.d.ts.map +1 -0
  155. package/dist/src/pathfinding/astar.js +180 -0
  156. package/dist/src/pathfinding/astar.js.map +1 -0
  157. package/dist/src/pathfinding/index.d.ts +3 -0
  158. package/dist/src/pathfinding/index.d.ts.map +1 -0
  159. package/dist/src/pathfinding/index.js +3 -0
  160. package/dist/src/pathfinding/index.js.map +1 -0
  161. package/dist/src/pathfinding/utils.d.ts +18 -0
  162. package/dist/src/pathfinding/utils.d.ts.map +1 -0
  163. package/dist/src/pathfinding/utils.js +68 -0
  164. package/dist/src/pathfinding/utils.js.map +1 -0
  165. package/dist/src/research/grsbm.d.ts +83 -0
  166. package/dist/src/research/grsbm.d.ts.map +1 -0
  167. package/dist/src/research/grsbm.js +411 -0
  168. package/dist/src/research/grsbm.js.map +1 -0
  169. package/dist/src/research/index.d.ts +12 -0
  170. package/dist/src/research/index.d.ts.map +1 -0
  171. package/dist/src/research/index.js +14 -0
  172. package/dist/src/research/index.js.map +1 -0
  173. package/dist/src/research/sync.d.ts +49 -0
  174. package/dist/src/research/sync.d.ts.map +1 -0
  175. package/dist/src/research/sync.js +342 -0
  176. package/dist/src/research/sync.js.map +1 -0
  177. package/dist/src/research/terahac.d.ts +63 -0
  178. package/dist/src/research/terahac.d.ts.map +1 -0
  179. package/dist/src/research/terahac.js +375 -0
  180. package/dist/src/research/terahac.js.map +1 -0
  181. package/dist/src/types/index.d.ts +9 -0
  182. package/dist/src/types/index.d.ts.map +1 -1
  183. package/dist/src/utils/graphNode.d.ts +8 -0
  184. package/dist/src/utils/graphNode.d.ts.map +1 -0
  185. package/dist/src/utils/graphNode.js +2 -0
  186. package/dist/src/utils/graphNode.js.map +1 -0
  187. package/dist/src/utils/priorityQueue.d.ts +21 -0
  188. package/dist/src/utils/priorityQueue.d.ts.map +1 -0
  189. package/dist/src/utils/priorityQueue.js +101 -0
  190. package/dist/src/utils/priorityQueue.js.map +1 -0
  191. package/package.json +13 -2
  192. package/src/algorithms/centrality/betweenness.ts +25 -7
  193. package/src/algorithms/centrality/closeness.ts +7 -7
  194. package/src/algorithms/centrality/degree.ts +1 -1
  195. package/src/algorithms/centrality/eigenvector.ts +162 -0
  196. package/src/algorithms/centrality/hits.ts +210 -0
  197. package/src/algorithms/centrality/index.ts +6 -0
  198. package/src/algorithms/centrality/katz.ts +139 -0
  199. package/src/algorithms/centrality/pagerank.ts +3 -3
  200. package/src/algorithms/community/girvan-newman.ts +372 -0
  201. package/src/algorithms/community/index.ts +13 -0
  202. package/src/algorithms/community/label-propagation.ts +392 -0
  203. package/src/algorithms/community/leiden.ts +572 -0
  204. package/src/algorithms/community/louvain.ts +298 -0
  205. package/src/algorithms/components/connected.ts +7 -7
  206. package/src/algorithms/index.ts +21 -0
  207. package/src/algorithms/matching/bipartite.ts +179 -0
  208. package/src/algorithms/matching/index.ts +8 -0
  209. package/src/algorithms/matching/isomorphism.ts +392 -0
  210. package/src/algorithms/mst/index.ts +4 -0
  211. package/src/algorithms/mst/kruskal.ts +61 -0
  212. package/src/algorithms/mst/prim.ts +80 -0
  213. package/src/algorithms/shortest-path/bellman-ford.ts +2 -2
  214. package/src/algorithms/shortest-path/dijkstra.ts +5 -5
  215. package/src/algorithms/shortest-path/floyd-warshall.ts +170 -0
  216. package/src/algorithms/shortest-path/index.ts +2 -0
  217. package/src/algorithms/traversal/bfs.ts +2 -2
  218. package/src/algorithms/traversal/dfs.ts +11 -11
  219. package/src/clustering/hierarchical.ts +555 -0
  220. package/src/clustering/index.ts +6 -0
  221. package/src/clustering/k-core.ts +460 -0
  222. package/src/clustering/mcl.ts +454 -0
  223. package/src/clustering/spectral.ts +672 -0
  224. package/src/core/graph.ts +34 -6
  225. package/src/data-structures/union-find.ts +2 -2
  226. package/src/flow/ford-fulkerson.ts +459 -0
  227. package/src/flow/index.ts +2 -0
  228. package/src/flow/min-cut.ts +482 -0
  229. package/src/index.ts +5 -0
  230. package/src/link-prediction/adamic-adar.ts +353 -0
  231. package/src/link-prediction/common-neighbors.ts +252 -0
  232. package/src/link-prediction/index.ts +20 -0
  233. package/src/pathfinding/astar.ts +229 -0
  234. package/src/pathfinding/index.ts +2 -0
  235. package/src/pathfinding/utils.ts +87 -0
  236. package/src/research/grsbm.ts +589 -0
  237. package/src/research/index.ts +17 -0
  238. package/src/research/sync.ts +469 -0
  239. package/src/research/terahac.ts +506 -0
  240. package/src/types/index.ts +11 -0
  241. package/src/utils/graphNode.ts +7 -0
  242. package/src/utils/priorityQueue.ts +120 -0
  243. package/dist/test/browser/basic.test.d.ts +0 -2
  244. package/dist/test/browser/basic.test.d.ts.map +0 -1
  245. package/dist/test/browser/basic.test.js +0 -70
  246. package/dist/test/browser/basic.test.js.map +0 -1
  247. package/dist/test/unit/bellman-ford.test.d.ts +0 -2
  248. package/dist/test/unit/bellman-ford.test.d.ts.map +0 -1
  249. package/dist/test/unit/bellman-ford.test.js +0 -231
  250. package/dist/test/unit/bellman-ford.test.js.map +0 -1
  251. package/dist/test/unit/betweenness-centrality.test.d.ts +0 -2
  252. package/dist/test/unit/betweenness-centrality.test.d.ts.map +0 -1
  253. package/dist/test/unit/betweenness-centrality.test.js +0 -311
  254. package/dist/test/unit/betweenness-centrality.test.js.map +0 -1
  255. package/dist/test/unit/bfs.test.d.ts +0 -2
  256. package/dist/test/unit/bfs.test.d.ts.map +0 -1
  257. package/dist/test/unit/bfs.test.js +0 -277
  258. package/dist/test/unit/bfs.test.js.map +0 -1
  259. package/dist/test/unit/closeness.test.d.ts +0 -2
  260. package/dist/test/unit/closeness.test.d.ts.map +0 -1
  261. package/dist/test/unit/closeness.test.js +0 -266
  262. package/dist/test/unit/closeness.test.js.map +0 -1
  263. package/dist/test/unit/connected-components.test.d.ts +0 -2
  264. package/dist/test/unit/connected-components.test.d.ts.map +0 -1
  265. package/dist/test/unit/connected-components.test.js +0 -355
  266. package/dist/test/unit/connected-components.test.js.map +0 -1
  267. package/dist/test/unit/degree-centrality.test.d.ts +0 -2
  268. package/dist/test/unit/degree-centrality.test.d.ts.map +0 -1
  269. package/dist/test/unit/degree-centrality.test.js +0 -260
  270. package/dist/test/unit/degree-centrality.test.js.map +0 -1
  271. package/dist/test/unit/dfs.test.d.ts +0 -2
  272. package/dist/test/unit/dfs.test.d.ts.map +0 -1
  273. package/dist/test/unit/dfs.test.js +0 -350
  274. package/dist/test/unit/dfs.test.js.map +0 -1
  275. package/dist/test/unit/dijkstra.test.d.ts +0 -2
  276. package/dist/test/unit/dijkstra.test.d.ts.map +0 -1
  277. package/dist/test/unit/dijkstra.test.js +0 -311
  278. package/dist/test/unit/dijkstra.test.js.map +0 -1
  279. package/dist/test/unit/graph.test.d.ts +0 -2
  280. package/dist/test/unit/graph.test.d.ts.map +0 -1
  281. package/dist/test/unit/graph.test.js +0 -175
  282. package/dist/test/unit/graph.test.js.map +0 -1
  283. package/dist/test/unit/pagerank.test.d.ts +0 -2
  284. package/dist/test/unit/pagerank.test.d.ts.map +0 -1
  285. package/dist/test/unit/pagerank.test.js +0 -281
  286. package/dist/test/unit/pagerank.test.js.map +0 -1
  287. package/dist/test/unit/priority-queue.test.d.ts +0 -2
  288. package/dist/test/unit/priority-queue.test.d.ts.map +0 -1
  289. package/dist/test/unit/priority-queue.test.js +0 -189
  290. package/dist/test/unit/priority-queue.test.js.map +0 -1
  291. package/dist/test/unit/union-find.test.d.ts +0 -2
  292. package/dist/test/unit/union-find.test.d.ts.map +0 -1
  293. package/dist/test/unit/union-find.test.js +0 -245
  294. package/dist/test/unit/union-find.test.js.map +0 -1
@@ -0,0 +1,229 @@
1
+ import {graphNode} from "../utils/graphNode.js";
2
+ import {MinPriorityQueue} from "../utils/priorityQueue.js";
3
+ import {pathfindingUtils} from "./utils.js";
4
+
5
+ /**
6
+ * A* pathfinding algorithm
7
+ * Finds the shortest path from start to goal using a heuristic function
8
+ *
9
+ * @param graph - The graph represented as an adjacency list
10
+ * @param start - The starting node
11
+ * @param goal - The goal node
12
+ * @param heuristic - Heuristic function that estimates distance from node to goal
13
+ * @returns Object containing the shortest path and its cost, or null if no path exists
14
+ *
15
+ * Time Complexity: O(E) with good heuristic, O(b^d) worst case
16
+ * Space Complexity: O(V)
17
+ */
18
+ export function astar<T>(
19
+ graph: Map<T, Map<T, number>>,
20
+ start: T,
21
+ goal: T,
22
+ heuristic: (node: T, goal: T) => number,
23
+ ): {path: T[], cost: number} | null {
24
+ if (!graph.has(start) || !graph.has(goal)) {
25
+ return null;
26
+ }
27
+
28
+ // Priority queue ordered by f(n) = g(n) + h(n)
29
+ const openSet = new MinPriorityQueue<graphNode<T>>();
30
+ const gScore = new Map<T, number>(); // Cost from start to node
31
+ const fScore = new Map<T, number>(); // Estimated total cost
32
+ const cameFrom = new Map<T, T>();
33
+ const closedSet = new Set<T>();
34
+
35
+ // Initialize start node
36
+ gScore.set(start, 0);
37
+ fScore.set(start, heuristic(start, goal));
38
+ const startFScore = fScore.get(start);
39
+ if (startFScore === undefined) {
40
+ return null;
41
+ }
42
+
43
+ openSet.insert({node: start, distance: startFScore});
44
+
45
+ while (!openSet.isEmpty()) {
46
+ const current = openSet.extractMin();
47
+ if (!current) {
48
+ break;
49
+ }
50
+
51
+ const currentNode = current.node;
52
+
53
+ if (currentNode === goal) {
54
+ // Reconstruct path
55
+ const path = pathfindingUtils.reconstructPath(cameFrom, goal);
56
+ const goalCost = gScore.get(goal);
57
+ if (goalCost === undefined) {
58
+ return null;
59
+ }
60
+
61
+ return {path, cost: goalCost};
62
+ }
63
+
64
+ closedSet.add(currentNode);
65
+
66
+ const neighbors = graph.get(currentNode);
67
+ if (!neighbors) {
68
+ continue;
69
+ }
70
+
71
+ for (const [neighbor, weight] of neighbors) {
72
+ if (closedSet.has(neighbor)) {
73
+ continue;
74
+ }
75
+
76
+ const currentNodeGScore = gScore.get(currentNode);
77
+ if (currentNodeGScore === undefined) {
78
+ continue;
79
+ }
80
+
81
+ const tentativeGScore = currentNodeGScore + weight;
82
+ const currentGScore = gScore.get(neighbor) ?? Infinity;
83
+
84
+ if (tentativeGScore < currentGScore) {
85
+ // This path to neighbor is better
86
+ cameFrom.set(neighbor, currentNode);
87
+ gScore.set(neighbor, tentativeGScore);
88
+ fScore.set(neighbor, tentativeGScore + heuristic(neighbor, goal));
89
+
90
+ // Add to open set if not already there
91
+ const neighborFScore = fScore.get(neighbor);
92
+ if (neighborFScore !== undefined) {
93
+ openSet.insert({node: neighbor, distance: neighborFScore});
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ return null; // No path found
100
+ }
101
+
102
+ /**
103
+ * A* pathfinding with path reconstruction details
104
+ * Returns detailed information about the search process
105
+ */
106
+ export function astarWithDetails<T>(
107
+ graph: Map<T, Map<T, number>>,
108
+ start: T,
109
+ goal: T,
110
+ heuristic: (node: T, goal: T) => number,
111
+ ): {
112
+ path: T[] | null;
113
+ cost: number;
114
+ visited: Set<T>;
115
+ gScores: Map<T, number>;
116
+ fScores: Map<T, number>;
117
+ } {
118
+ const openSet = new MinPriorityQueue<graphNode<T>>();
119
+ const gScore = new Map<T, number>();
120
+ const fScore = new Map<T, number>();
121
+ const cameFrom = new Map<T, T>();
122
+ const closedSet = new Set<T>();
123
+
124
+ gScore.set(start, 0);
125
+ fScore.set(start, heuristic(start, goal));
126
+ const startFScore = fScore.get(start);
127
+ if (startFScore === undefined) {
128
+ return {
129
+ path: null,
130
+ cost: Infinity,
131
+ visited: new Set(),
132
+ gScores: new Map(),
133
+ fScores: new Map(),
134
+ };
135
+ }
136
+
137
+ openSet.insert({node: start, distance: startFScore});
138
+
139
+ while (!openSet.isEmpty()) {
140
+ const current = openSet.extractMin();
141
+ if (!current) {
142
+ break;
143
+ }
144
+
145
+ const currentNode = current.node;
146
+
147
+ if (currentNode === goal) {
148
+ const path = pathfindingUtils.reconstructPath(cameFrom, goal);
149
+ return {
150
+ path,
151
+ cost: gScore.get(goal) ?? Infinity,
152
+ visited: closedSet,
153
+ gScores: gScore,
154
+ fScores: fScore,
155
+ };
156
+ }
157
+
158
+ closedSet.add(currentNode);
159
+
160
+ const neighbors = graph.get(currentNode);
161
+ if (!neighbors) {
162
+ continue;
163
+ }
164
+
165
+ for (const [neighbor, weight] of neighbors) {
166
+ if (closedSet.has(neighbor)) {
167
+ continue;
168
+ }
169
+
170
+ const currentNodeGScore = gScore.get(currentNode);
171
+ if (currentNodeGScore === undefined) {
172
+ continue;
173
+ }
174
+
175
+ const tentativeGScore = currentNodeGScore + weight;
176
+ const currentGScore = gScore.get(neighbor) ?? Infinity;
177
+
178
+ if (tentativeGScore < currentGScore) {
179
+ cameFrom.set(neighbor, currentNode);
180
+ gScore.set(neighbor, tentativeGScore);
181
+ fScore.set(neighbor, tentativeGScore + heuristic(neighbor, goal));
182
+ const neighborFScore = fScore.get(neighbor);
183
+ if (neighborFScore !== undefined) {
184
+ openSet.insert({node: neighbor, distance: neighborFScore});
185
+ }
186
+ }
187
+ }
188
+ }
189
+
190
+ return {
191
+ path: null,
192
+ cost: Infinity,
193
+ visited: closedSet,
194
+ gScores: gScore,
195
+ fScores: fScore,
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Common heuristic functions for A*
201
+ */
202
+ export const heuristics = {
203
+ /**
204
+ * Manhattan distance heuristic for grid-based graphs
205
+ */
206
+ manhattan: (a: [number, number], b: [number, number]): number => {
207
+ return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
208
+ },
209
+
210
+ /**
211
+ * Euclidean distance heuristic
212
+ */
213
+ euclidean: (a: [number, number], b: [number, number]): number => {
214
+ return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2));
215
+ },
216
+
217
+ /**
218
+ * Chebyshev distance heuristic (diagonal movement allowed)
219
+ */
220
+ chebyshev: (a: [number, number], b: [number, number]): number => {
221
+ return Math.max(Math.abs(a[0] - b[0]), Math.abs(a[1] - b[1]));
222
+ },
223
+
224
+ /**
225
+ * Zero heuristic (makes A* behave like Dijkstra)
226
+ */
227
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
228
+ zero: <T>(_a: T, _b: T): number => 0,
229
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./astar.js";
2
+ export * from "./utils.js";
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Utility functions for pathfinding algorithms
3
+ */
4
+
5
+ export const pathfindingUtils = {
6
+ /**
7
+ * Reconstructs a path from start to goal using the cameFrom map
8
+ */
9
+ reconstructPath<T>(cameFrom: Map<T, T>, goal: T): T[] {
10
+ const path: T[] = [goal];
11
+ let current = goal;
12
+
13
+ while (cameFrom.has(current)) {
14
+ const next = cameFrom.get(current);
15
+ if (next === undefined) {
16
+ break;
17
+ }
18
+
19
+ current = next;
20
+ path.unshift(current);
21
+ }
22
+
23
+ return path;
24
+ },
25
+
26
+ /**
27
+ * Creates a grid graph for testing pathfinding algorithms
28
+ */
29
+ createGridGraph(
30
+ width: number,
31
+ height: number,
32
+ obstacles = new Set<string>(),
33
+ ): Map<string, Map<string, number>> {
34
+ const graph = new Map<string, Map<string, number>>();
35
+
36
+ for (let x = 0; x < width; x++) {
37
+ for (let y = 0; y < height; y++) {
38
+ const node = `${String(x)},${String(y)}`;
39
+ if (obstacles.has(node)) {
40
+ continue;
41
+ }
42
+
43
+ const neighbors = new Map<string, number>();
44
+
45
+ // Add 4-directional neighbors
46
+ const directions = [
47
+ [0, 1], [1, 0], [0, -1], [-1, 0],
48
+ ];
49
+
50
+ for (const dir of directions) {
51
+ const dx = dir[0];
52
+ const dy = dir[1];
53
+ if (dx === undefined || dy === undefined) {
54
+ continue;
55
+ }
56
+
57
+ const nx = x + dx;
58
+ const ny = y + dy;
59
+ const neighbor = `${String(nx)},${String(ny)}`;
60
+
61
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height && !obstacles.has(neighbor)) {
62
+ neighbors.set(neighbor, 1); // Unit cost for grid movement
63
+ }
64
+ }
65
+
66
+ graph.set(node, neighbors);
67
+ }
68
+ }
69
+
70
+ return graph;
71
+ },
72
+
73
+ /**
74
+ * Parses a grid coordinate string
75
+ */
76
+ parseGridCoordinate(coord: string): [number, number] {
77
+ const parts = coord.split(",").map(Number);
78
+ const x = parts[0];
79
+ const y = parts[1];
80
+ if (x === undefined || y === undefined) {
81
+ throw new Error(`Invalid coordinate: ${coord}`);
82
+ }
83
+
84
+ return [x, y];
85
+ },
86
+ };
87
+