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