From c334a9858359eb9b7c09f2b02f1bc4ce0d8bb334 Mon Sep 17 00:00:00 2001 From: Adam Millerchip Date: Sat, 21 Dec 2024 17:19:46 +0900 Subject: [PATCH] Add 2024 Day 21 WIP - probably give up --- 2024/day21_wip.exs | 133 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100755 2024/day21_wip.exs diff --git a/2024/day21_wip.exs b/2024/day21_wip.exs new file mode 100755 index 0000000..cc20923 --- /dev/null +++ b/2024/day21_wip.exs @@ -0,0 +1,133 @@ +#!/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()