diff --git a/21/input b/21/input new file mode 100644 index 0000000..10276c8 --- /dev/null +++ b/21/input @@ -0,0 +1,5 @@ +140A +169A +170A +528A +340A \ No newline at end of file diff --git a/21/main.rb b/21/main.rb new file mode 100755 index 0000000..e220ba4 --- /dev/null +++ b/21/main.rb @@ -0,0 +1,176 @@ +#!/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 " >^AvAA<^A>A>^AvA^A^A^A>AAvA^AA>^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