Advent of Code 2021 - Day 2

Another take:

  def part1(), do: solve({0, 0})
  def part2(), do: solve({0, 0, 0})

  defp solve(seed) do
    File.stream!(@path)
    |> Stream.map(&parse_line/1)
    |> Enum.reduce(seed, &process_cmd/2)
    |> Tuple.product()
  end

  defp process_cmd({:forward, n}, {h, d}), do: {h+n, d}
  defp process_cmd({:up, n},      {h, d}), do: {h, d-n}
  defp process_cmd({:down, n},    {h, d}), do: {h, d+n}

  defp process_cmd({:forward, n}, {h, d, a}), do: {h+n, d + (n * a), a}
  defp process_cmd({:up, n},      {h, d, a}), do: {h, d, a-n}
  defp process_cmd({:down, n},    {h, d, a}), do: {h, d, a+n}

  defp parse_line(line) do
    case String.trim(line) do
      "forward " <> rest -> {:forward, String.to_integer(rest)}
      "up "      <> rest -> {:up,      String.to_integer(rest)}
      "down "    <> rest -> {:down,    String.to_integer(rest)}
    end
  end