133 lines
2.8 KiB
Elixir
Executable file
133 lines
2.8 KiB
Elixir
Executable file
#!/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()
|