Advent of Code 2025 - Day 1

I wanted to play a little bit with nimble_parsec. I will try to use it for every parsing job. Usually I use regexes but 1) time to change, 2) and get a more powerful parsing technique.

#!/usr/bin/env elixir

# Advent of Code 2025. Day 1

Mix.install([
  {:nimble_parsec, "~> 1.4.2"},
])

defmodule M do
  import NimbleParsec

  rotation =
    choice([string("L"), string("R")])
    |> integer(min: 1)

  defparsec :rotation, rotation
end

# Part 1
File.stream!("../day01.txt")
|> Stream.map(fn line -> {:ok, [dir, qty], "\n", %{}, _, _} = M.rotation(line) ; {dir, qty} end)
|> Enum.reduce({50, 0}, fn {dir, qty}, {pos, zeroes} ->
  pos =  Integer.mod(pos + (if dir == "R", do: 1, else: -1) * qty, 100)
  {pos, (if pos == 0, do: zeroes+1, else: zeroes)}
end)
|> tap(fn {_pos, zeroes} -> IO.puts("Day 1. Part 1. Number of zeroes: #{zeroes}") end)

# Part 2
File.stream!("../day01.txt")
|> Stream.map(fn line -> {:ok, [dir, qty], "\n", %{}, _, _} = M.rotation(line) ; {dir, qty} end)
|> Enum.reduce({50, 0}, fn {dir, qty}, {pos, zeroes} ->
  dist_to_zero = if dir == "L", do: pos, else: Integer.mod(100-pos, 100)
  pos =  Integer.mod(pos + (if dir == "R", do: 1, else: -1) * qty, 100)
  n = div(max(0, qty-dist_to_zero), 100) + (if pos != 0 && qty-dist_to_zero >= 0, do: 1, else: 0)
  {pos, zeroes + n}
end)
|> tap(fn {_pos, zeroes} -> IO.puts("Day 1. Part 2. Number of zeroes: #{zeroes}") end)