Worst Practice

Advent of Code - Day 3

Posted on December  3, 2022 @ 10:00

Posted under the Backend category

Level: beginner

Posted with the following tags: #Advent, #PHP

A nice finger practice to count characters.

Advent of Code - Day 3
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

The guys didn’t go crazy with this input for the first sight.

  • Every line contains “random” characters from the English alphabet.

Game rules

  • Each character has a priority number:
    • the lowercase characters (from a to z) have priorities 1 through 26.
    • the uppercase characters (from A to Z) have priorities 27 through 52.
  • We have to deal with groups of strings, and the character that is common in every string within a group gives the groups priority.
  • We have to count all the groups’ priorities.

Part one

In the first task we have to split every line of string into two equal parts, and they will form a group.

The first thing we need to realize here is the priority numbers are not the same way added to the characters as they present in the ASCII table. Because the character codes are the following:

  • Characters from A trough Z are between 65 and 90.
  • Characters from a trough z are between 97 and 122.

In PHP, you can easily get this value from the character set’s mapping table with the ord() function.

The second thing is - like in most programming languages - the string are not really equal to an array of characters, so we need to convert each string to arrays of characters.

So the code will be like this:

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

const PRIORITY_DIFF_LOWERCASE = (-97 + 1);
const PRIORITY_DIFF_UPPERCASE = (-65 + 27);

if ($fn = fopen(__DIR__.'/input.txt', 'r')) {
    while (($line = fgets($fn, 1024)) !== false) {
        $line = trim($line);
        $characters = str_split($line);
        [$compartment1, $compartment2] = array_chunk($characters, floor(count($characters) / 2));
        $commonItem = current(array_unique(array_intersect($compartment1, $compartment2)));
        $priorityDiff = ord($commonItem) >= ord('a')
            ? PRIORITY_DIFF_LOWERCASE
            : PRIORITY_DIFF_UPPERCASE;

        $sum += (ord($commonItem) + $priorityDiff);
    }
    fclose($fn);
}


echo $sum.PHP_EOL;

As you can see the big “trick” here is we use the character code as a starting pont and with a simple addition (subtraction), we get the right priority number without having to store them in an array. And as I mentioned earlier, the best way to solve this puzzle to convert the strings into arrays of characters (doing it with the str_split()), and then with the array_intersect() we can easily get all the common elements of the arrays.

Since we know that the input data has been delivered with care, we don’t need to be super strict with checks:

  • We assume that each line has an even number of characters, so we can split with no issue.
  • We assume that grouping will result one and only one common character, so we get the right result when we pick the first item from the returning array of the array_intersect() function.
  • We assume there are no tricks with “out of range” (like random UTF-8) characters.

Part two

In this task the only thing changed is the way we make the groups. Instead of splitting each row, now we collect 3 rows into a group. Then the rest of the logic is more-or-less the same:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$sum = 0;
$backpacks = [];

const PRIORITY_DIFF_LOWERCASE = (-97 + 1);
const PRIORITY_DIFF_UPPERCASE = (-65 + 27);

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

        if (count($backpacks) < 3) {
            continue;
        }

        $commonItem = current(array_unique(array_intersect($backpacks[0], $backpacks[1], $backpacks[2])));
        $priorityDiff = ord($commonItem) >= ord('a')
            ? PRIORITY_DIFF_LOWERCASE
            : PRIORITY_DIFF_UPPERCASE;

        $sum += (ord($commonItem) + $priorityDiff);
        $backpacks = [];
    }
    fclose($fn);
}


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