136 lines
2.6 KiB
Ruby
Executable file
136 lines
2.6 KiB
Ruby
Executable file
#!/usr/bin/env ruby
|
|
|
|
require "debug"
|
|
require "matrix"
|
|
|
|
input = (ARGV.first.nil? ? DATA : ARGF)
|
|
.readlines(chomp: true)
|
|
input2 = input
|
|
.map { _1.gsub("#", "##").gsub("O", "[]").gsub(".", "..").gsub("@", "@.") }
|
|
|
|
split = input.index("")
|
|
|
|
DIRECTIONS = {
|
|
"^" => Vector[-1, 0],
|
|
">" => Vector[0, 1],
|
|
"v" => Vector[1, 0],
|
|
"<" => Vector[0, -1]
|
|
}
|
|
|
|
@grid = input[0...split].map(&:chars)
|
|
@grid2 = input2[0...split].map(&:chars)
|
|
@moves = input[split+1..].map(&:chars).flatten
|
|
|
|
def find_robot
|
|
@robot = nil
|
|
(0...@grid.size).each do |x|
|
|
break unless @robot.nil?
|
|
(0...@grid.first.size).each do |y|
|
|
if @grid[x][y] == "@"
|
|
@grid[x][y] = "."
|
|
return Vector[x, y]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def print_grid(grid)
|
|
counts = Hash.new { |h, k| h[k] = 0 }
|
|
grid.each_with_index do |row, x|
|
|
row.each_with_index do |val, y|
|
|
if @robot == Vector[x, y]
|
|
counts["@"] += 1
|
|
print "@"
|
|
else
|
|
counts[val] += 1
|
|
print val
|
|
end
|
|
end
|
|
puts
|
|
end
|
|
p counts
|
|
p @robot
|
|
puts
|
|
puts
|
|
end
|
|
|
|
def push(location, direction, called_by, test:)
|
|
return false if @grid.dig(*location) == "#"
|
|
return true if @grid.dig(*location) == "."
|
|
|
|
location_value = @grid.dig(*location)
|
|
|
|
move_to = location + direction
|
|
|
|
result = if ["[", "]"].include?(location_value)
|
|
move_to = location + direction
|
|
pair = location + (location_value == "[" ? Vector[0, 1] : Vector[0, -1])
|
|
|
|
if pair == move_to || pair == called_by
|
|
push(move_to, direction, location, test: test)
|
|
else
|
|
push(move_to, direction, location, test: test) && push(pair, direction, location, test: test)
|
|
end
|
|
else
|
|
push(move_to, direction, location, test: test)
|
|
end
|
|
|
|
if result && test == false
|
|
@grid[move_to[0]][move_to[1]] = location_value
|
|
@grid[location[0]][location[1]] = "."
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
def predict
|
|
@moves.each do |move|
|
|
robot_next = @robot + DIRECTIONS[move]
|
|
|
|
block = @grid.dig(*robot_next.to_a)
|
|
|
|
case block
|
|
when "#" # robot does not move
|
|
when "." # robot can take position
|
|
@robot = robot_next
|
|
else # it's a box (of some sort)
|
|
res = push(robot_next, DIRECTIONS[move], @robot, test: true)
|
|
if res
|
|
push(robot_next, DIRECTIONS[move], @robot, test: false)
|
|
@robot = robot_next
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def compute_gps
|
|
(0...@grid.size).map do |x|
|
|
(0...@grid.first.size).map do |y|
|
|
["O", "["].include?(@grid[x][y]) ? 100 * x + y : 0
|
|
end
|
|
end.flatten.sum
|
|
end
|
|
|
|
# part 1
|
|
@robot = find_robot
|
|
predict
|
|
p compute_gps
|
|
|
|
# part 2
|
|
@grid = @grid2
|
|
@robot = find_robot
|
|
predict
|
|
p compute_gps
|
|
|
|
__END__
|
|
######
|
|
#....#
|
|
#@O..#
|
|
#.OO.#
|
|
#.O..#
|
|
#.O..#
|
|
#.#..#
|
|
#....#
|
|
######
|
|
|
|
>>^>>v
|