const sample = await Deno.readTextFile("sample.txt"); const input = await Deno.readTextFile("input.txt"); interface Map { s: number; d: number; l: number; } interface ParsedInput { seeds: number[]; seedToSoil: Map[]; soilToFertilizer: Map[]; fertilizerToWater: Map[]; waterToLight: Map[]; lightToTemperature: Map[]; temperatureToHumidity: Map[]; humidityToLocation: Map[]; } const computeMap = (maps: Map[]) => (input: number): number => { for (const { s, d, l } of maps) { if (input >= s && input < s + l) return (input - s) + d; } return input; }; const parseInput = (input: string): ParsedInput => { const seeds: number[] = input.split("\n\n").shift()?.split(" ").slice(1).map(parseFloat) || []; const parsed = input.split("\n\n") .filter(Boolean) .slice(1) .map((map): string[] => map.split(/:\ |\ map:\ *\n*/)) .map(( [name, rows], ): [string, number[][]] => [ name, rows.trim().split(/\n/).map((values) => values.split(/\ /).map(parseFloat) ), ]); let seedToSoil: Map[] = []; let soilToFertilizer: Map[] = []; let fertilizerToWater: Map[] = []; let waterToLight: Map[] = []; let lightToTemperature: Map[] = []; let temperatureToHumidity: Map[] = []; let humidityToLocation: Map[] = []; parsed.forEach(( [name, mapValues], ) => { const maps = mapValues.map(([d, s, l]) => ({ d, s, l })); if (name === "seed-to-soil") { seedToSoil = maps; } else if (name === "soil-to-fertilizer") { soilToFertilizer = maps; } else if (name === "fertilizer-to-water") { fertilizerToWater = maps; } else if (name === "water-to-light") { waterToLight = maps; } else if (name === "light-to-temperature") { lightToTemperature = maps; } else if (name === "temperature-to-humidity") { temperatureToHumidity = maps; } else if (name === "humidity-to-location") { humidityToLocation = maps; } }); return { seeds, seedToSoil, soilToFertilizer, fertilizerToWater, waterToLight, lightToTemperature, temperatureToHumidity, humidityToLocation, }; }; const solvePart1 = (data: string): number => { const { seeds, seedToSoil, soilToFertilizer, fertilizerToWater, waterToLight, lightToTemperature, temperatureToHumidity, humidityToLocation, } = parseInput(data); return seeds .map(computeMap(seedToSoil)) .map(computeMap(soilToFertilizer)) .map(computeMap(fertilizerToWater)) .map(computeMap(waterToLight)) .map(computeMap(lightToTemperature)) .map(computeMap(temperatureToHumidity)) .map(computeMap(humidityToLocation)) .reduce((m, v) => Math.min(m, v)); }; console.log("Sample:", solvePart1(sample)); // 35 console.log("Input", solvePart1(input)); // 265018614 const getRanges = (list: number[]): [number, number][] => { const result: [number, number][] = []; for (let i = 0; i < list.length; i += 2) { result.push([list[i], list[i + 1]]); } return result; }; const mapRange = (s: number, l: number, fn: (n: number) => void): void => { for (let i = s; i < s + l; i += 1) { fn(i); } }; const solvePart2 = (data: string): number => { const { seeds: seedRanges, seedToSoil, soilToFertilizer, fertilizerToWater, waterToLight, lightToTemperature, temperatureToHumidity, humidityToLocation, } = parseInput(data); console.log("getRanges(seedRanges)", getRanges(seedRanges)); const fn = (n: number): number => computeMap(humidityToLocation)( computeMap(temperatureToHumidity)( computeMap(lightToTemperature)( computeMap(waterToLight)( computeMap(fertilizerToWater)( computeMap(soilToFertilizer)(computeMap(seedToSoil)(n)), ), ), ), ), ); let lowest = Number.MAX_VALUE getRanges(seedRanges).forEach(([s, l]) => { console.log("range", s, lowest); mapRange(s, l, (n) => { lowest = Math.min(lowest, fn(n)); }); }); return lowest; }; console.log("Sample:", solvePart2(sample)); // 46 console.log("Input", solvePart2(input)); // 63179500