this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Day 8

tom.sherman.is c1ee7d96 2382bc8e

verified
+131
+131
src/day08.ts
··· 1 + // JS sets preserve insertion order, which is useful for part 2 2 + type Circuit = Set<Vector3>; 3 + 4 + export function solvePart1(input: string, numberOfPairs = 1000) { 5 + const points = parseInput(input); 6 + 7 + const circuits = connectClosestPairs(points, numberOfPairs); 8 + 9 + const threeLargestCircuits = circuits 10 + .sort((a, b) => b.size - a.size) 11 + .slice(0, 3); 12 + 13 + return String( 14 + threeLargestCircuits.reduce((sum, circuit) => sum * circuit.size, 1), 15 + ); 16 + } 17 + 18 + export function solvePart2(input: string) { 19 + const points = parseInput(input); 20 + 21 + const circuits = connectClosestPairs(points); 22 + 23 + // There should just be one circuit now because we iterated over all pairs 24 + const circuit = circuits[0]!; 25 + 26 + return String( 27 + [...circuit].slice(-2).reduce((xProduct, point) => xProduct * point.x, 1), 28 + ); 29 + } 30 + 31 + function connectClosestPairs(points: Vector3[], numberOfPairs?: number) { 32 + // ~500k pairs lol 33 + const pairDistances = makePairs(points).map((p) => ({ 34 + pair: p, 35 + distanceSquared: p[0].distanceToSquared(p[1]), 36 + })) 37 + .toArray() 38 + .sort((a, b) => a.distanceSquared - b.distanceSquared); 39 + 40 + const circuits = [] as Circuit[]; 41 + // Circuit lookup to avoid O(n) searches over `circuits` array every time 42 + const circuitLookup = new Map<Vector3, Circuit>(); 43 + 44 + const pairsToProcess = numberOfPairs 45 + ? pairDistances.slice(0, numberOfPairs) 46 + : pairDistances; 47 + 48 + for (const { pair: [a, b] } of pairsToProcess) { 49 + const circuitA = circuitLookup.get(a); 50 + const circuitB = circuitLookup.get(b); 51 + 52 + if (circuitA && circuitB) { 53 + if (circuitA === circuitB) { 54 + // both points already in the same circuit 55 + continue; 56 + } 57 + 58 + // merge circuits 59 + for (const point of circuitB) { 60 + circuitA.add(point); 61 + circuitLookup.set(point, circuitA); 62 + } 63 + circuits.splice(circuits.indexOf(circuitB), 1); 64 + // Rearrange circuitA to place a and b at the end for part 2 65 + circuitA.delete(a); 66 + circuitA.delete(b); 67 + circuitA.add(a); 68 + circuitA.add(b); 69 + } else if (circuitA || circuitB) { 70 + const existingCircuit = circuitA || circuitB!; 71 + const newPoint = circuitA ? b : a; 72 + circuitLookup.set(newPoint, existingCircuit); 73 + 74 + // Delete and re-add to ensure a and b are at the end to preserve order for part 2 75 + existingCircuit.delete(a); 76 + existingCircuit.delete(b); 77 + existingCircuit.add(a); 78 + existingCircuit.add(b); 79 + } else { 80 + // create new circuit 81 + const newCircuit = new Set<Vector3>([a, b]); 82 + circuits.push(newCircuit); 83 + circuitLookup.set(a, newCircuit); 84 + circuitLookup.set(b, newCircuit); 85 + } 86 + } 87 + 88 + return circuits; 89 + } 90 + 91 + function* makePairs<T>(arr: T[]) { 92 + for (let i = 0; i < arr.length; i++) { 93 + for (let j = i + 1; j < arr.length; j++) { 94 + yield [arr[i]!, arr[j]!] as const; 95 + } 96 + } 97 + } 98 + 99 + //613037 100 + //1344696 101 + function parseInput(input: string): Vector3[] { 102 + return input.trim().split("\n").map((line) => { 103 + const [x, y, z] = line.split(",").map((coord) => Number(coord.trim())); 104 + return new Vector3(x!, y!, z!); 105 + }); 106 + } 107 + 108 + class Vector3 { 109 + readonly x: number; 110 + readonly y: number; 111 + readonly z: number; 112 + 113 + constructor(x: number, y: number, z: number) { 114 + this.x = x; 115 + this.y = y; 116 + this.z = z; 117 + } 118 + 119 + distanceTo(other: Vector3): number { 120 + return Math.sqrt(this.distanceToSquared(other)); 121 + } 122 + 123 + // distanceToSquared can be used to compare distances without computing a square root which is more efficient 124 + distanceToSquared(other: Vector3): number { 125 + const dx = this.x - other.x; 126 + const dy = this.y - other.y; 127 + const dz = this.z - other.z; 128 + 129 + return dx * dx + dy * dy + dz * dz; 130 + } 131 + }