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

Day 03

2024/day-03.livemd

Day 03

Mix.install([
  {:kino, "~> 0.14"},
  {:nimble_parsec, "~> 1.4"}
])

example_input =
  Kino.Input.textarea("example input:")
  |> Kino.render()

real_input = Kino.Input.textarea("real input:")

Common

defmodule AOC do
  def parse(input) do
    input
    |> Kino.Input.read()
    |> Parser.parse()
    |> case do
      {:ok, acc, "", _, _, _} -> acc
    end
  end
end

defmodule Parser do
  import NimbleParsec

  disable =
    ignore(string("don't()"))
    |> tag(:disable)

  enable =
    ignore(string("do()"))
    |> tag(:enable)

  operand = integer(max: 3, min: 1)

  mul =
    ignore(string("mul("))
    |> concat(operand)
    |> ignore(string(","))
    |> concat(operand)
    |> ignore(string(")"))
    |> tag(:mul)

  instruction = choice([disable, enable, mul])

  instructions =
    eventually(instruction)
    |> repeat()

  defparsec(:parse, instructions |> eventually(eos()))
end

Part 1

defmodule Part1 do
  def process(instructions) do
    instructions
    |> Enum.reduce(0, fn
      {:mul, [a, b]}, acc -> acc + a * b
      _, acc -> acc
    end)
  end
end

real_input
|> AOC.parse()
|> Part1.process()

Part 2

defmodule Part2 do
  def process(instructions) do
    {_, sum} =
      instructions
      |> Enum.reduce({:enabled, 0}, fn
        {:mul, [a, b]}, {:enabled, sum} -> {:enabled, sum + a * b}
        {:disable, _}, {:enabled, sum} -> {:disabled, sum}
        {:enable, _}, {:disabled, sum} -> {:enabled, sum}
        _, acc -> acc
      end)

    sum
  end
end

real_input
|> AOC.parse()
|> Part2.process()