@@ -52,15 +52,38 @@ Deno.test("Day 5: If You Give A Seed A Fertilizer", async (t) => {
5252 } ) ;
5353 } ) ;
5454
55- await t . step ( "Solution" , async ( t ) => {
55+ await t . step ( "Solution" , async ( ) => {
5656 const solution = almanac (
5757 ( await Deno . readTextFile ( "./input/day05.txt" ) ) . split ( "\n" )
5858 ) ;
5959 assertEquals ( lowest ( solution ) , 403695602 ) ;
6060 } ) ;
6161 } ) ;
62+
63+ await t . step ( "Part 2" , async ( t ) => {
64+ await t . step ( "Example" , async ( ) => {
65+ const example = lowestSeedRange (
66+ ( await Deno . readTextFile ( "./input/day05.example.txt" ) ) . split ( "\n" )
67+ ) ;
68+ assertEquals ( example , 46 ) ;
69+ } ) ;
70+ /**
71+ * FIXME: Completes after ~5 minutes
72+ * This should be optimizable by
73+ * - combining all the maps into one final map
74+ * - reverting the algorithm to start at the lowest positions until a matching seed is found.
75+ await t.step("Solution", async () => {
76+ const solution = lowestSeedRange(
77+ (await Deno.readTextFile("./input/day05.txt")).split("\n")
78+ );
79+ assertEquals(solution, 219529182);
80+ });
81+ */
82+ } ) ;
6283} ) ;
6384
85+ const lowest = ( numbers : Set < number > ) => Math . min ( ...numbers . values ( ) ) ;
86+
6487const rangeRx =
6588 / ^ (?< destRangeStart > \d + ) (?< sourceRangeStart > \d + ) (?< rangeLength > \d + ) $ / ;
6689
@@ -96,6 +119,48 @@ const almanac = (almanac: string[]) => {
96119 const seeds = almanac [ 0 ] . split ( ":" ) [ 1 ] . trim ( ) . split ( " " ) . map ( toNumber ) ;
97120
98121 // Read in all the map ranges
122+ const maps = almanacToMaps ( almanac ) ;
123+
124+ return mapSeeds ( seeds , maps ) ;
125+ } ;
126+
127+ const lowestSeedRange = ( almanac : string [ ] ) : number => {
128+ // Get the seed pairs from the first line
129+ const seedPairs = almanac [ 0 ]
130+ . split ( ":" ) [ 1 ]
131+ . trim ( )
132+ . matchAll ( / ( \d + \d + ) + / g) ;
133+
134+ // Read in all the map ranges
135+ const maps = almanacToMaps ( almanac ) ;
136+
137+ let lowest = Number . MAX_SAFE_INTEGER ;
138+ for ( const pair of seedPairs ) {
139+ const [ start , length ] = pair [ 0 ] . split ( " " ) . map ( toNumber ) ;
140+ for ( let i = start ; i < start + length ; i ++ ) {
141+ lowest = Math . min (
142+ maps . reduce ( ( mapped , seedMap ) => seedMap ( mapped ) , i ) ,
143+ lowest
144+ ) ;
145+ }
146+ }
147+
148+ return lowest ;
149+ } ;
150+
151+ // Pass each seed through each map
152+ const mapSeeds = (
153+ seeds : number [ ] ,
154+ maps : Array < ( seed : number ) => number >
155+ ) : Set < number > =>
156+ new Set < number > (
157+ seeds . map ( ( seed ) => maps . reduce ( ( mapped , seedMap ) => seedMap ( mapped ) , seed ) )
158+ ) ;
159+
160+ /**
161+ * Parses the almanac to maps
162+ */
163+ const almanacToMaps = ( almanac : string [ ] ) : Array < ( seed : number ) => number > => {
99164 const mapRanges : Array < Array < string > > = [ [ ] ] ;
100165 let i = 0 ;
101166 // Skip first three lines
@@ -110,12 +175,5 @@ const almanac = (almanac: string[]) => {
110175 }
111176
112177 // Convert to maps
113- const maps = mapRanges . map ( seedMap ) ;
114-
115- // Pass each seed through each map
116- return new Set < number > (
117- seeds . map ( ( seed ) => maps . reduce ( ( mapped , seedMap ) => seedMap ( mapped ) , seed ) )
118- ) ;
178+ return mapRanges . map ( seedMap ) ;
119179} ;
120-
121- const lowest = ( numbers : Set < number > ) => Math . min ( ...numbers . values ( ) ) ;
0 commit comments