Day 3 - Advent of Code 2024
Mix.install([
{:kino, "~> 0.14.2"},
{:nimble_parsec, "~> 1.4"}
])
Setup
input = Kino.Input.textarea("Paste in your input:", default: "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))")
Part 1
defmodule Computer.Parsers do
import NimbleParsec
def mul_instruction do
ignore(string("mul("))
|> integer(min: 1, max: 3)
|> ignore(string(","))
|> integer(min: 1, max: 3)
|> ignore(string(")"))
|> tag(:mul)
end
def irrelevant_char do
ignore(utf8_char([]))
end
end
defmodule Computer do
import NimbleParsec
import Computer.Parsers
defparsec :parse_instructions, repeat(choice([mul_instruction(), irrelevant_char()]))
def execute(program) do
program
|> parse_instructions()
|> elem(1)
|> Stream.map(fn {:mul, [x, y]} -> x * y end)
|> Enum.sum()
end
end
program = Kino.Input.read(input)
Computer.execute(program)
Part 2
defmodule Computer.V2 do
import NimbleParsec
import Computer.Parsers
do_instruction =
ignore(string("do()"))
|> tag(:do)
dont_instruction =
ignore(string("don't()"))
|> tag(:dont)
choices =
choice([
do_instruction,
dont_instruction,
mul_instruction(),
irrelevant_char()
])
defparsec :parse_instructions, repeat(choices)
def execute(program) do
program
|> parse_instructions()
|> elem(1)
|> Enum.reduce({true, 0}, fn instruction, {enabled, total} ->
with {:mul, [x, y]} <- instruction,
true <- enabled do
{true, total + x * y}
else
{:do, _} -> {true, total}
{:dont, _} -> {false, total}
_ -> {enabled, total}
end
end)
|> elem(1)
end
end
Computer.V2.execute(program)