@@ -16,29 +16,27 @@ Acre.initEnum({
1616 }
1717} ) ;
1818
19- class Point {
20- constructor ( x , y ) {
21- this . x = x ;
22- this . y = y ;
23- }
24- }
25-
2619function parse ( char ) {
2720 for ( const d of Acre . enumValues ) {
28- if ( d . symbol === char ) {
21+ if ( d . symbol === char ) {
2922 return d ;
3023 }
3124 }
25+ }
3226
3327class Grid {
34- constructor ( input ) {
35- let splits = input . split ( / \r ? \n / )
36- . map ( ( line ) => line = line . trim ( ) ) ;
37- this . height = splits . length ;
38- this . width = splits [ 0 ] . length ;
28+ constructor ( width , height ) {
29+ this . height = height ;
30+ this . width = width ;
3931 this . grid = Array ( this . height ) ;
4032 for ( let j = 0 ; j < this . height ; j ++ ) {
41- this . grid [ j ] = splits [ j ] . split ( '' ) . map ( char => parse ( char ) ) ;
33+ this . grid [ j ] = new Array ( this . width ) ;
34+ }
35+ }
36+
37+ fill ( inputLines ) {
38+ for ( let j = 0 ; j < this . height ; j ++ ) {
39+ this . grid [ j ] = inputLines [ j ] . split ( '' ) . map ( char => parse ( char ) ) ;
4240 }
4341 }
4442
@@ -62,6 +60,59 @@ class Grid {
6260 console . log ( '' ) ;
6361 }
6462
63+ evolve ( ) {
64+ let nextState = new Grid ( this . width , this . height ) ;
65+ for ( let y = 0 ; y < this . height ; y ++ ) {
66+ for ( let x = 0 ; x < this . width ; x ++ ) {
67+ switch ( this . get ( x , y ) ) {
68+ case Acre . OPEN : {
69+ let woods = this . getNeighbourCount ( x , y , Acre . WOOD ) ;
70+ if ( woods >= 3 ) {
71+ nextState . set ( x , y , Acre . WOOD ) ;
72+ } else {
73+ nextState . set ( x , y , Acre . OPEN ) ;
74+ }
75+ break ;
76+ }
77+ case Acre . WOOD : {
78+ let lumberyards = this . getNeighbourCount ( x , y , Acre . LUMBERYARD ) ;
79+ if ( lumberyards >= 3 ) {
80+ nextState . set ( x , y , Acre . LUMBERYARD ) ;
81+ } else {
82+ nextState . set ( x , y , Acre . WOOD ) ;
83+ }
84+ break ;
85+ }
86+ case Acre . LUMBERYARD : {
87+ let woods = this . getNeighbourCount ( x , y , Acre . WOOD ) ;
88+ let lumberyards = this . getNeighbourCount ( x , y , Acre . LUMBERYARD ) ;
89+ if ( woods > 0 && lumberyards > 0 ) {
90+ nextState . set ( x , y , Acre . LUMBERYARD ) ;
91+ } else {
92+ nextState . set ( x , y , Acre . OPEN ) ;
93+ }
94+ break ;
95+ }
96+ }
97+ }
98+ }
99+ return nextState ;
100+ }
101+
102+ getNeighbourCount ( x , y , type ) {
103+ let count = 0 ;
104+ for ( let i = x - 1 ; i <= x + 1 ; i ++ ) {
105+ for ( let j = y - 1 ; j <= y + 1 ; j ++ ) {
106+ if ( ! ( i == x && j == y ) ) { //don't count self
107+ if ( this . get ( i , j ) == type ) {
108+ count ++ ;
109+ }
110+ }
111+ }
112+ }
113+ return count ;
114+ }
115+
65116 get woods ( ) {
66117 let water = 0 ;
67118 for ( let x = 0 ; x < this . width ; x ++ ) {
@@ -88,87 +139,33 @@ class Grid {
88139}
89140
90141function calculateResourceProduct ( input , iterations = 10 ) {
91- let grid = new Grid ( input ) ;
92- grid . print ( ) ;
93- //floodGrid(input,iterations);
94- return grid . woods * grid . lumberYards ;
95- }
96-
97- function floodGrid ( input ) {
98- let clay = [ ] ;
99- input . split ( / \r ? \n / )
100- . map ( ( line ) => {
101- line = line . trim ( ) ;
102- let result = line . match ( / ( [ x | y ] ) = ( \d + ) , ( [ x | y ] ) = ( \d + ) ..( \d + ) / ) ;
103- if ( result [ 1 ] == 'x' ) {
104- for ( let i = + result [ 4 ] ; i <= + result [ 5 ] ; i ++ ) {
105- clay . push ( new Point ( result [ 2 ] , i ) ) ;
142+ let inputLines = input . split ( / \r ? \n / )
143+ . map ( ( line ) => line = line . trim ( ) ) ;
144+ let grid = new Grid ( inputLines [ 0 ] . length , inputLines . length ) ;
145+ grid . fill ( inputLines ) ;
146+ let cycleSearch = iterations > 500 ;
147+ const results = [ ] ;
148+ let prev = - 1 ;
149+ let result = grid . woods * grid . lumberYards ;
150+ results . push ( result ) ;
151+ for ( let i = 1 ; i <= iterations ; i ++ ) {
152+ grid = grid . evolve ( ) ;
153+ if ( cycleSearch ) {
154+ prev = result ;
155+ result = grid . woods * grid . lumberYards ;
156+ const prevIndex = results . indexOf ( prev ) ;
157+ if ( prevIndex != - 1 && results . indexOf ( result ) == prevIndex + 1 ) {
158+ const cycle = ( i - prevIndex ) - 1 ;
159+ while ( i < iterations - cycle ) {
160+ i += cycle ;
106161 }
162+ cycleSearch = false ;
107163 } else {
108- for ( let i = + result [ 4 ] ; i <= + result [ 5 ] ; i ++ ) {
109- clay . push ( new Point ( i , + result [ 2 ] ) ) ;
110- }
164+ results . push ( result ) ;
111165 }
112- } ) ;
113-
114- const sortX = clay
115- . map ( p => p . x )
116- . sort ( ( a , b ) => b - a ) ;
117- const minX = + sortX [ sortX . length - 1 ] - 1 ;
118- const width = ( sortX [ 0 ] - minX ) + 3 ;
119- const springX = 500 - minX ;
120-
121- const sortY = clay
122- . map ( p => p . y )
123- . sort ( ( a , b ) => b - a ) ;
124- const minY = + sortY [ sortY . length - 1 ] ;
125- const height = ( sortY [ 0 ] - minY ) + 1 ;
126-
127- // console.log('Grid from', minX, minY, ' to ', minX + width, minY + height);
128-
129- let grid = new Grid ( width , height , springX , Acre . SAND ) ;
130- clay . forEach ( pos => grid . set ( pos . x - minX , pos . y - minY , Acre . CLAY ) ) ;
131- //grid.print();
132-
133- propagateWater ( grid , springX , - 1 ) ;
134- //grid.print();
135- return grid ;
136- }
137-
138- function propagateWater ( grid , x , y ) {
139- // console.log('propagateWater', x, y);
140- //grid.print();
141- //console.log('checking below',grid.get(x, y + 1));
142- let below = grid . get ( x , y + 1 ) ;
143- if ( below == Acre . SAND ) {
144- // console.log('settingBelowToRunning');
145- //flow down and continue;
146- grid . set ( x , y + 1 , Acre . RUNNING ) ;
147- propagateWater ( grid , x , y + 1 ) ;
148- }
149- //console.log('below is Blocking',grid.get(x, y + 1));
150- if ( grid . isBlocking ( x , y + 1 ) ) {
151- if ( grid . get ( x + 1 , y ) == Acre . SAND ) {
152- // console.log('settingRightToRunning');
153- grid . set ( x + 1 , y , Acre . RUNNING ) ;
154- propagateWater ( grid , x + 1 , y ) ;
155- }
156- }
157- //console.log('below is Blocking2',grid.get(x, y + 1));
158- if ( grid . isBlocking ( x , y + 1 ) ) {
159- if ( grid . get ( x - 1 , y ) == Acre . SAND ) {
160- // console.log('settingLefttToRunning');
161- grid . set ( x - 1 , y , Acre . RUNNING ) ;
162- propagateWater ( grid , x - 1 , y ) ;
163- }
164- }
165- //console.log('getting bucket');
166- let range = grid . getBucketRange ( x , y ) ;
167- if ( range [ 0 ] <= range [ 1 ] ) {
168- // console.log('filling bucketRange', x, y, range);
169- for ( let i = range [ 0 ] ; i <= range [ 1 ] ; i ++ ) {
170- grid . set ( i , y , Acre . WATER ) ;
171166 }
172167 }
168+ return grid . woods * grid . lumberYards ;
173169}
170+
174171module . exports . calculateResourceProduct = calculateResourceProduct ;
0 commit comments