@@ -44,6 +44,7 @@ class HotSprings
4444
4545 def initialize ( input = "" )
4646 @input = input
47+ @scan_cache = Hash . new
4748 @rows =
4849 @input
4950 . split ( "\n " )
@@ -84,50 +85,54 @@ def maybe_damaged?(spring)
8485
8586 # @example 1st row
8687 # new.scan("???.###", [1,1,3]) #=> 1
88+ # new("???.### 1,1,3").unfold.map{ new.scan(*_1)}.first #=> 1
8789 #
8890 # @example 2nd row
8991 # new.scan(".??..??...?##.", [1,1,3]) #=> 4
92+ # new(".??..??...?##. 1,1,3").unfold.map{ new.scan(*_1)}.first #=> 16384
9093 #
9194 # @example 3rd row
9295 # new.scan("?#?#?#?#?#?#?#?", [1,3,1,6]) #=> 1
96+ # new("?#?#?#?#?#?#?#? 1,3,1,6").unfold.map{ new.scan(*_1)}.first #=> 1
9397 #
9498 # @example 4th row
9599 # new.scan("????.#...#...", [4,1,1]) #=> 1
100+ # new("????.#...#... 4,1,1").unfold.map{ new.scan(*_1)}.first #=> 16
96101 #
97102 # @example 5th row
98103 # new.scan("????.######..#####.", [1,6,5]) #=> 4
104+ # new("????.######..#####. 1,6,5").unfold.map{ new.scan(*_1)}.first #=> 2500
99105 #
100106 # @example 6th row
101107 # new.scan("?###????????", [3,2,1]) #=> 10
108+ # new("?###???????? 3,2,1").unfold.map{ new.scan(*_1)}.first #=> 506250
102109 def scan ( springs , counts , previous_maybe_damaged = false )
103- # what's left shouldn't be damaged if the trusted counts say there are no more damaged springs
104- return ( springs . include? ( DAMAGED ) ? 0 : 1 ) if counts . empty?
110+ return @scan_cache . fetch ( [ springs , counts , previous_maybe_damaged ] ) { |key |
111+ @scan_cache [ key ] =
112+ if counts . empty?
113+ # what's left shouldn't be damaged if the trusted counts say there are no more damaged springs
114+ springs . include? ( DAMAGED ) ? 0 : 1
105115
106- # the trusted counts shouldn't say there are more damaged when we're out of springs to evaluate
107- return ( counts . reduce ( &:+ ) . positive? ? 0 : 1 ) if springs . empty?
116+ elsif springs . empty?
117+ # the trusted counts shouldn't say there are more damaged when we're out of springs to evaluate
118+ counts . reduce ( &:+ ) . positive? ? 0 : 1
108119
109- # OK, we gotta compute stuff ...
120+ elsif counts [ 0 ] == 0
121+ maybe_working? ( springs [ 0 ] ) ? scan ( springs [ 1 ..] , counts [ 1 ..] , false ) : 0
110122
111- current_spring , remaining_springs = springs [ 0 ] , springs [ 1 ..]
112- current_count , remaining_counts = counts [ 0 ] , counts [ 1 ..]
113- decremented_counts = ( [ current_count -1 ] + remaining_counts )
123+ elsif previous_maybe_damaged
124+ maybe_damaged? ( springs [ 0 ] ) ? scan ( springs [ 1 ..] , ( [ counts [ 0 ] -1 ] + counts [ 1 ..] ) , true ) : 0
114125
115- case
116- when current_count == 0
117- return maybe_working? ( current_spring ) ? scan ( remaining_springs , remaining_counts , false ) : 0
126+ elsif springs [ 0 ] == DAMAGED
127+ scan ( springs [ 1 ..] , ( [ counts [ 0 ] -1 ] + counts [ 1 ..] ) , true )
118128
119- when previous_maybe_damaged
120- return maybe_damaged? ( current_spring ) ? scan ( remaining_springs , decremented_counts , true ) : 0
129+ elsif springs [ 0 ] == WORKING
130+ scan ( springs [ 1 .. ] , counts , false )
121131
122- when current_spring == DAMAGED
123- return scan ( remaining_springs , decremented_counts , true )
124-
125- when current_spring == WORKING
126- return scan ( remaining_springs , counts , false )
127-
128- else
129- return scan ( remaining_springs , counts , false ) + # run the scenarios where first spring is working
130- scan ( remaining_springs , decremented_counts , true ) # and the scenarios where first is/might-be broken
131- end
132+ else
133+ scan ( springs [ 1 ..] , counts , false ) + # run the scenarios where first spring is working
134+ scan ( springs [ 1 ..] , ( [ counts [ 0 ] -1 ] + counts [ 1 ..] ) , true ) # and the scenarios where first is/might-be broken
135+ end
136+ }
132137 end
133138end
0 commit comments