|
1 | 1 | require_relative 'day'
|
2 |
| -require_relative 'ugly_sweater' |
3 | 2 |
|
4 | 3 | class Day12 < Day # >
|
5 | 4 |
|
@@ -44,6 +43,7 @@ class HotSprings
|
44 | 43 |
|
45 | 44 | def initialize(input="")
|
46 | 45 | @input = input
|
| 46 | + @scan_cache = Hash.new |
47 | 47 | @rows =
|
48 | 48 | @input
|
49 | 49 | .split("\n")
|
@@ -83,51 +83,61 @@ def maybe_damaged?(spring)
|
83 | 83 | end
|
84 | 84 |
|
85 | 85 | # @example 1st row
|
86 |
| - # new.scan("???.###", [1,1,3]) #=> 1 |
| 86 | + # ♨️ = new("???.### 1,1,3") |
| 87 | + # ♨️.rows.map { ♨️.scan(*_1) }.first #=> 1 |
| 88 | + # ♨️.unfold.map{ new.scan(*_1) }.first #=> 1 |
87 | 89 | #
|
88 | 90 | # @example 2nd row
|
89 |
| - # new.scan(".??..??...?##.", [1,1,3]) #=> 4 |
| 91 | + # ♨️ = new(".??..??...?##. 1,1,3") |
| 92 | + # ♨️.rows.map { ♨️.scan(*_1) }.first #=> 4 |
| 93 | + # ♨️.unfold.map{ new.scan(*_1) }.first #=> 16384 |
90 | 94 | #
|
91 | 95 | # @example 3rd row
|
92 |
| - # new.scan("?#?#?#?#?#?#?#?", [1,3,1,6]) #=> 1 |
| 96 | + # ♨️ = new("?#?#?#?#?#?#?#? 1,3,1,6") |
| 97 | + # ♨️.rows.map { ♨️.scan(*_1) }.first #=> 1 |
| 98 | + # ♨️.unfold.map{ new.scan(*_1) }.first #=> 1 |
93 | 99 | #
|
94 | 100 | # @example 4th row
|
95 |
| - # new.scan("????.#...#...", [4,1,1]) #=> 1 |
| 101 | + # ♨️ = new("????.#...#... 4,1,1") |
| 102 | + # ♨️.rows.map { ♨️.scan(*_1) }.first #=> 1 |
| 103 | + # ♨️.unfold.map{ new.scan(*_1) }.first #=> 16 |
96 | 104 | #
|
97 | 105 | # @example 5th row
|
98 |
| - # new.scan("????.######..#####.", [1,6,5]) #=> 4 |
| 106 | + # ♨️ = new("????.######..#####. 1,6,5") |
| 107 | + # ♨️.rows.map { ♨️.scan(*_1) }.first #=> 4 |
| 108 | + # ♨️.unfold.map{ new.scan(*_1) }.first #=> 2500 |
99 | 109 | #
|
100 | 110 | # @example 6th row
|
101 |
| - # new.scan("?###????????", [3,2,1]) #=> 10 |
| 111 | + # ♨️ = new("?###???????? 3,2,1") |
| 112 | + # ♨️.rows.map { ♨️.scan(*_1) }.first #=> 10 |
| 113 | + # ♨️.unfold.map{ new.scan(*_1) }.first #=> 506250 |
102 | 114 | 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? |
| 115 | + return @scan_cache.fetch([springs, counts, previous_maybe_damaged]) { |key| |
| 116 | + @scan_cache[key] = |
| 117 | + if counts.empty? |
| 118 | + # what's left shouldn't be damaged if the trusted counts say there are no more damaged springs |
| 119 | + springs.include?(DAMAGED) ? 0 : 1 |
105 | 120 |
|
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? |
| 121 | + elsif springs.empty? |
| 122 | + # the trusted counts shouldn't say there are more damaged when we're out of springs to evaluate |
| 123 | + counts.reduce(&:+).positive? ? 0 : 1 |
108 | 124 |
|
109 |
| - # OK, we gotta compute stuff ... |
| 125 | + elsif counts[0] == 0 |
| 126 | + maybe_working?(springs[0]) ? scan(springs[1..], counts[1..], false) : 0 |
110 | 127 |
|
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) |
| 128 | + elsif previous_maybe_damaged |
| 129 | + maybe_damaged?(springs[0]) ? scan(springs[1..], ([counts[0]-1] + counts[1..]), true) : 0 |
114 | 130 |
|
115 |
| - case |
116 |
| - when current_count == 0 |
117 |
| - return maybe_working?(current_spring) ? scan(remaining_springs, remaining_counts, false) : 0 |
| 131 | + elsif springs[0] == DAMAGED |
| 132 | + scan(springs[1..], ([counts[0]-1] + counts[1..]), true) |
118 | 133 |
|
119 |
| - when previous_maybe_damaged |
120 |
| - return maybe_damaged?(current_spring) ? scan(remaining_springs, decremented_counts, true) : 0 |
| 134 | + elsif springs[0] == WORKING |
| 135 | + scan(springs[1..], counts, false) |
121 | 136 |
|
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 |
| 137 | + else |
| 138 | + scan(springs[1..], counts, false) + # run the scenarios where first spring is working |
| 139 | + scan(springs[1..], ([counts[0]-1] + counts[1..]), true) # and the scenarios where first is/might-be broken |
| 140 | + end |
| 141 | + } |
132 | 142 | end
|
133 | 143 | end
|
0 commit comments