Group of persons behind computers overseeing a golden network with a nature landscape

Crédit: Generated with AI

03-12-2024
AOC 2024 - Day 03 - Mull It Over

new Day in the Advent Office

Today, we are transported into the North Pole Toboggan transport shop warehouse where it seems the computers are not behaving properly...

The mildly flustered shopkeeper asks us if we would be able to look and fix the program run. After some look up, we understand that the memory is corrupted and that a special treatment needs to be applied...

example image...

In today's coding adventure, we'll dive into regex capability and how to extract patterned information from within a sequence of characters (aka string 👍)

Part 1 - simple multiplications

The memory is of the following form:

1xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))

As we understand, the only operations that need to be executed are the the ones following the following pattern:

1mul(X,Y)

where X and Y are both numbers between 1 and 3 digits

The expected outcome of the program is to sum each operations where each non-corrupted operation would be X*Y

The idea is to use regular expressions (regex) to extract from the string only the correct operations. For that, the regex, to use is the following:

1/mul\(\d{1-3},\d{1-3}\)/

There are multiple elements to consider here:

  • mul just says that we are searching all the chains of characters that are starting with the 3 letters mul
  • \( means that we are looking, after mul, to find the '(' character but as the '(' has a specific meaning in any regular expression, we need to escape it
  • \d means that we are looking at any digit (the number between 1 and 9 inclusive) => we could have also written [1-9]
  • {1-3} means that we need to find the previous character (here a digit) at least 1 time and maximum 3 times next to one another (it can be 3 completely different digits like 123)
  • the remaining is using the same kinds of pattern matching

Knowing that regular expression, we can then find all the elements from the string, multiply them and them sum. For that, in python, we need to use the re module which is encompassing functions for regular expression handling.

1import re
2
3total = 0
4for m in re.findall(r"mul\(\d{1-3},\d{1-3}\)", string):
5    # let's remember that m is in the form mul(X,Y) so...
6    # use only part between brackets starting after the index and until the previous to last character in the string 
7    # and then splitting it over the ',' 
8    # and then transforming them into numbers 
9    X, Y = map(int, m[4:-1].split(','))
10    total += X * Y
11return total

Part 2 - enabled multiplications

The Part 2 introduces the concept of condition/enablement in the form of do() and don't()...

Any do() enables any following operation to be executed and a don't() forbids any following operation to be executed until a new do() is seen. By default, we understand that the program starts with enabling the operations to happen

The idea will be a bit the same, but we'll need to search for some other information within the regular expression, like so:

1/do\(\)|don't\(\)|mul\(\d{1-3},\d{1-3}\)/

Additional elements are introduced here:

  • the | character is a special character which means or => meaning that or we look at the pattern on the left or we look for the pattern on the right... so here we look of:
    • for do()
    • or for don't()
    • or for mul(X,Y)
  • the others elements were already used within the part 1

So, with the information, we need a way to enable the computation to happen, so let's take our script again and modify it a bit...

1import re
2
3total = 0
4enabled = True
5for m in re.findall(r"do\(\)|don't\(\)|mul\(\d{1-3},\d{1-3}\)", string):
6    # we need now to consider the other patterns that we search for and act for each of them
7    if m == "do()":
8        # here we enable the computation
9        enabled = True
10    elif m == "don't()":
11        # here we disable the computation
12        enabled = False
13    elif enabled:
14        # only in case the computation is enabled we perform it
15        X, Y = map(int, m[4:-1].split(','))
16        total += X * Y
17return total

Conclusion

I liked this day as it was a really good introduction to regular expression using some already notions of parsing and complexifying just a tiny bit for the part 2...

For more Regex notions, you can visit the following sites:

  • Regex 101 => a nice interactive websites to introduce you to and dive into regex
  • Regexr.com => a nice sandbox with some explanations and a capacity to test your regex against sample text

The Repository

The following repository will keep in the main branch all the code of this year resolution (and also presents the ones from the previous year I already solved... I'm still missing some years and days...)

The code of my solution for this specific day can be seen here