AdventOfCode/2024/day21_wip.exs

134 lines
2.8 KiB
Elixir
Raw Normal View History

2024-12-21 08:19:46 +00:00
#!/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()