Vandaag was weer een vrij makkelijke dag.

Als ik de puzzels had moeten inplannen zou ik dag 5 (die ik ontzettend lastig vond) en dag 15 omgekeerd hebben.

Advent of Code 2023 dag 15: de opdracht Link to heading

We moeten een hash-algoritme implementeren, waarvan de eisen zo ongeveer letterlijk uitgespeld worden.

Dat maakt zeker ster 1 heel toegankelijk, waardoor het voor mij meer een week één-puzzel leek. Zeker voor op de vrijdag (dus waar je in het weekend nog even verder kunt puzzelen) was dit erg makkelijk.

Advent of Code 2023 dag 15, ster 1 Link to heading

<?php
require_once __DIR__ . '/../init.php';

function hash_str($str)
{
	$chars         = str_split($str);
	$current_value = 0;

	foreach($chars as $my_char)
	{
		// Determine the ASCII code for the current character of the string.
		$ascii_code = ord($my_char);
		// Increase the current value by the ASCII code you just determined.
		$current_value += $ascii_code;
		// Set the current value to itself multiplied by 17.
		$current_value *= 17;
		// Set the current value to the remainder of dividing itself by 256.
		$current_value %= 256;
	}

	return $current_value;
}

$sum = array_reduce($lines[0], fn($acc, $val) => $acc += hash_str($val), 0);
printf("%d\n", $sum);

Het belangrijkste hier is de hash-functie, de rest is de totale som optellen.

Omdat we de eisen zo letterlijk uitgespeld kregen had ik die gekopieerd, comments van gemaakt, en daarna gewoon per comment letterlijk de code er onder geschreven.

Handig als je weet dat str_split en ord bestaan, dan gaat de rest vrijwel vanzelf.

Advent of Code 2023 dag 15, ster 2 Link to heading

Voor de tweede ster werd het iets ingewikkelder. We gebruiken nog steeds dezelfde hash-functie, maar moeten nu beter kijken naar de regels tekst.

Die zijn opgebouwd uit drie stukjes: een label (a-z), een symbool (- of =), en — als er een = was — een brandpuntsafstand.

<?php
$boxes = [];
foreach($lines[0] as $instructions)
{
	preg_match('/(?<label>[a-z]+)(?<sign>[-=])(?<focal_length>\d+)?/', $instructions, $step);
	$box_key = hash_str($step['label']);

	switch($step['sign'])
	{
		case '=':
			$boxes[$box_key][$step['label']] = $step['focal_length'];
			break;
		case '-':
			unset($boxes[$box_key][$step['label']]);
			break;
		default:
			throw new Exception(sprintf("Unknown sign %s", $step['sign']));
			break;
	}
}

$sum = array_reduce(array_keys($boxes), function($sum, $box_number) use ($boxes){
	$numeric_keys = array_values($boxes[$box_number]);
	return $sum + array_sum(array_map(
		fn($slot_number) => ($box_number + 1) * ($slot_number + 1) * $numeric_keys[$slot_number]
		, array_keys($numeric_keys)
	));
}, 0);

printf("%d\n", $sum);

Met een simpele reguliere expressie (/([a-z]+)([-=])(\d+)?/) hebben we alledrie de delen te pakken.

Dan is het gewoon een kwestie van een array ($boxes) bijhouden, en er eventueel weer dingen uit halen als we een minnetje zien.

Om aan het einde het optellen wat makkelijker te maken, zonder een aparte counter-variabele, gebruik ik array_values om numerieke indices te krijgen voor de array.

Omdat de indices in PHP in volgorde blijven hoeven we er dan alleen maar één bij op te tellen (een array is 0-indexed), en weten we het box/slot-nummer.