diff --git a/2024/ruby/day_16.rb b/2024/ruby/day_16.rb new file mode 100644 index 0000000..30b96f2 --- /dev/null +++ b/2024/ruby/day_16.rb @@ -0,0 +1,62 @@ +tiles = DATA.readlines(chomp: true).flat_map.with_index {|row, y| + row.chars.filter_map.with_index {|tile, x| + tile == ?# ? nil : [[y,x], tile] + } +}.to_h + +start, stop = %w[ S E ].map {|t| tiles.find { _2 == t }[0] } + +scores = Hash.new(Float::INFINITY) +scores[[start, [0,1]]] = 0 + +queue = [[start, [0,1]]] +visited = Set.new +loop do + fail if queue.empty? + + current, dir = queue.shift + visited << [current, dir] + score = scores.fetch([current, dir]) + break if current == stop + + # straight ahead + yx = current.zip(dir).map { _1 + _2 } + if tiles.has_key?(yx) + scores[[yx, dir]] = [scores[[yx, dir]], score + 1].min + queue << [yx, dir] unless visited.include?([yx, dir]) + end + + # sides + [-1, 1].each do |d| + delta = dir.reverse.zip([d, d]).map { _1 * _2 } + yx = current.zip(delta).map { _1 + _2 } + if tiles.has_key?(yx) + scores[[yx, delta]] = [scores[[yx, delta]], score + 1001].min + queue << [yx, delta] unless visited.include?([yx, delta]) + end + end + + queue.uniq! + queue.sort_by! { scores.fetch(_1) } +end + +pp scores.find {|(yx,_),_| yx == stop }[1] + +__END__ +################# +#...#...#...#..E# +#.#.#.#.#.#.#.#^# +#.#.#.#...#...#^# +#.#.#.#.###.#.#^# +#>>v#.#.#.....#^# +#^#v#.#.#.#####^# +#^#v..#.#.#>>>>^# +#^#v#####.#^###.# +#^#v#..>>>>^#...# +#^#v###^#####.### +#^#v#>>^#.....#.# +#^#v#^#####.###.# +#^#v#^........#.# +#^#v#^#########.# +#S#>>^..........# +#################