Worst Practice

Advent of Code - Day 4

Posted on December  4, 2022 @ 12:00

Posted under the Backend category

Level: beginner

Posted with the following tags: #Advent, #PHP

Who like to clean the house when it was already cleaned up. Today we go the lazy way: we need to find out how to reduce redundant work.

Advent of Code - Day 4
Calendar icon by Kevin Sanderson from Pixabay

Today’s puzzle in short: There are a bunch of character strings. Each letter has a number, and we need to group these strings by different criteria and sum the common characters’ numbers.

The input data

Each line in the input data represents two number sequences in the following way:

  • Two ranges of numbers (decimals separated by -), then a comma, then another range.
  • The ranges of course contain the start and end number.

Game rules

The puzzle is simple:

  • The elves work in sections.
  • Each section has an ID number.
  • Each elf work in a range of sections.
  • The elves work in pairs.

Or task is to find overlapping (concurrency, redundancy) of the section ranges.

Part One

In the first part of the puzzle, we need to identify and count the fully overlapping ranges.

With PHP, it’s an easy task. We have built-in function to create a range of numbers as arrays, then just simply compare these arrays.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$fullyContained = 0;

if ($fn = fopen(__DIR__.'/input.txt', 'r')) {
    while (($line = fgets($fn, 1024)) !== false) {
        $line = trim($line);
        $pairRanges = [];

        if (preg_match('/^(?P<E1from>\d+)\-(?P<E1to>\d+),(?P<E2from>\d+)\-(?P<E2to>\d+)$/', $line, $pairRanges)) {
            $elf1Range = range($pairRanges['E1from'], $pairRanges['E1to']);
            $elf2Range = range($pairRanges['E2from'], $pairRanges['E2to']);

            if (
                count(array_diff($elf1Range, $elf2Range)) === 0 ||
                count(array_diff($elf2Range, $elf1Range)) === 0
            ) {
                $fullyContained++;
            }
        }
    }
    fclose($fn);
}


echo $fullyContained.PHP_EOL;

Just for fun, I used a regular expression to split the line of string into four numbers. I LOVE regular expressions by the way!

So when we create the ranges with the range() function, we need to check how different they are. The array_diff() function is just perfect for this. It checks the first argument array against the second array and returns any element that is present only in the first array, but not in the other. Therefore, to find out whether a range of numbers is fully contained in the other one, we should get back an empty array.

We need to do this check for the other range too, because we can’t be sure, that only the first range can be a subset.

Part two

This part is almost the same. Here we need to count also the partially overlapping ranges. How to do that? The same way, the only difference is now don’t look for empty result, but a result that has fewer elements than the subject array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$partiallyOrFullyContained = 0;

if ($fn = fopen(__DIR__.'/input.txt', 'r')) {
    while (($line = fgets($fn, 1024)) !== false) {
        $line = trim($line);
        $pairRanges = [];

        if (preg_match('/^(?P<E1from>\d+)\-(?P<E1to>\d+),(?P<E2from>\d+)\-(?P<E2to>\d+)$/', $line, $pairRanges)) {
            $elf1Range = range($pairRanges['E1from'], $pairRanges['E1to']);
            $elf2Range = range($pairRanges['E2from'], $pairRanges['E2to']);

            if (
                count(array_diff($elf1Range, $elf2Range)) < count($elf1Range) ||
                count(array_diff($elf2Range, $elf1Range)) < count($elf2Range)
            ) {
                $partiallyOrFullyContained++;
            }
        }
    }
    fclose($fn);
}


echo $partiallyOrFullyContained.PHP_EOL;
Gábor Iván