You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
advent-of-code/2023/ruby/day_16.rb

52 lines
1.4 KiB

input = ARGF.readlines(chomp: true)
.flat_map.with_index {|row, y|
row.chars.map.with_index {|elem, x| [[y,x], elem] }
}.to_h
count_energized = ->(start, dir) {
current = [[start, dir]]
seen = Set.new
until current.empty?
coord, delta = current.shift
seen << [coord, delta]
next_delta = case [input[coord], delta]
in [nil, _]
[] # the beam has escaped the contraption
in [?., _] | [?|, [_,0]] | [?-, [0,_]] # keep going
[delta]
in [?|, [0,_]] # split up and down
[[-1,0], [1,0]]
in [?-, [_,0]] # split left and right
[[0,-1], [0,1]]
in [?/, _]
[delta.map { -_1 }.reverse]
in [?\\, _]
[delta.reverse]
else
fail
end
current.concat(
next_delta
.map {|d| [coord.zip(d).map { _1 + _2 }, d] }
.reject { seen.include?(_1) }
)
end
seen.map(&:first).select { input.has_key?(_1) }.uniq.size
}
max_y = input.keys.map(&:first).max
max_x = input.keys.map(&:last).max
candidates = [
(0..max_x).map { [[0,_1], [1,0]] }, # down
(0..max_x).map { [[max_y,_1], [-1,0]] }, # up
(0..max_y).map { [[_1,0], [0,1]] }, # right
(0..max_y).map { [[_1,max_x], [0,-1]] }, # left
].inject(:+)
p candidates.map { count_energized[*_1] }.max