import type { Vector } from "./Vector.ts"; export type Node = T; export type Edge = [Node, Node]; export type Graph = Map, Array>>; export type PositionPartial = { position: Vector; }; export function drawNode( node: Node, ctx: CanvasRenderingContext2D, color: string = "#fff", ): void { ctx.lineWidth = 2; ctx.strokeStyle = color; ctx.beginPath(); ctx.arc(node.position.x, node.position.y, 8, 0, 2 * Math.PI); ctx.stroke(); } export function getNodeByPosition( nodes: Array>, position: Vector, ): Node | null { for (const node of nodes) { if ( node.position.x <= position.x + 16 && node.position.x >= position.x - 16 && node.position.y <= position.y + 16 && node.position.y >= position.y - 16 ) { return node; } } return null; } export function drawEdge( edge: Edge, ctx: CanvasRenderingContext2D, color: string = "#fff", ): void { ctx.lineWidth = 2; ctx.strokeStyle = color; ctx.beginPath(); ctx.moveTo(edge[0].position.x, edge[0].position.y); ctx.lineTo(edge[1].position.x, edge[1].position.y); ctx.stroke(); } export function createGraph( nodes: Array>, edges: Array>, ): Graph { const graph: Graph = new Map(); for (const node of nodes) { const neighbours = edges.reduce( (acc, edge) => { if (edge[0] === node) { acc.push(edge[1]); return acc; } if (edge[1] === node) { acc.push(edge[0]); return acc; } return acc; }, [] as Array>, ); if (neighbours.length > 0) { graph.set(node, neighbours); } } return graph; } export function originDFS(origin: Node, graph: Graph): Array> { const visited: Array> = [origin]; if (!graph.has(origin)) { return visited; } innerDFS(origin, graph, visited); return visited; } function innerDFS( node: Node, graph: Graph, visited: Array>, ): void { const neighbours = graph.get(node)!; for (const node of neighbours) { if (visited.includes(node)) { continue; } visited.push(node); innerDFS(node, graph, visited); } } export function getNeighbours( graph: Graph, node: Node, ): Array> { return graph.has(node) ? graph.get(node)! : []; }