code-shoily

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

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

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

pehbehbeh

Wanted to try out something new and used nimble_parsec for the first time.

bjorng

bjorng

Erlang Core Team

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

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

Where Next?

Popular in Challenges Top

bjorng
Note: This topic is to talk about Day 25 of the Advent of Code 2019. There is a private leaderboard for elixirforum members. You can joi...
New
LostKobrakai
This one has been quite the ride. Struggled at first to find a good data format to suite the problem. I really like how that turned out b...
New
bjorng
Note: This topic is to talk about Day 1 of the Advent of Code 2019.
New
Aetherus
This topic is about the Advent of Code 2021 - Day 4. Thanks to @bjorng , we now have a new Private Leaderboard. The entry code is: 370...
New
kwando
Phew, this one took a while to get right. My naive attempts was way to slow so I reached for Dijkstras shortest path algorithm… and that ...
New
Aetherus
This topic is about Day 5 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/le...
New
igorb
I found today a bit tedious: advent-of-code-2024/lib/advent_of_code2024/day15.ex at main · ibarakaiev/advent-of-code-2024 · GitHub.
New
stevensonmt
Reasonably pleased with my solution. The bitstring packet problems are so well suited to Erlang/Elixir it’s almost not fair. defmodule D...
New
seeplusplus
Hello all, hopefully I post this before someone else does and I don’t dupe. IMO Day 4 was much easier than Day 3 (yay, I can sleep befor...
New
coen.bakker
Since I started using Elixir, I have benefited greatly from being able to study various open-source projects. The codebase of LiveBook, i...
New

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New

We're in Beta

About us Mission Statement