import AOC

aoc 2015, 3 do
  def input_chars(), do: input_string() |> String.split("", trim: true)

  def p1 do
    input_chars()
    |> run()
    |> then(fn {visited, _} -> MapSet.size(visited) end)
  end

  def p2 do
    {santa, robo_santa} =
      input_chars()
      |> Enum.with_index()
      |> Enum.split_with(fn {_, i} -> Integer.mod(i, 2) == 0 end)
      |> then(fn {santa, robo_santa} ->
        {without_index(santa), without_index(robo_santa)}
      end)

    {visited, _} = run(santa)
    {visited, _} = run(robo_santa, visited)

    MapSet.size(visited)
  end

  defp op("^"), do: {1, 0}
  defp op(">"), do: {0, 1}
  defp op("v"), do: {-1, 0}
  defp op("<"), do: {0, -1}

  defp add({x, y}, {a, b}), do: {x + a, y + b}

  defp run(inst, visited \\ MapSet.new()) do
    starting_position = {0, 0}
    visited = MapSet.put(visited, starting_position)

    Enum.reduce(inst, {visited, starting_position}, fn command, {visited, current_position} ->
      current_position = add(current_position, op(command))
      visited = MapSet.put(visited, current_position)
      {visited, current_position}
    end)
  end

  defp without_index(enum), do: Enum.map(enum, &elem(&1, 0))
end