1
0
Fork 0

Day twenty-one Part one

This commit is contained in:
Andrew Tomaka 2024-12-25 10:52:41 -05:00
parent c6c314ca30
commit 3e6096cb9f
Signed by: atomaka
GPG key ID: 61209BF70A5B18BE
2 changed files with 342 additions and 0 deletions

5
21/input Normal file
View file

@ -0,0 +1,5 @@
140A
169A
170A
528A
340A

337
21/main.rb Executable file
View file

@ -0,0 +1,337 @@
#!/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
numeric_movements = {
"0" => ["^", ">"],
"A" => ["<", "^"],
"1" => ["^", ">"],
"2" => ["<", "^", ">", "v"],
"3" => ["<", "^", "v"],
"4" => ["^", ">", "v"],
"5" => ["<", "^", ">", "v"],
"6" => ["<", "^", "v"],
"7" => [">", "v"],
"8" => ["<", ">", "v"],
"9" => ["<", "v"],
}
directional_movements = {
"^" => [">", "v"],
"A" => ["v", "<"],
"<" => [">"],
"v" => ["^", ">", "<"],
">" => ["^", "<"],
}
numeric_keypad = [
["7", "8", "9"],
["4", "5", "6"],
["1", "2", "3"],
[nil, "0", "A"],
]
directional_keypad = [
[nil, "^", "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_paths(prev, target, current_path = [])
return [current_path.reverse] if prev[target].nil?
prev[target].flat_map do |parent|
dijkstra_paths(prev, parent, current_path + [target])
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|
new_moves = moves + 1
if dest[neighbor].nil? || new_moves < dest[neighbor]
dest[neighbor] = new_moves
prev[neighbor] = [node]
queue << [neighbor, new_moves]
elsif new_moves == dest[neighbor]
prev[neighbor] << node
end
end
end
paths = dijkstra_paths(prev, target)
return dest, paths
end
# calculate most efficient number pad paths
# actually AN efficient path; ties not included :\
# @numeric_map = numeric_keypad
# .flatten.reject { _1.nil? }
# .permutation(2).to_a
# .map { [[_1, _2], dijkstra_with_lookup(numeric_keypad, numeric_movements, _1, _2)] }
# .map do |(start, target), (dest, paths)|
# presses = paths.map do |path|
# ([discover(start, numeric_keypad)] + path)
# .each_cons(2).to_a
# .map { @dir_arrows[[_2.first - _1.first, _2.last - _1.last]] }.join
# end
# [[start, target], presses]
# end
# .to_h
@numeric_map = {
["7", "8"]=>[">"],
["7", "9"]=>[">>"],
["7", "4"]=>["v"],
["7", "5"]=>["v>"],
["7", "6"]=>["v>>"],
["7", "1"]=>["vv"],
["7", "2"]=>["vv>"],
["7", "3"]=>["vv>>"],
["7", "0"]=>[">vvv", "v>vv", "vv>v"],
["7", "A"]=>[">>vvv"],
["8", "7"]=>["<"],
["8", "9"]=>[">"],
["8", "4"]=>["<v", "v<"],
["8", "5"]=>["v"],
["8", "6"]=>["v>"],
["8", "1"]=>["<vv", "vv<"],
["8", "2"]=>["vv"],
["8", "3"]=>["vv>"],
["8", "0"]=>["vvv"],
["8", "A"]=>["vvv>"],
["9", "7"]=>["<<"],
["9", "8"]=>["<"],
["9", "4"]=>["<<v"],
["9", "5"]=>["<v", "v<"],
["9", "6"]=>["v"],
["9", "1"]=>["<<vv", "vv<<"],
["9", "2"]=>["<vv", "vv<"],
["9", "3"]=>["vv"],
["9", "0"]=>["<vvv", "vvv<"],
["9", "A"]=>["vvv"],
["4", "7"]=>["^"],
["4", "8"]=>["^>", ">^"],
["4", "9"]=>["^>>", ">>^"],
["4", "5"]=>[">"],
["4", "6"]=>[">>"],
["4", "1"]=>["v"],
["4", "2"]=>["v>"],
["4", "3"]=>["v>>"],
["4", "0"]=>[">vv"],
["4", "A"]=>[">>vv"],
["5", "7"]=>["<^", "^<"],
["5", "8"]=>["^"],
["5", "9"]=>["^>", ">^"],
["5", "4"]=>["<"],
["5", "6"]=>[">"],
["5", "1"]=>["<v", "v<"],
["5", "2"]=>["v"],
["5", "3"]=>["v>"],
["5", "0"]=>["vv"],
["5", "A"]=>["vv>"],
["6", "7"]=>["<<^", "^<<"],
["6", "8"]=>["<^", "^<"],
["6", "9"]=>["^"],
["6", "4"]=>["<<"],
["6", "5"]=>["<"],
["6", "1"]=>["<<v", "v<<"],
["6", "2"]=>["<v", "v<"],
["6", "3"]=>["v"],
["6", "0"]=>["<vv", "vv<"],
["6", "A"]=>["vv"],
["1", "7"]=>["^^"],
["1", "8"]=>["^^>", ">^^"],
["1", "9"]=>["^^>>", ">>^^"],
["1", "4"]=>["^"],
["1", "5"]=>["^>", ">^"],
["1", "6"]=>["^>>", ">>^"],
["1", "2"]=>[">"],
["1", "3"]=>[">>"],
["1", "0"]=>[">v"],
["1", "A"]=>[">>v", ">v>"],
["2", "7"]=>["<^^", "^^<"],
["2", "8"]=>["^^"],
["2", "9"]=>["^^>", ">^^"],
["2", "4"]=>["<^", "^<"],
["2", "5"]=>["^"],
["2", "6"]=>["^>", ">^"],
["2", "1"]=>["<"],
["2", "3"]=>[">"],
["2", "0"]=>["v"],
["2", "A"]=>[">v", "v>"],
["3", "7"]=>["<<^^", "^^<<"],
["3", "8"]=>["<^^", "^^<"],
["3", "9"]=>["^^"],
["3", "4"]=>["<<^", "^<<"],
["3", "5"]=>["<^", "^<"],
["3", "6"]=>["^"],
["3", "1"]=>["<<"],
["3", "2"]=>["<"],
["3", "0"]=>["<v", "v<"],
["3", "A"]=>["v"],
["0", "7"]=>["^^^<"],
["0", "8"]=>["^^^"],
["0", "9"]=>["^^^>", ">^^^"],
["0", "4"]=>["^^<"],
["0", "5"]=>["^^"],
["0", "6"]=>["^^>", ">^^"],
["0", "1"]=>["^<"],
["0", "2"]=>["^"],
["0", "3"]=>["^>", ">^"],
["0", "A"]=>[">"],
["A", "7"]=>["^^^<<"],
["A", "8"]=>["<^^^", "^^^<"],
["A", "9"]=>["^^^"],
["A", "4"]=>["^^<<"],
["A", "5"]=>["<^^", "^^<"],
["A", "6"]=>["^^"],
["A", "1"]=>["^<<"],
["A", "2"]=>["<^", "^<"],
["A", "3"]=>["^"],
["A", "0"]=>["<"]
}
# cache efficient direction movements
# @directional_map = directional_keypad
# .flatten.reject { _1.nil? }
# .permutation(2).to_a
# .map { [[_1, _2], dijkstra_with_lookup(directional_keypad, directional_movements, _1, _2)] }
# .map do |(start, target), (dest, paths)|
# presses = paths.map do |path|
# ([discover(start, directional_keypad)] + path)
# .each_cons(2).to_a
# .map { @dir_arrows[[_2.first - _1.first, _2.last - _1.last]] }.join
# end
# [[start, target], presses]
# end
# .to_h
@directional_map = {
["^", "A"]=>[">"],
["^", "<"]=>["v<"],
["^", "v"]=>["v"],
["^", ">"]=>[">v", "v>"],
["A", "^"]=>["<"],
["A", "<"]=>["v<<", "<v<"],
["A", "v"]=>["v<", "<v"],
["A", ">"]=>["v"],
["<", "^"]=>[">^"],
["<", "A"]=>[">>^"],
["<", "v"]=>[">"],
["<", ">"]=>[">>"],
["v", "^"]=>["^"],
["v", "A"]=>["^>", ">^"],
["v", "<"]=>["<"],
["v", ">"]=>[">"],
[">", "^"]=>["^<", "<^"],
[">", "A"]=>["^"],
[">", "<"]=>["<<"],
[">", "v"]=>["<"]
}
def solve(input, times = 3)
@robot_1 = input
@robot_2 = @robot_1
.map { ["A"] + _1 }
.map { _1.each_cons(2).to_a }
.map { _1.map { |move| @numeric_map[move].first }.join("A") }
.map { _1 + "A" }
(3..times).each do |num|
prev_robot = instance_variable_get(:"@robot_#{num - 1}")
robot = prev_robot
.map { _1.chars }
.map { ["A"] + _1 }
.map { _1.each_cons(2).to_a }
.map do
_1.map do |move|
@directional_map[move].nil? ? "" : @directional_map[move].first
end.join("A")
end
.map { _1 + "A" }
instance_variable_set(:"@robot_#{num}", robot)
@last_num = num
end
last_robot = instance_variable_get(:"@robot_#{@last_num}")
me = last_robot
.map { _1.chars }
.map { ["A"] + _1 }
.map { _1.each_cons(2).to_a }
.map do
_1.map do |move|
@directional_map[move].nil? ? "" : @directional_map[move].first
end.join("A")
end
.map { _1 + "A" }
me
end
me = solve(input, 3)
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
__END__
029A
980A
179A
456A
379A