this repo has no description
0
fork

Configure Feed

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

ok, lcm was the missing piece

+23 -54
+23 -54
2023/day08/part2.ts
··· 1 1 type Node = { L: string; R: string }; 2 2 type Network = Record<string, Node>; 3 3 4 - type Path = { 5 - start: string; 6 - current: string; 7 - history: string[]; 8 - }; 9 - 10 - export function answer(input: string): number { 4 + export function answer(input: string) { 11 5 const [instructionsRaw, , ...networkRaw] = input.split("\n"); 12 6 13 7 const network: Network = networkRaw.reduce((network, line) => { ··· 16 10 return { ...network, [id]: { L, R } }; 17 11 }, {}); 18 12 19 - const instructions = instructionsRaw.split(""); 13 + const instructions = instructionsRaw.split("") as ("L" | "R")[]; 20 14 21 - const next = (node: string, i: number): string => 22 - network[node][instructions[i] as "L" | "R"]; 15 + const paths = Object.keys(network).filter((n) => n.endsWith("A")); 23 16 24 - const startNodes = Object.keys(network).filter((n) => n.endsWith("A")); 25 - const endNodes = Object.keys(network).filter((n) => n.endsWith("Z")); 26 - 27 - const paths: Path[] = startNodes.map((n) => ({ 28 - start: n, 29 - current: n, 30 - history: [], 31 - })); 32 - 33 - const stepsToZCache: Record<string, number> = {}; 34 - 35 - const stepPath = (p: Path, instIdx: number, step: number) => { 36 - p.history.push(p.current); 37 - p.current = next(p.current, instIdx); 38 - 39 - if (p.current.endsWith("Z")) { 40 - p.history.forEach((prev, i) => { 41 - console.log(`${instIdx}.${prev}.${p.current} = ${step - i + 1}`); 42 - stepsToZCache[`${instIdx}.${prev}.${p.current}`] = step - i + 1; 43 - }); 17 + const stepsToZ = (node: string) => { 18 + let step = 0; 19 + while (!node.endsWith("Z")) { 20 + for (const dir of instructions) { 21 + node = network[node][dir]; 22 + step++; 23 + if (node.endsWith("Z")) break; 24 + } 44 25 } 26 + return step; 45 27 }; 46 28 47 - let step = 0; 48 - while (true) { 49 - for (let instIdx = 0; instIdx < instructions.length; instIdx++) { 50 - const stepsToZFromCurrent: number[] = []; 51 - 52 - paths.forEach((p) => { 53 - stepPath(p, instIdx, step); 54 - for (const en of endNodes) { 55 - const steps = stepsToZCache[`${instIdx}.${p.current}.${en}`]; 56 - if (steps) stepsToZFromCurrent.push(steps); 57 - } 58 - }); 59 - 60 - const pathsToZ = paths.map((p) => 61 - endNodes 62 - .map((en) => stepsToZCache[`${instIdx}.${p.current}.${en}`]) 63 - .filter((s) => s !== undefined), 64 - ); 29 + return lcm(paths.map((p) => stepsToZ(p))); 30 + } 65 31 66 - if (pathsToZ.every((p) => p.length > 0)) { 67 - return pathsToZ.reduce((product, x) => (product *= x[x.length - 1]), 1); 68 - } 32 + function lcm(nums: number[]): number { 33 + const [a, b, ...rest] = nums; 34 + const c = (a * b) / gcf(a, b); 35 + if (rest.length === 0) return c; 36 + return lcm([c, ...rest]); 37 + } 69 38 70 - step++; 71 - } 72 - } 39 + function gcf(a: number, b: number): number { 40 + if (b === 0) return a; 41 + return gcf(b, a % b); 73 42 } 74 43 75 44 if (import.meta.main) {