5_1.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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[]|MappableObject[]): IdentifiableObject|MappableObject|undefined {
  126. return haystack.find((obj) => obj.ID == needle);
  127. }
  128. /**
  129. * Map a Seed ID to all of its other attributes
  130. *
  131. * Given a seed ID, finds its soil type, fertilizer type, water type,
  132. * light type, temperature type, humidity type, and location ID.
  133. *
  134. * @param {number} seedID
  135. * @param {RangeMaps} rangeMaps A parsed map of ranges
  136. * @returns
  137. */
  138. function MapSeed(seedID: number, rangeMaps: RangeMaps): SeedMap|undefined {
  139. // Make sure the seed with that ID exists before continueing
  140. if(!FindObjectByID(seedID, rangeMaps.Seeds)) { return undefined; }
  141. // Initialize our seed map object
  142. const seed: SeedMap = {
  143. ID: seedID,
  144. SoilID: 0,
  145. FertilizerID: 0,
  146. WaterID: 0,
  147. LightID: 0,
  148. TemperatureID: 0,
  149. HumidityID: 0,
  150. LocationID: 0,
  151. };
  152. seed.SoilID = (FindObjectByID(seedID, rangeMaps.SeedToSoil) as MappableObject)?.PointsTo || seedID;
  153. seed.FertilizerID = (FindObjectByID(seed.SoilID, rangeMaps.SoilToFertilizer) as MappableObject)?.PointsTo || seed.SoilID;
  154. seed.WaterID = (FindObjectByID(seed.FertilizerID, rangeMaps.FertilizerToWater) as MappableObject)?.PointsTo || seed.FertilizerID;
  155. seed.LightID = (FindObjectByID(seed.WaterID, rangeMaps.WaterToLight) as MappableObject)?.PointsTo || seed.WaterID;
  156. seed.TemperatureID = (FindObjectByID(seed.LightID, rangeMaps.LightToTemperature) as MappableObject)?.PointsTo|| seed.LightID;
  157. seed.HumidityID = (FindObjectByID(seed.TemperatureID, rangeMaps.TemperatureToHumidity) as MappableObject)?.PointsTo || seed.TemperatureID;
  158. seed.LocationID = (FindObjectByID(seed.HumidityID, rangeMaps.HumidityToLocation) as MappableObject)?.PointsTo || seed.HumidityID;
  159. return seed;
  160. }
  161. interface IdentifiableObject {
  162. ID: number,
  163. };
  164. interface Seed extends IdentifiableObject {};
  165. interface MappableObject extends IdentifiableObject {
  166. PointsTo: number,
  167. };
  168. type RangeMaps = {
  169. Seeds: Seed[],
  170. SeedToSoil: MappableObject[],
  171. SoilToFertilizer: MappableObject[],
  172. FertilizerToWater: MappableObject[],
  173. WaterToLight: MappableObject[],
  174. LightToTemperature: MappableObject[],
  175. TemperatureToHumidity: MappableObject[],
  176. HumidityToLocation: MappableObject[],
  177. }
  178. type SeedMap = {
  179. /** The ID of the seed */
  180. ID: number,
  181. /** The ID of the soil type the seed needs planted in */
  182. SoilID: number,
  183. /** The ID of the fertilizer type the soil needs */
  184. FertilizerID: number,
  185. /** The ID of the water type the fertilizer needs */
  186. WaterID: number,
  187. /** The ID of the light type the water needs */
  188. LightID: number,
  189. /** The ID of the temperature type the light needs */
  190. TemperatureID: number,
  191. /** The ID of the humidity type the temperature needs */
  192. HumidityID: number,
  193. /** The ID of the location the humidity needs */
  194. LocationID: number,
  195. }