this repo has no description
0
fork

Configure Feed

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

keep history, cache steps to end nodes

tests pass, answer is too low

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