DEV Community

Grant Riordan
Grant Riordan

Posted on

AoC '24 - Day 3: Mull it Over (C# and Python)

Mull it Over

Today's challenge screamed Regex when I first saw it, mainly because whenever I see "extract parts of this string", Regex is my goto;

Basic Concept and Requirements

So we need to find all the mul(number1, number2) and multiply these together, but ignore all other characters.

So we need to find a mechanism to find all the valid mul() function declarations.

Part1

To do this, we can leverage the power of Regex, using the following pattern

mul\([0-9]{1,3},[0-9]{1,3}\)"

Which will match on mul( + any number between 0-9 , a number of 1 > 3 times + closing bracket.

Once we've got the mul() matches, we can utilise regex again to pull out the numbers, parsing these and adding to the total.

Quite a simple and straightforward solution.

void Part1()
{
    const string regex = @"mul\([0-9]{1,3},[0-9]{1,3}\)";
    var matches = Regex.Matches(input, regex);

    var total = 0;

    foreach (Match match in matches)
    {
        var numbers = GetNumbers(match);
        total += numbers[0] * numbers[1];
    }
}

int[] GetNumbers(Match match)
{
    var numbers = Regex.Matches(match.Value, "\\d{1,3}");
    var a = int.Parse(numbers[0].Value);
    var b = int.Parse(numbers[1].Value);

    return [a, b];
}
Enter fullscreen mode Exit fullscreen mode

Part 2

This added slightly more complicated instructions, adding the caveat that do() and don't() phrases will enable or disable the mil() functions.

The best way to handle this, seemed easy, update the Regex pattern to account for do() dont() or mul(number, number

The Regex will now look for any of these phrases, by using the | oprator.

We can then loop through these and using a switch statemnt decide if we're looking at a do, dont or mil() match, and update the enabled flag accordingly.

It's then a simple check of whether its a mul() and isEnabled is True, before multiplying and adding to the total.

Full Code for both solutions below


using System.Text.RegularExpressions;

var input = File.ReadAllText("./input1.txt");
// var input = @"xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))";

Part1();
Part2();
return;

void Part1()
{
    const string regex = @"mul\([0-9]{1,3},[0-9]{1,3}\)";
    var matches = Regex.Matches(input, regex);

    var total = 0;

    foreach (Match match in matches)
    {
        var numbers = GetNumbers(match);
        total += numbers[0] * numbers[1];
    }

    Console.WriteLine("Total: " + total);
}

void Part2()
{
    const string regex = @"do\(\)|don't\(\)|mul\([0-9]{1,3},[0-9]{1,3}\)";
    var matches = Regex.Matches(input, regex);

    // At the start, mul instructions are enabled
    var isEnabled = true;
    var total = 0;

    // loop over the matches (e.g do(), dont() or mul(x, y)
    foreach (Match match in matches)
    {
        switch (match.Value)
        {
            case "do()":
                isEnabled = true;
                break;
            case "don't()":
                isEnabled = false;
                break;
            default:
            {
                if (match.Value.StartsWith("mul") && isEnabled)
                {
                    var numbers = GetNumbers(match);
                    total += numbers[0] * numbers[1];
                }

                break;
            }
        }
    }

    Console.WriteLine("Total: " + total);
}

int[] GetNumbers(Match match)
{
    var numbers = Regex.Matches(match.Value, "\\d{1,3}");
    var a = int.Parse(numbers[0].Value);
    var b = int.Parse(numbers[1].Value);

    return [a, b];
}
Enter fullscreen mode Exit fullscreen mode

Python Solution Attempt

If you're new to my series, i'll re-iterate, I'm using AoC '24 to help learn and improve my existing Python skills - so all solutions will include both C# and Python attempts.

We can use the similar concepts but leverage Pythons language and functions:


import re

# Read input from file
with open("./input1.txt", "r") as file:
    input_text = file.read()

# Part 1
def part1():
    regex = r"mul\(\d{1,3},\d{1,3}\)"
    matches = re.findall(regex, input_text)

    total = 0
    for match in matches:
        a, b = get_numbers(match)
        total += a * b

    print(f"Total: {total}")

# Part 2
def part2():
    regex = r"do\(\)|don't\(\)|mul\(\d{1,3},\d{1,3}\)"
    matches = re.findall(regex, input_text)

    is_enabled = True  # At the start, mul instructions are enabled
    total = 0

    for match in matches:
        if match == "do()":
            is_enabled = True
        elif match == "don't()":
            is_enabled = False
        elif match.startswith("mul") and is_enabled:
            a, b = get_numbers(match)
            total += a * b

    print(f"Total: {total}")

# Helper function to extract numbers from a match
def get_numbers(match):
    numbers = re.findall(r"\d{1,3}", match)
    return int(numbers[0]), int(numbers[1])

# Execute parts
part1()
part2()

Enter fullscreen mode Exit fullscreen mode

As always you can follow me on twitter or view the whole repo for more solutions on Github.

Top comments (0)