import { ExtractNumbers, Inspect } from "../common.ts"; const tests = [ "seeds: 79 14 55 13", "", "seed-to-soil map:", "50 98 2", "52 50 48", "", "soil-to-fertilizer map:", "0 15 37", "37 52 2", "39 0 15", "", "fertilizer-to-water map:", "49 53 8", "0 11 42", "42 0 7", "57 7 4", "", "water-to-light map:", "88 18 7", "18 25 70", "", "light-to-temperature map:", "45 77 23", "81 45 19", "68 64 13", "", "temperature-to-humidity map:", "0 69 1", "1 0 69", "", "humidity-to-location map:", "60 56 37", "56 93 4", ]; const maps = ParseInput(tests); const demoSeed = FindObjectByID(14, maps.Seeds); Inspect(demoSeed); const demoSoil = FindObjectByID(demoSeed?.ID || 0, maps.SeedToSoil); Inspect(demoSoil); function ParseInput(almanac: string[]): RangeMaps { /** An empty initializer for our output */ const output: RangeMaps = { Seeds: [], SeedToSoil: [], SoilToFertilizer: [], FertilizerToWater: [], WaterToLight: [], LightToTemperature: [], TemperatureToHumidity: [], HumidityToLocation: [], }; /** A translation map for range titles to RangeMap keys*/ for (let i = 0; i < almanac.length; i++) { let line = almanac[i]; // Parse the seed ID's if (/^seeds:/.test(line)) { // Extract all numbers from the line const seedIDs = ExtractNumbers(line); // Add to the output's Seeds array a new Seed for each number seedIDs.forEach((id) => { output.Seeds.push({ID: id}); }); // Skip the next blank i++; } // Parse the Seed to Soil ranges else if (/^seed\-to/.test(line)) { output.SeedToSoil = ParseSourceDestinationRange(++i, almanac); } // Parse the Soil to Fertilizer ranges else if (/^soil\-to/.test(line)) { output.SoilToFertilizer = ParseSourceDestinationRange(++i, almanac); } // Parse the Fertilizer to Water ranges else if (/^fertilizer\-to/.test(line)) { output.FertilizerToWater = ParseSourceDestinationRange(++i, almanac); } // Parse the Water to Light ranges else if (/^water\-to/.test(line)) { output.WaterToLight = ParseSourceDestinationRange(++i, almanac); } // Parse the Light to Temperature ranges else if (/^light\-to/.test(line)) { output.LightToTemperature = ParseSourceDestinationRange(++i, almanac); } // Parse the Temperature to Humidity ranges else if (/^temperature\-to/.test(line)) { output.TemperatureToHumidity = ParseSourceDestinationRange(++i, almanac); } // Parse the Humidity to Location ranges else if (/^humidity\-to/.test(line)) { output.HumidityToLocation = ParseSourceDestinationRange(++i, almanac); } } return output; } /** * Helper function to parse the ranges for each mappable section * * @param {number} lineNumber The line number to begin parsing from * @param {string[]} almanac The complete almanac * @returns {MappableObject[]} A list of mapped indices */ function ParseSourceDestinationRange(lineNumber: number, almanac: string[]): MappableObject[] { const rangeMap: MappableObject[] = []; do { // Get the values out of the line const [destinationRangeStart, sourceRangeStart, rangeLength] = ExtractNumbers(almanac[lineNumber]); // Create the ranges for (let idx = 0; idx < rangeLength; idx++) { rangeMap.push({ ID: sourceRangeStart + idx, PointsTo: destinationRangeStart + idx, }); } } while(almanac[++lineNumber]); return rangeMap; } /** * Find an IdentifiableObject by its ID number * * @param needle The ID number to find * @param haystack The list to find the ID in * @returns {IdentifiableObject|undefined} The object by that ID if found, or undefined */ function FindObjectByID(needle: number, haystack: IdentifiableObject[]): IdentifiableObject|undefined { return haystack.find((obj) => obj.ID == needle); } interface IdentifiableObject { ID: number, }; interface Seed extends IdentifiableObject {}; interface MappableObject extends IdentifiableObject { PointsTo: number, }; type RangeMaps = { Seeds: Seed[], SeedToSoil: MappableObject[], SoilToFertilizer: MappableObject[], FertilizerToWater: MappableObject[], WaterToLight: MappableObject[], LightToTemperature: MappableObject[], TemperatureToHumidity: MappableObject[], HumidityToLocation: MappableObject[], }