Переглянути джерело

Refactor to work with input

Refactored the whole thing to work with less memory. Instead of keeping
a whole dictionary of ID maps, only the ranges are kept. When a lookup
is performed, some arithmetic is done to find the destination.
ApisNecros 1 рік тому
батько
коміт
141659ae99
1 змінених файлів з 51 додано та 43 видалено
  1. 51 43
      5/5_1.ts

+ 51 - 43
5/5_1.ts

@@ -42,7 +42,7 @@ const input = await LoadInput(5);
 const maps = ParseInput(input);
 
 // Map the seeds
-const seeds = maps.Seeds.map((seed) => MapSeed(seed.ID, maps));
+const seeds = maps.Seeds.map((seed) => MapSeed(seed, maps));
 
 // Get the output
 let closestLocationID = Number.MAX_SAFE_INTEGER;
@@ -75,7 +75,7 @@ function ParseInput(almanac: string[]): RangeMaps {
             // 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}); });
+            seedIDs.forEach((id) => { output.Seeds.push(id); });
             // Skip the next blank
             i++;
         }
@@ -117,35 +117,46 @@ function ParseInput(almanac: string[]): RangeMaps {
  *
  * @param {number} lineNumber The line number to begin parsing from
  * @param {string[]} almanac The complete almanac
- * @returns {MappableObject[]} A list of mapped indices
+ * @returns {RangeMap[]} A list of mapped indices
  */
-function ParseSourceDestinationRange(lineNumber: number, almanac: string[]): MappableObject[] {
-    const rangeMap: MappableObject[] = [];
+function ParseSourceDestinationRange(lineNumber: number, almanac: string[]): RangeMap[] {
+    const rangeMap: RangeMap[] = [];
     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,
-            });
-        }
+        rangeMap.push({
+            SourceRanges: {
+                Start: sourceRangeStart,
+                End: sourceRangeStart + rangeLength - 1,
+            },
+            DestinationRange: {
+                Start: destinationRangeStart,
+                End: destinationRangeStart + rangeLength - 1,
+            }
+        });
     } while(almanac[++lineNumber]);
     
     return rangeMap;
 }
 
 /**
- * Find an IdentifiableObject by its ID number
+ * Maps one object to another based on ID ranges
+ *
+ * If the ID given doesn't fit in any of the ranges given, then the
+ * input is returned
  *
- * @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
+ * @param {number} needle The ID number to find
+ * @param {RangeMap[]} haystack The list of ranges to find the ID in
+ * @returns {number} The ID of the mapped object
  */
-function FindObjectByID(needle: number, haystack: IdentifiableObject[]|MappableObject[]): IdentifiableObject|MappableObject|undefined {
-    return haystack.find((obj) => obj.ID == needle);
+function MapObjectByID(needle: number, haystack: RangeMap[]): number {
+    for (const range of haystack) {
+        if (range.SourceRanges.Start <= needle && range.SourceRanges.End >= needle) {
+            return range.DestinationRange.Start + (needle - range.SourceRanges.Start);
+        }
+    }
+    return needle;
 }
 
 /**
@@ -160,7 +171,7 @@ function FindObjectByID(needle: number, haystack: IdentifiableObject[]|MappableO
  */
 function MapSeed(seedID: number, rangeMaps: RangeMaps): SeedMap|undefined {
     // Make sure the seed with that ID exists before continueing
-    if(!FindObjectByID(seedID, rangeMaps.Seeds)) { return undefined; }
+    if(!rangeMaps.Seeds.includes(seedID)) { return undefined; }
     
     // Initialize our seed map object
     const seed: SeedMap = {
@@ -174,13 +185,13 @@ function MapSeed(seedID: number, rangeMaps: RangeMaps): SeedMap|undefined {
         LocationID: 0,
     };
 
-    seed.SoilID =        (FindObjectByID(seedID, rangeMaps.SeedToSoil) as MappableObject)?.PointsTo || seedID;
-    seed.FertilizerID =  (FindObjectByID(seed.SoilID, rangeMaps.SoilToFertilizer) as MappableObject)?.PointsTo || seed.SoilID;
-    seed.WaterID =       (FindObjectByID(seed.FertilizerID, rangeMaps.FertilizerToWater) as MappableObject)?.PointsTo || seed.FertilizerID;
-    seed.LightID =       (FindObjectByID(seed.WaterID, rangeMaps.WaterToLight) as MappableObject)?.PointsTo || seed.WaterID;
-    seed.TemperatureID = (FindObjectByID(seed.LightID, rangeMaps.LightToTemperature) as MappableObject)?.PointsTo|| seed.LightID;
-    seed.HumidityID =    (FindObjectByID(seed.TemperatureID, rangeMaps.TemperatureToHumidity) as MappableObject)?.PointsTo || seed.TemperatureID;
-    seed.LocationID =    (FindObjectByID(seed.HumidityID, rangeMaps.HumidityToLocation) as MappableObject)?.PointsTo || seed.HumidityID;
+    seed.SoilID =        MapObjectByID(seedID, rangeMaps.SeedToSoil);
+    seed.FertilizerID =  MapObjectByID(seed.SoilID, rangeMaps.SoilToFertilizer);
+    seed.WaterID =       MapObjectByID(seed.FertilizerID, rangeMaps.FertilizerToWater);
+    seed.LightID =       MapObjectByID(seed.WaterID, rangeMaps.WaterToLight);
+    seed.TemperatureID = MapObjectByID(seed.LightID, rangeMaps.LightToTemperature);
+    seed.HumidityID =    MapObjectByID(seed.TemperatureID, rangeMaps.TemperatureToHumidity);
+    seed.LocationID =    MapObjectByID(seed.HumidityID, rangeMaps.HumidityToLocation);
 
     return seed;
 }
@@ -206,39 +217,36 @@ function isSeedMapArray(valueArray: any[]): valueArray is SeedMap[] {
         && Object.hasOwn(value, "LocationID");
 }
 
-/** Any object with a unique identifier */
-interface IdentifiableObject {
-    /** The ID number for this object */
-    ID: number,
+type IDRange = {
+    Start: number,
+    End: number,
 };
 
-/** A seed */
-interface Seed extends IdentifiableObject {};
-
 /** An IdentifiableObject that points to another IdentifiableObject */
-interface MappableObject extends IdentifiableObject {
+type RangeMap = {
     /** The ID that this object points to */
-    PointsTo: number,
+    SourceRanges: IDRange,
+    DestinationRange: IDRange,
 };
 
 /** A complete map of all object IDs and where they point to */
 type RangeMaps = {
     /** The list of seed IDs */
-    Seeds: Seed[],
+    Seeds: number[],
     /** The map of seed to soil IDs */
-    SeedToSoil: MappableObject[],
+    SeedToSoil: RangeMap[],
     /** The map of soil to fertilizer IDs */
-    SoilToFertilizer: MappableObject[],
+    SoilToFertilizer: RangeMap[],
     /** The map of fertilizer to water IDs */
-    FertilizerToWater: MappableObject[],
+    FertilizerToWater: RangeMap[],
     /** The map of water to light IDs */
-    WaterToLight: MappableObject[],
+    WaterToLight: RangeMap[],
     /** The map of light to temperature IDs */
-    LightToTemperature: MappableObject[],
+    LightToTemperature: RangeMap[],
     /** The map of temperature to humidity IDs */
-    TemperatureToHumidity: MappableObject[],
+    TemperatureToHumidity: RangeMap[],
     /** The map of humidity to location IDs */
-    HumidityToLocation: MappableObject[],
+    HumidityToLocation: RangeMap[],
 }
 
 /** A completed map of a seed's property IDs */