aoc/20/lib/days/day12.ex
2023-12-04 10:25:33 +01:00

93 lines
2.5 KiB
Elixir

defmodule AOC.Day12 do
@turn_right %{
N: :E,
E: :S,
S: :W,
W: :N
}
def parse_input do
AOC.Util.input_lines(12, 1)
|> Enum.map(fn line ->
{action, value} = String.split_at(line, 1)
action = String.to_atom(action)
value = String.to_integer(value)
{action, value}
end)
end
def handle_instruction1({:N, value}, acc), do: Map.update!(acc, :y, &(&1 - value))
def handle_instruction1({:E, value}, acc), do: Map.update!(acc, :x, &(&1 + value))
def handle_instruction1({:S, value}, acc), do: Map.update!(acc, :y, &(&1 + value))
def handle_instruction1({:W, value}, acc), do: Map.update!(acc, :x, &(&1 - value))
def handle_instruction1({:F, value}, %{dir: dir} = acc),
do: handle_instruction1({dir, value}, acc)
def handle_instruction1({:L, value}, acc), do: handle_instruction1({:R, -value}, acc)
def handle_instruction1({:R, value}, %{dir: dir} = acc) do
value = rem(div(value, 90), 4)
value =
if value < 0 do
value + 4
else
value
end
dir =
List.duplicate(nil, value)
|> Enum.reduce(dir, fn _, d -> Map.get(@turn_right, d) end)
Map.put(acc, :dir, dir)
end
def handle_instruction2({:N, value}, acc), do: Map.update!(acc, :wpy, &(&1 - value))
def handle_instruction2({:E, value}, acc), do: Map.update!(acc, :wpx, &(&1 + value))
def handle_instruction2({:S, value}, acc), do: Map.update!(acc, :wpy, &(&1 + value))
def handle_instruction2({:W, value}, acc), do: Map.update!(acc, :wpx, &(&1 - value))
def handle_instruction2({:F, value}, %{x: x, y: y, wpx: wpx, wpy: wpy} = acc),
do: %{acc | x: x + value * wpx, y: y + value * wpy}
def handle_instruction2({:L, value}, acc), do: handle_instruction2({:R, -value}, acc)
def handle_instruction2({:R, value}, %{wpx: wpx, wpy: wpy} = acc) do
value = rem(div(value, 90), 4)
value =
if value < 0 do
value + 4
else
value
end
{wpx, wpy} =
case value do
0 -> {wpx, wpy}
1 -> {-wpy, wpx}
2 -> {-wpx, -wpy}
3 -> {wpy, -wpx}
end
%{acc | wpx: wpx, wpy: wpy}
end
def handle_instructions(instructions, instruction_handler) do
acc = %{x: 0, y: 0, dir: :E, wpx: 10, wpy: -1}
Enum.reduce(instructions, acc, instruction_handler)
end
def parts do
input = parse_input()
%{x: x, y: y} = handle_instructions(input, &handle_instruction1/2)
part1 = abs(x) + abs(y)
%{x: x, y: y} = handle_instructions(input, &handle_instruction2/2)
part2 = abs(x) + abs(y)
{part1, part2}
end
end