1
0
Fork 0
advent-of-code-2024/21/main.rb
Andrew Tomaka 45056ce1fa
First incorrect attempt
does not recheck all possible paths that have the same complexity
2024-12-22 01:44:35 -05:00

176 lines
3.8 KiB
Ruby
Executable file

#!/usr/bin/env ruby
require "debug"
input = (ARGV.first.nil? ? DATA : ARGF)
.readlines(chomp: true)
.map(&:chars)
@arrow_dirs = {
"<" => [0, -1],
"^" => [-1, 0],
">" => [0, 1],
"v" => [1, 0],
}
@dir_arrows = @arrow_dirs.invert
number_movements = {
"0" => ["^", ">"],
"A" => ["<", "^"],
"1" => ["^", ">"],
"2" => ["<", "^", ">", "v"],
"3" => ["<", "^", "v"],
"4" => ["^", ">", "v"],
"5" => ["<", "^", ">", "v"],
"6" => ["<", "^", "v"],
"7" => [">", "v"],
"8" => ["<", ">", "v"],
"9" => ["<", "v"],
}
arrow_movements = {
"^" => [">", "v"],
"A" => ["v", "<"],
"<" => [">"],
"v" => ["^", ">", "<"],
">" => ["^", "<"],
}
number_grid = [
["7", "8", "9"],
["4", "5", "6"],
["1", "2", "3"],
["#", "0", "A"],
]
arrow_grid = [
["#", "^", "A"],
["<", "v", ">"],
]
class PriorityQueue < Array
alias_method :extract_min, :shift
def <<(v)
super
sort_by!(&:last)
end
end
def discover(char, graph)
(0...graph.size).each do |x|
(0...graph.first.size).each do |y|
return [x, y] if char == graph.dig(x, y)
end
end
end
def dijkstra_with_lookup(graph, movements, start_char, target_char)
start = discover(start_char, graph)
target = discover(target_char, graph)
dijkstra(graph, movements, start, target)
end
def dijkstra(graph, movements, start, target)
queue = PriorityQueue.new
dest = Hash.new
prev = Hash.new
queue << [start, 0]
dest[start] = 0
prev[start] = nil
until queue.empty?
node, moves = queue.extract_min
movements[graph.dig(*node)]
.map { @arrow_dirs[_1] }
.map { |dx, dy| [node.first + dx, node.last + dy] }
.each do |neighbor|
if dest[neighbor].nil? || moves + 1 < dest[neighbor]
dest[neighbor] = moves + 1
prev[neighbor] = node
queue << [neighbor, moves + 1]
end
end
end
path = Array.new
u = target
while prev[u]
path.unshift(u)
u = prev[u]
end
return dest, path
end
# calculate most efficient number pad paths
# actually AN efficient path; ties not included :\
number_cache = number_grid
.flatten.reject { _1 == "#" || _2 == "#" }
.permutation(2).to_a
.map { [[_1, _2], dijkstra_with_lookup(number_grid, number_movements, _1, _2)] }
.map do |(start, target), (dest, prev)|
presses = ([discover(start, number_grid)] + prev)
.each_cons(2).to_a
.map { @dir_arrows[[_2.first - _1.first, _2.last - _1.last]] }
[[start, target], presses]
end
.to_h
# cache efficient direction movements
arrow_cache = arrow_grid
.flatten.reject { _1 == "#" || _2 == "#" }
.permutation(2).to_a
.map { [[_1, _2], dijkstra_with_lookup(arrow_grid, arrow_movements, _1, _2)] }
.map do |(start, target), (dest, prev)|
presses = ([discover(start, arrow_grid)] + prev)
.each_cons(2).to_a
.map { @dir_arrows[[_2.first - _1.first, _2.last - _1.last]] }
[[start, target], presses]
end
.to_h
arrow_cache[["<", "<"]] = ["A"]
arrow_cache[["^", "^"]] = ["A"]
arrow_cache[[">", ">"]] = ["A"]
arrow_cache[["v", "v"]] = ["A"]
arrow_cache[["A", "A"]] = ["A"]
robot_2 = input
.map { ["A"] + _1 }
.map { _1.each_cons(2).to_a }
.map { _1.map { |move| number_cache[move].join }.join("A") + "A" }
robot_3 = robot_2
.map { _1.chars }
.map { ["A"] + _1 }
.map { _1.each_cons(2).to_a }
.map { _1.map { |move| arrow_cache[move].join }.join("A") + "A" }
me = robot_3
.map { _1.chars }
.map { ["A"] + _1 }
.map { _1.each_cons(2).to_a }
.map { _1.map { |move| arrow_cache[move].join }.join("A") + "A" }
pp " <vA<AA>>^AvAA<^A>A<v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A"
pp me
me.each_with_index do |entry, i|
p "#{entry.length} * #{input[i].join.to_i} = #{entry.length * input[i].join.to_i}"
end
p me.map.with_index { |entry, i| entry.length * input[i].join.to_i }.sum
#debugger
__END__
029A
980A
179A
456A
379A