5_1.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import { ExtractNumbers, Inspect } from "../common.ts";
  2. const tests = [
  3. "seeds: 79 14 55 13",
  4. "",
  5. "seed-to-soil map:",
  6. "50 98 2",
  7. "52 50 48",
  8. "",
  9. "soil-to-fertilizer map:",
  10. "0 15 37",
  11. "37 52 2",
  12. "39 0 15",
  13. "",
  14. "fertilizer-to-water map:",
  15. "49 53 8",
  16. "0 11 42",
  17. "42 0 7",
  18. "57 7 4",
  19. "",
  20. "water-to-light map:",
  21. "88 18 7",
  22. "18 25 70",
  23. "",
  24. "light-to-temperature map:",
  25. "45 77 23",
  26. "81 45 19",
  27. "68 64 13",
  28. "",
  29. "temperature-to-humidity map:",
  30. "0 69 1",
  31. "1 0 69",
  32. "",
  33. "humidity-to-location map:",
  34. "60 56 37",
  35. "56 93 4",
  36. ];
  37. const maps = ParseInput(tests);
  38. const demoSeed = FindObjectByID(14, maps.Seeds);
  39. Inspect(demoSeed);
  40. const demoSoil = FindObjectByID(demoSeed?.ID || 0, maps.SeedToSoil);
  41. Inspect(demoSoil);
  42. function ParseInput(almanac: string[]): RangeMaps {
  43. /** An empty initializer for our output */
  44. const output: RangeMaps = {
  45. Seeds: [],
  46. SeedToSoil: [],
  47. SoilToFertilizer: [],
  48. FertilizerToWater: [],
  49. WaterToLight: [],
  50. LightToTemperature: [],
  51. TemperatureToHumidity: [],
  52. HumidityToLocation: [],
  53. };
  54. for (let i = 0; i < almanac.length; i++) {
  55. let line = almanac[i];
  56. // Parse the seed ID's
  57. if (/^seeds:/.test(line)) {
  58. // Extract all numbers from the line
  59. const seedIDs = ExtractNumbers(line);
  60. // Add to the output's Seeds array a new Seed for each number
  61. seedIDs.forEach((id) => { output.Seeds.push({ID: id}); });
  62. // Skip the next blank
  63. i++;
  64. }
  65. // Parse the Seed to Soil ranges
  66. else if (/^seed\-to/.test(line)) {
  67. output.SeedToSoil = ParseSourceDestinationRange(++i, almanac);
  68. }
  69. // Parse the Soil to Fertilizer ranges
  70. else if (/^soil\-to/.test(line)) {
  71. output.SoilToFertilizer = ParseSourceDestinationRange(++i, almanac);
  72. }
  73. // Parse the Fertilizer to Water ranges
  74. else if (/^fertilizer\-to/.test(line)) {
  75. output.FertilizerToWater = ParseSourceDestinationRange(++i, almanac);
  76. }
  77. // Parse the Water to Light ranges
  78. else if (/^water\-to/.test(line)) {
  79. output.WaterToLight = ParseSourceDestinationRange(++i, almanac);
  80. }
  81. // Parse the Light to Temperature ranges
  82. else if (/^light\-to/.test(line)) {
  83. output.LightToTemperature = ParseSourceDestinationRange(++i, almanac);
  84. }
  85. // Parse the Temperature to Humidity ranges
  86. else if (/^temperature\-to/.test(line)) {
  87. output.TemperatureToHumidity = ParseSourceDestinationRange(++i, almanac);
  88. }
  89. // Parse the Humidity to Location ranges
  90. else if (/^humidity\-to/.test(line)) {
  91. output.HumidityToLocation = ParseSourceDestinationRange(++i, almanac);
  92. }
  93. }
  94. return output;
  95. }
  96. /**
  97. * Helper function to parse the ranges for each mappable section
  98. *
  99. * @param {number} lineNumber The line number to begin parsing from
  100. * @param {string[]} almanac The complete almanac
  101. * @returns {MappableObject[]} A list of mapped indices
  102. */
  103. function ParseSourceDestinationRange(lineNumber: number, almanac: string[]): MappableObject[] {
  104. const rangeMap: MappableObject[] = [];
  105. do {
  106. // Get the values out of the line
  107. const [destinationRangeStart, sourceRangeStart, rangeLength] = ExtractNumbers(almanac[lineNumber]);
  108. // Create the ranges
  109. for (let idx = 0; idx < rangeLength; idx++) {
  110. rangeMap.push({
  111. ID: sourceRangeStart + idx,
  112. PointsTo: destinationRangeStart + idx,
  113. });
  114. }
  115. } while(almanac[++lineNumber]);
  116. return rangeMap;
  117. }
  118. /**
  119. * Find an IdentifiableObject by its ID number
  120. *
  121. * @param needle The ID number to find
  122. * @param haystack The list to find the ID in
  123. * @returns {IdentifiableObject|undefined} The object by that ID if found, or undefined
  124. */
  125. function FindObjectByID(needle: number, haystack: IdentifiableObject[]): IdentifiableObject|undefined {
  126. return haystack.find((obj) => obj.ID == needle);
  127. }
  128. interface IdentifiableObject {
  129. ID: number,
  130. };
  131. interface Seed extends IdentifiableObject {};
  132. interface MappableObject extends IdentifiableObject {
  133. PointsTo: number,
  134. };
  135. type RangeMaps = {
  136. Seeds: Seed[],
  137. SeedToSoil: MappableObject[],
  138. SoilToFertilizer: MappableObject[],
  139. FertilizerToWater: MappableObject[],
  140. WaterToLight: MappableObject[],
  141. LightToTemperature: MappableObject[],
  142. TemperatureToHumidity: MappableObject[],
  143. HumidityToLocation: MappableObject[],
  144. }