code-shoily
Advent of Code 2024 - Day 3
Here’s my day 3 code
This was quite easy. I was afraid Part 2 would be “un-regex-able” and was preparing for hand crafting automata but looks like it wasn’t the case. Also, nice to have that Toboggan reference. I love cross-overs.
Most Liked
Flo0807
Hey!
This is my solution for Day 03.
Part 1
Regex.scan(~r/mul\((\d+),(\d+)\)/, puzzle_input, capture: :all_but_first)
|> Enum.map(fn [a, b] ->
String.to_integer(a) * String.to_integer(b)
end)
|> Enum.sum()
Part 2
Regex.scan(~r/mul\((-?\d+),(-?\d+)\)|do(?:n't)?\(\)/, puzzle_input)
|> Enum.reduce({0, :enabled}, fn
["don't()"], {count, _status} ->
{count, :disabled}
["do()"], {count, _status} ->
{count, :enabled}
[_text, a, b], {count, :enabled} ->
result = String.to_integer(a) * String.to_integer(b)
{result + count, :enabled}
[_text, _a, _b], {count, :disabled} ->
{count, :disabled}
end)
|> elem(0)
jswanner
I used NimbleParsec to build a parser:
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
pehbehbeh
Wanted to try out something new and used nimble_parsec for the first time.
bjorng
I went for a solution using regexes and regretted it almost immediately. It took me a while to realize that Regex.run/3 with the :global option will not return multiple solutions (as :re.run/3 would), but that I needed to use Regex.scan/3. Fortunately, having invested a lot of time solving part 1 with a regex, it turned out it was possible to solve also part 2 with a regex.
Having tried regexes, I decided to implement a solution in Erlang using the binary syntax to do the parsing:
UPDATE: After looking at the other solutions, I realized that I only looked for do and don't instead of do() and don't(). That happened to produce the correct result (at least for my input), but I’ve now updated my programs to match the parens too.
smaller_infinity
I really dont like regex so I used nimble parsec (for the first time):
defmodule Advent2024.Day03 do
@test_data1 "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"
@test_data2 "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"
defmodule Parser do
import NimbleParsec
defcombinator :int, integer(min: 1, max: 3)
defcombinator :do, string("do()") |> replace(:do)
defcombinator :dont, string("don't()") |> replace(:dont)
defparsec :mul,
ignore(string("mul("))
|> parsec(:int)
|> ignore(string(","))
|> parsec(:int)
|> ignore(string(")"))
|> reduce(:collect_args)
defp collect_args([a, b]), do: {:mul, a, b}
defparsec :eval,
choice([parsec(:do), parsec(:mul), parsec(:dont)]) |> eventually() |> repeat()
end
alias Advent2024.Day03.Parser
defp parse_line(input) do
{:ok, result, _, _, _, _} = Parser.eval(input)
result
end
defp parse_input(input) do
input
|> Enum.take_while(&Kernel.!=(&1, ""))
|> Enum.flat_map(&parse_line/1)
end
def part1(input) do
input
|> parse_input()
|> Enum.map(fn
{:mul, a, b} -> a * b
_ -> 0
end)
|> Enum.sum()
end
defp handle_instructions(:do, {acc, _}), do: {acc, true}
defp handle_instructions(:dont, {acc, _}), do: {acc, false}
defp handle_instructions({:mul, a, b}, {acc, true}), do: {acc + a * b, true}
defp handle_instructions(_, {acc, false}), do: {acc, false}
def part2(input) do
input
|> parse_input()
|> Enum.reduce({0, true}, &handle_instructions/2)
|> elem(0)
end
def test_input1() do
[@test_data1]
end
def test_input2() do
[@test_data2]
end
def input() do
File.stream!("data/data_03.txt")
end
end







