#!/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", "v>"], ["7", "6"]=>[">>v", "v>>"], ["7", "1"]=>["vv"], ["7", "2"]=>[">vv", "vv>"], ["7", "3"]=>[">>vv", "vv>>"], ["7", "0"]=>[">vvv", "v>vv", "vv>v"], ["7", "A"]=>[">>vvv"], ["8", "7"]=>["<"], ["8", "9"]=>[">"], ["8", "4"]=>["["v"], ["8", "6"]=>[">v", "v>"], ["8", "1"]=>["["vv"], ["8", "3"]=>[">vv", "vv>"], ["8", "0"]=>["vvv"], ["8", "A"]=>[">vvv", "vvv>"], ["9", "7"]=>["<<"], ["9", "8"]=>["<"], ["9", "4"]=>["<["["v"], ["9", "1"]=>["<["["vv"], ["9", "0"]=>["["vvv"], ["4", "7"]=>["^"], ["4", "8"]=>["^>", ">^"], ["4", "9"]=>["^>>", ">>^"], ["4", "5"]=>[">"], ["4", "6"]=>[">>"], ["4", "1"]=>["v"], ["4", "2"]=>[">v", "v>"], ["4", "3"]=>[">>v", "v>>"], ["4", "0"]=>[">vv"], ["4", "A"]=>[">>vv"], ["5", "7"]=>["<^", "^<"], ["5", "8"]=>["^"], ["5", "9"]=>["^>", ">^"], ["5", "4"]=>["<"], ["5", "6"]=>[">"], ["5", "1"]=>["["v"], ["5", "3"]=>[">v", "v>"], ["5", "0"]=>["vv"], ["5", "A"]=>[">vv", "vv>"], ["6", "7"]=>["<<^", "^<<"], ["6", "8"]=>["<^", "^<"], ["6", "9"]=>["^"], ["6", "4"]=>["<<"], ["6", "5"]=>["<"], ["6", "1"]=>["<["["v"], ["6", "0"]=>["["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"], ["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<", ""]=>["v"], ["<", "^"]=>[">^"], ["<", "A"]=>[">>^"], ["<", "v"]=>[">"], ["<", ">"]=>[">>"], ["v", "^"]=>["^"], ["v", "A"]=>["^>", ">^"], ["v", "<"]=>["<"], ["v", ">"]=>[">"], [">", "^"]=>["^<", "<^"], [">", "A"]=>["^"], [">", "<"]=>["<<"], [">", "v"]=>["<"] } 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" } robot_3 = robot_2 .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 = robot_3 .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.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 puts me.first puts robot_3.first puts robot_2.first puts robot_1.first.join __END__ 029A 980A 179A 456A 379A