#!/usr/bin/env elixir defmodule Day21 do @numpad %{ "7" => {0, 0}, "8" => {1, 0}, "9" => {2, 0}, "4" => {0, 1}, "5" => {1, 1}, "6" => {2, 1}, "1" => {0, 2}, "2" => {1, 2}, "3" => {2, 2}, "0" => {1, 3}, "A" => {2, 3} } @keypad %{ "^" => {1, 0}, "A" => {2, 0}, "<" => {0, 1}, "v" => {1, 1}, ">" => {2, 1} } def part1(input) do Enum.map(input, &complexity/1) end def complexity(code) do length = code |> derive_keys(@numpad) # asdfsadfsdafdfs for the robot, some derived combinations are shorter, why? # Maybe going left non-sequentially is expensive because of round trips to the A buttom # so sequentially is cheaper? # Need to figure out what the situation that causes a longer sequence is |> derive_keys(@keypad) |> derive_keys(@keypad) |> byte_size() |> dbg() {numeric, "A"} = Integer.parse(code) dbg(numeric) numeric * length end def derive_keys(seq, pad) do String.graphemes("A" <> seq) |> Enum.chunk_every(2, 1, :discard) |> Enum.map_join("", fn [a, b] -> keys(a, b, pad) <> "A" end) end def numpad, do: @numpad def keys(a, b, pad) do {x1, y1} = Map.fetch!(pad, a) {x2, y2} = Map.fetch!(pad, b) dx = x2 - x1 dy = y2 - y1 keys_x = keys_x(dx) keys_y = keys_y(dy) # avoid the gap if dx < 0 do keys_y <> keys_x else keys_x <> keys_y end end def keys_x(-2), do: "<<" def keys_x(-1), do: "<" def keys_x(0), do: "" def keys_x(1), do: ">" def keys_x(2), do: ">>" def keys_y(-3), do: "^^^" def keys_y(-2), do: "^^" def keys_y(-1), do: "^" def keys_y(0), do: "" def keys_y(1), do: "v" def keys_y(2), do: "vv" def keys_y(3), do: "vvv" def keypad, do: @keypad def part2(_input) do :ok end def input do with [input_filename] <- System.argv(), {:ok, input} <- File.read(input_filename) do String.split(input, "\n", trim: true) else _ -> :error end end ####################### # HERE BE BOILERPLATE # ####################### def run do case input() do :error -> print_usage() input -> run_parts_with_timer(input) end end defp run_parts_with_timer(input) do run_with_timer(1, fn -> part1(input) end) run_with_timer(2, fn -> part2(input) end) end defp run_with_timer(part, fun) do {time, result} = :timer.tc(fun) IO.puts("Part #{part} (completed in #{format_time(time)}):\n") IO.puts("#{inspect(result)}\n") end defp format_time(μsec) when μsec < 1_000, do: "#{μsec}μs" defp format_time(μsec) when μsec < 1_000_000, do: "#{μsec / 1000}ms" defp format_time(μsec), do: "#{μsec / 1_000_000}s" defp print_usage do IO.puts("Usage: elixir day21.exs input_filename") end end # Day21.run()