Skip to content

Commit c582fe7

Browse files
author
Robb Kidd
committed
day 12, part 1
Cobbled together from reading other people's solutions. I was going to regex-validate the combinatorials like a silly person.
1 parent ff7441d commit c582fe7

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

2023/ruby/day12.rb

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
require_relative 'day'
2+
require_relative 'ugly_sweater'
3+
4+
class Day12 < Day # >
5+
6+
# @example
7+
# day.part1 #=> 21
8+
def part1
9+
@hot_springs ||= HotSprings.new(input)
10+
11+
@hot_springs
12+
.rows
13+
.map { |springs, damaged_counts|
14+
@hot_springs.scan(springs, damaged_counts)
15+
}
16+
.reduce(&:+)
17+
end
18+
19+
# example
20+
# #day.part2 #=> 'how are you'
21+
def part2
22+
end
23+
24+
EXAMPLE_INPUT = <<~INPUT
25+
???.### 1,1,3
26+
.??..??...?##. 1,1,3
27+
?#?#?#?#?#?#?#? 1,3,1,6
28+
????.#...#... 4,1,1
29+
????.######..#####. 1,6,5
30+
?###???????? 3,2,1
31+
INPUT
32+
end
33+
34+
class HotSprings
35+
attr_reader :input, :rows
36+
37+
def initialize(input="")
38+
@input = input
39+
@rows =
40+
@input
41+
.split("\n")
42+
.map { |line|
43+
springs, damaged_counts = line.split(" ")
44+
[
45+
springs,
46+
damaged_counts.split(",").map(&:to_i)
47+
]
48+
}
49+
end
50+
51+
WORKING = "."
52+
DAMAGED = "#"
53+
UNKNOWN = "?"
54+
55+
def maybe_working?(spring)
56+
[UNKNOWN, WORKING].include?(spring)
57+
end
58+
59+
def maybe_damaged?(spring)
60+
[UNKNOWN, DAMAGED].include?(spring)
61+
end
62+
63+
# @example 1st row
64+
# new.scan("???.###", [1,1,3]) #=> 1
65+
#
66+
# @example 2nd row
67+
# new.scan(".??..??...?##.", [1,1,3]) #=> 4
68+
#
69+
# @example 3rd row
70+
# new.scan("?#?#?#?#?#?#?#?", [1,3,1,6]) #=> 1
71+
#
72+
# @example 4th row
73+
# new.scan("????.#...#...", [4,1,1]) #=> 1
74+
#
75+
# @example 5th row
76+
# new.scan("????.######..#####.", [1,6,5]) #=> 4
77+
#
78+
# @example 6th row
79+
# new.scan("?###????????", [3,2,1]) #=> 10
80+
def scan(springs, counts, previous_maybe_damaged=false)
81+
# what's left shouldn't be damaged if the trusted counts say there are no more damaged springs
82+
return (springs.include?(DAMAGED) ? 0 : 1) if counts.empty?
83+
84+
# the trusted counts shouldn't say there are more damaged when we're out of springs to evaluate
85+
return (counts.reduce(&:+).positive? ? 0 : 1) if springs.empty?
86+
87+
# OK, we gotta compute stuff ...
88+
89+
current_spring, remaining_springs = springs[0], springs[1..]
90+
current_count, remaining_counts = counts[0], counts[1..]
91+
decremented_counts = ([current_count-1] + remaining_counts)
92+
93+
case
94+
when current_count == 0
95+
return maybe_working?(current_spring) ? scan(remaining_springs, remaining_counts, false) : 0
96+
97+
when previous_maybe_damaged
98+
return maybe_damaged?(current_spring) ? scan(remaining_springs, decremented_counts, true) : 0
99+
100+
when current_spring == DAMAGED
101+
return scan(remaining_springs, decremented_counts, true)
102+
103+
when current_spring == WORKING
104+
return scan(remaining_springs, counts, false)
105+
106+
else
107+
return scan(remaining_springs, counts, false) + # run the scenarios where first spring is working
108+
scan(remaining_springs, decremented_counts, true) # and the scenarios where first is/might-be broken
109+
end
110+
end
111+
end

0 commit comments

Comments
 (0)