Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 3

livebook/2024/day_3.livemd

Day 3

Mix.install([
  {:kino_aoc, "~> 0.1"}
])

Input

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2024", "3", System.fetch_env!("LB_SESSION"))

test input

test_input = """
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
"""

Token parser

defmodule Token do
  def parse(input) do
    input
    |> tokenize()
    |> Enum.reduce(0, fn [a, b], acc ->
      acc + String.to_integer(a) * String.to_integer(b)
    end)
  end

  def tokenize(input) do
    ~r/mul\((\d+),(\d+)\)/
    |> Regex.scan(input, capture: :all_but_first)
    # |> IO.inspect(chars: :as_list)
  end
end

test_input
|> Token.parse()
defmodule TokenTwo do
  def parse(input, enable \\ :enable, acc \\ 0)

  def parse(input, :enable, acc) do
    Regex.split(~r/don't\(\)/, input, parts: 2)
    |> case do
      [valid, rest] -> parse(rest, :disable, acc + Token.parse(valid))
      [valid] -> acc + Token.parse(valid)
    end
  end

  def parse(input, :disable, acc) do
    Regex.split(~r/do\(\)/, input, parts: 2)
    |> case do
      [_invalid, rest] -> parse(rest, :enable, acc)
      [_invalid] -> acc
    end
  end
end

test_input
# puzzle_input
|> TokenTwo.parse()

test parser

ExUnit.start(autorun: false)

defmodule TokenTest do
  use ExUnit.Case, async: true

  @test_input """
  xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
  """

  test "tokenize" do
    assert Token.tokenize(@test_input) == [["2", "4"], ["5", "5"], ["11", "8"], ["8", "5"]]
  end
end

ExUnit.run()

part 1

defmodule PartOne do
  def solve(input) do
    IO.puts("--- Part One ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    Token.parse(input)
  end
end

test_input
# puzzle_input
|> PartOne.run()

part 1 - test

ExUnit.start(autorun: false)

defmodule PartOneTest do
  use ExUnit.Case

  @input puzzle_input

  test "part one" do
    assert PartOne.run(@input) == 187_833_789
  end
end

ExUnit.run()

part 2

defmodule PartTwo do
  def solve(input) do
    IO.puts("--- Part Two ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    TokenTwo.parse(input)
  end
end

# test_input
puzzle_input
|> PartTwo.run()

part 2 - test

ExUnit.start(autorun: false)

defmodule PartTwoTest do
  use ExUnit.Case

  @input puzzle_input

  test "part two" do
    assert PartTwo.run(@input) == 94_455_185
  end
end

ExUnit.run()