Snippet

advent_of_code/2024_15.rb
Code:
# Advent of Code 2024, Day 15: Warehouse Woes

# https://adventofcode.com/2024/day/15

require_relative './helpers.rb'

class Obstacle
  attr_accessor :type, :pos

  def initialize(type, pos)
    @type, @pos = type, pos
  end

  def try(g, d)
    o = get_grid(g, [@pos.x + d.x, @pos.y + d.y].to_p)
    return false if o.type == '#'
    return true if o.type == '.'
    return o.try(g, d) if o.type == 'O'
    if o.type == '[' || o.type == ']'
      return o.try(g, d) if d.y == 0
      a = get_grid(g, [o.pos.x + (o.type == '[' ? 1 : -1), o.pos.y].to_p)
      o.try(g, d) && a.try(g, d)
    end
  end

  def move(g, d)
    return unless try(g, d)
    o = get_grid(g, [@pos.x + d.x, @pos.y + d.y].to_p)
    o.move(g, d) if o.type == 'O'
    if o.type == '[' || o.type == ']'
      a = get_grid(g, [o.pos.x + (o.type == '[' ? 1 : -1), o.pos.y].to_p)
      a.move(g, d) if d.x == 0
      o.move(g, d)
    end
    o.type, @type = @type, '.'
  end
end

def simulate(grid, steps)
  grid.map!.with_index { |row, y| row.map.with_index { |cell, x| Obstacle.new(cell, [x, y].to_p) } }
  r = grid.flatten.filter { |o| o.type == '@' }.compact.first
  steps.each { |s| r = get_grid(grid, [r.pos.x + s.x, r.pos.y + s.y].to_p) if r.move(grid, s) }
  grid.each { |r| r.each { |o| print o.type }; print "\n" } if grid.size < 20
  return grid
end

def part_one(grid, steps)
  simulate(grid, steps).flatten.sum { |o| o.type == 'O' ? (o.pos.x + o.pos.y * 100) : 0}
end

def part_two(grid, steps)
  grid.map! { |r| r.map { |c| c == '@' ? '@.' : (c == 'O' ? '[]' : c * 2) }.join.chars }
  simulate(grid, steps).flatten.sum { |o| o.type == '[' ? (o.pos.x + o.pos.y * 100) : 0}
end

def solve(data)
  grid, steps = [], []
  data.each { |l| '^>v<'.chars.include?(l[0]) ? (steps += l.chars) : (grid << l.chars) }
  steps.map! { |s| { '>' => [1, 0], 'v' => [0, 1], '<' => [-1, 0], '^' => [0, -1] }[s].to_p }
  [part_one(copy_grid(grid), steps), part_two(copy_grid(grid), steps)]
end

puts solve(get_dataset(year: 2024, day: 15, type: 'example'))
puts solve(get_dataset(year: 2024, day: 15, type: 'example_2'))
puts solve(get_dataset(year: 2024, day: 15, type: 'example_3'))
puts solve(get_dataset(year: 2024, day: 15, type: 'input'))
Output:
##########
#.O.O.OOO#
#........#
#OO......#
#OO@.....#
#O#.....O#
#O.....OO#
#O.....OO#
#OO....OO#
##########

####################
##[].......[].[][]##
##[]...........[].##
##[]........[][][]##
##[]......[]....[]##
##..##......[]....##
##..[]............##
##..@......[].[][]##
##......[][]..[]..##
####################

10092
9021
########
#....OO#
##.....#
#.....O#
#.#O@..#
#...O..#
#...O..#
########

################
##......[][]..##
####....[]....##
##......[]....##
##..##...[]...##
##....@.......##
##......[]....##
################

2028
1751
#######
#@..#.#
#.O...#
#..O..#
#..O..#
#.....#
#######

##############
##...[].##..##
##...@.[]...##
##....[]....##
##..........##
##..........##
##############

908
618
1318523
1337648