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/2022/ruby/day_14.rb

53 lines
1.2 KiB

scan = ARGF.read.lines(chomp: true)
cave = scan.each.with_object({}) {|line, cave|
line.split(" -> ")
.map { _1.split(?,).map(&:to_i) }
.each_cons(2) {|(ax,ay),(bx,by)|
Range.new(*[ax, bx].sort).each do |x|
Range.new(*[ay, by].sort).each do |y|
cave[[x, y]] = ?#
end
end
}
}
def cave.to_s
x_min, x_max = keys.map(&:first).minmax
y_min, y_max = keys.map(&:last).minmax
(0..y_max+1).map {|y|
(x_min-1..x_max+1).map {|x|
self.fetch([x, y], ?.)
}.join
}.join("\n")
end
def pour_sand(cave, stop:)
return enum_for(__method__, cave, stop:) unless block_given?
loop do
# puts cave
pos = [500, 0]
while next_pos = [0, -1, 1].map {|dx| pos.zip([dx, 1]).map { _1 + _2 }}.find { cave[_1].nil? }
pos = next_pos
break if stop.(*pos)
end
break if stop.(*pos)
cave[pos] = ?o
yield pos
end
end
y_max = cave.keys.map(&:last).max
# part one
p pour_sand(cave, stop: ->(_, y) { y >= y_max }).count
# part two
cave.delete_if { _2 == ?o } # reset cave
cave.default_proc = ->(_,(_,y)) { y == y_max + 2 ? ?# : nil }
p pour_sand(cave, stop: ->(x, y) { [x, y] == [500, 0] }).count + 1