Powered by AppSignal & Oban Pro

Advent of Code 2024/8

2025/1.livemd

Advent of Code 2024/8

Mix.install([
  {:kino, "~> 0.18"}
])

Section

input = Kino.Input.textarea("input")
defmodule AoC2025_1 do
  defp step(state, {instruction, value}) do
    case instruction do
      "L" -> step_left(state, value)
      "R" -> step_right(state, value)
    end
  end

  defp state_at_zero({0, 0}), do: {0, 1}
  defp state_at_zero({pos, points}), do: {pos, points}
  defp state_crossing_zero(0), do: 0
  defp state_crossing_zero(_), do: 1

  def step_left(state, value) do
    pos = state - rem(value, 100)
    zero_points = div(value, 100)
    cond do
      pos == 0 -> {pos, zero_points + 1}
      pos < 0 -> {100 + pos, zero_points + state_crossing_zero(state)}
      true -> {pos, zero_points}
    end
  end

  def step_right(state, value) do
    pos = state + rem(value, 100)
    zero_points = div(value, 100)
    cond do
      pos == 0 -> {pos, zero_points + 1}
      pos > 99 -> {pos - 100, zero_points + state_crossing_zero(state)}
      true -> {pos, zero_points}
    end
  end

  def parse(input) do
    Kino.Input.read(input)
    |> String.split("\n", trim: true)
    |> Enum.map(fn op -> {String.at(op, 0), String.to_integer(String.slice(op, 1..-1//1))} end)
  end

  def part_1(input) do
    input
    |> parse
    |> Enum.map_reduce(50, fn {instruction, value}, acc ->
      {pos, _} = step(acc, {instruction, value})
      {pos, pos}
    end)
    |> elem(0)
    |> dbg()
    |> Enum.count(fn el -> el == 0 end)
  end

  def part_2(input) do
    input
    |> parse
    |> Enum.map_reduce(50, fn {instruction, value}, acc ->
      {pos, zero_points} = step(acc, {instruction, value})
      {{pos, zero_points, instruction, value}, pos}
    end)
    |> elem(0)
    |> dbg()
    |> Enum.sum_by(fn el -> elem(el, 1) end)
  end
end
AoC2025_1.part_1(input)
AoC2025_1.part_2(input)