diff --git a/2023/ruby/day_16.rb b/2023/ruby/day_16.rb index e5bb867..1d7cb7b 100644 --- a/2023/ruby/day_16.rb +++ b/2023/ruby/day_16.rb @@ -3,45 +3,59 @@ input = ARGF.readlines(chomp: true) row.chars.map.with_index {|elem, x| [[y,x], elem] } }.to_h -current = [[[0,0], [0,1]]] -seen = Set.new - -until current.empty? - coord, delta = current.shift - seen << [coord, delta] - - case [elem = input[coord], delta] - in [nil, _] - # the beam has escaped the contraption - in [?., _] | [?|, [_,0]] | [?-, [0,_]] # keep going - current << [coord.zip(delta).map { _1 + _2 }, delta] - in [?|, [0,_]] # split up and down - current << [coord.zip([-1,0]).map { _1 + _2 }, [-1,0]] - current << [coord.zip([1,0]).map { _1 + _2 }, [1,0]] - in [?-, [_,0]] # split left and right - current << [coord.zip([0,-1]).map { _1 + _2 }, [0,-1]] - current << [coord.zip([0,1]).map { _1 + _2 }, [0,1]] - in [?/, [0,1]] # going right, goes up - current << [coord.zip([-1,0]).map { _1 + _2 }, [-1,0]] - in [?/, [0,-1]] # going left, goes down - current << [coord.zip([1,0]).map { _1 + _2 }, [1,0]] - in [?/, [1,0]] # going down, goes left - current << [coord.zip([0,-1]).map { _1 + _2 }, [0,-1]] - in [?/, [-1,0]] # going up, goes right - current << [coord.zip([0,1]).map { _1 + _2 }, [0,1]] - in [?\\, [0,1]] # going right, goes down - current << [coord.zip([1,0]).map { _1 + _2 }, [1,0]] - in [?\\, [0,-1]] # going left, goes up - current << [coord.zip([-1,0]).map { _1 + _2 }, [-1,0]] - in [?\\, [1,0]] # going down, goes right - current << [coord.zip([0,1]).map { _1 + _2 }, [0,1]] - in [?\\, [-1,0]] # going up, goes left - current << [coord.zip([0,-1]).map { _1 + _2 }, [0,-1]] - else - fail "unexpected element: #{elem.inspect}" +count_energized = ->(start, dir) { + current = [[start, dir]] + seen = Set.new + + until current.empty? + coord, delta = current.shift + seen << [coord, delta] + + case [elem = input[coord], delta] + in [nil, _] + # the beam has escaped the contraption + in [?., _] | [?|, [_,0]] | [?-, [0,_]] # keep going + current << [coord.zip(delta).map { _1 + _2 }, delta] + in [?|, [0,_]] # split up and down + current << [coord.zip([-1,0]).map { _1 + _2 }, [-1,0]] + current << [coord.zip([1,0]).map { _1 + _2 }, [1,0]] + in [?-, [_,0]] # split left and right + current << [coord.zip([0,-1]).map { _1 + _2 }, [0,-1]] + current << [coord.zip([0,1]).map { _1 + _2 }, [0,1]] + in [?/, [0,1]] # going right, goes up + current << [coord.zip([-1,0]).map { _1 + _2 }, [-1,0]] + in [?/, [0,-1]] # going left, goes down + current << [coord.zip([1,0]).map { _1 + _2 }, [1,0]] + in [?/, [1,0]] # going down, goes left + current << [coord.zip([0,-1]).map { _1 + _2 }, [0,-1]] + in [?/, [-1,0]] # going up, goes right + current << [coord.zip([0,1]).map { _1 + _2 }, [0,1]] + in [?\\, [0,1]] # going right, goes down + current << [coord.zip([1,0]).map { _1 + _2 }, [1,0]] + in [?\\, [0,-1]] # going left, goes up + current << [coord.zip([-1,0]).map { _1 + _2 }, [-1,0]] + in [?\\, [1,0]] # going down, goes right + current << [coord.zip([0,1]).map { _1 + _2 }, [0,1]] + in [?\\, [-1,0]] # going up, goes left + current << [coord.zip([0,-1]).map { _1 + _2 }, [0,-1]] + else + fail "unexpected element: #{elem.inspect}" + end + + current = current.reject { seen.include?(_1) } end - current = current.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 seen.map(&:first).select { input.has_key?(_1) }.uniq.size +p candidates.map { count_energized[*_1] }.max