@@ -44,6 +44,7 @@ class HotSprings
44
44
45
45
def initialize ( input = "" )
46
46
@input = input
47
+ @scan_cache = Hash . new
47
48
@rows =
48
49
@input
49
50
. split ( "\n " )
@@ -84,50 +85,54 @@ def maybe_damaged?(spring)
84
85
85
86
# @example 1st row
86
87
# new.scan("???.###", [1,1,3]) #=> 1
88
+ # new("???.### 1,1,3").unfold.map{ new.scan(*_1)}.first #=> 1
87
89
#
88
90
# @example 2nd row
89
91
# new.scan(".??..??...?##.", [1,1,3]) #=> 4
92
+ # new(".??..??...?##. 1,1,3").unfold.map{ new.scan(*_1)}.first #=> 16384
90
93
#
91
94
# @example 3rd row
92
95
# new.scan("?#?#?#?#?#?#?#?", [1,3,1,6]) #=> 1
96
+ # new("?#?#?#?#?#?#?#? 1,3,1,6").unfold.map{ new.scan(*_1)}.first #=> 1
93
97
#
94
98
# @example 4th row
95
99
# new.scan("????.#...#...", [4,1,1]) #=> 1
100
+ # new("????.#...#... 4,1,1").unfold.map{ new.scan(*_1)}.first #=> 16
96
101
#
97
102
# @example 5th row
98
103
# new.scan("????.######..#####.", [1,6,5]) #=> 4
104
+ # new("????.######..#####. 1,6,5").unfold.map{ new.scan(*_1)}.first #=> 2500
99
105
#
100
106
# @example 6th row
101
107
# new.scan("?###????????", [3,2,1]) #=> 10
108
+ # new("?###???????? 3,2,1").unfold.map{ new.scan(*_1)}.first #=> 506250
102
109
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
105
115
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
108
119
109
- # OK, we gotta compute stuff ...
120
+ elsif counts [ 0 ] == 0
121
+ maybe_working? ( springs [ 0 ] ) ? scan ( springs [ 1 ..] , counts [ 1 ..] , false ) : 0
110
122
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
114
125
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 )
118
128
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 )
121
131
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
+ }
132
137
end
133
138
end
0 commit comments