Waar ik achteraf van veel mensen las dat ze dag vier veel makkelijker vonden dan de voorgaande dagen, had ik juist veel moeite met het tweede deel van dag 4.

Dat kwam door een verkeerde aanpak (bedacht ik me na het een tijdje met rust gelaten te hebben) die niet goed uitpakte.

Gelukkig bedacht ik een andere manier, waardoor het ineens heel snel ging. En bovendien met minder, én simpelere code.

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

Op dag vier gaan we spelen met kraskaarten, die er bijvoorbeeld zo uit zien:

Card 3:  1 21 53 59 44 | 69 82 63 72 16 21 14  1

We hebben dus een kaart-nummer (3), de winnende getallen (1, 21 … 44), en onze getallen (69, 82, … 1).

Wat we daar mee moeten doen verschilt per ster.

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

Voor de eerste ster tellen we hoeveel winnende getallen we hebben (hierboven 1 en 21), en wordt onze kaart dubbel zoveel waard.

Dus bij bijvoorbeeld vier punten:

  • 1 punt = 1
  • Eerste verdubbeling = 2
  • Tweede verdubbeling = 4
  • Derde verdubbeling = 8

Of simpeler: 2 ^ 3 is 8.

Net als een paar van de voorgaande dagen die ik in PHP heb gedaan slaan we even het inlezen van de data over.

Neem maar gewoon weer van me aan dat alle regels van de input in $lines zitten. 😉

<?php
// https://adventofcode.com/2023/day/4
require_once __DIR__ . '/../init.php';

$sum = array_reduce($lines, function($total, $line){
	$line                           = explode(": ", $line)[1];
	[$winning_numbers, $my_numbers] = array_map(
		fn($x) => array_filter(explode(" ", $x)),
		explode(" | ", $line)
	);
	$my_winning_numbers         = array_intersect($winning_numbers, $my_numbers);
	$number_of_winning_numbers  = count($my_winning_numbers);

	if($number_of_winning_numbers === 0)
	{
		return $total;
	}

	return $total + pow(2, ($number_of_winning_numbers - 1));
}, 0);

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

In de functie die we naar array_reduce geven krijgen we steeds twee parameters binnen: het lopende totaal (begint op 0), en de huidige regel.

De huidige regel splitsen we dan een paar keer: eerst zijn we alleen geïnteresseerd in het deel na de “:”. Dan willen we twee arrays: één met de winnende getallen, en één met onze getallen.

De overlap van die twee arrays bepalen we met array_intersect, die alle elementen teruggeeft die zich in beide arrays bevinden.

Als we die eenmaal hebben is het een kwestie van kijken of we winnende nummers hebben. Zo niet, doen we niets. (Let op dat 2 ^ 0 namelijk 1 is en niet 0!)

En anders is het simpel machtsverheffen, wat we in PHP doen met pow.

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

Voor de tweede ster blijkt dat we de score totaal verkeerd gedaan hebben. Eigenlijk win je gewoon steeds meer kraskaarten!

(Onthoud: de hele uitleg kun je lezen op de website van AoC.)

<?php
// https://adventofcode.com/2023/day/4
require_once __DIR__ . '/../init.php';

$cards = array_map(function($x){
	[$winning_numbers, $my_numbers] = array_map(
		fn($x) => array_filter(explode(" ", $x)),
		explode(" | ", explode(": ", $x)[1])
	);
	$my_winning_numbers         = array_intersect($winning_numbers, $my_numbers);
	$number_of_winning_numbers  = count($my_winning_numbers);

	return [
		'number_of_winning_numbers' => $number_of_winning_numbers,
		'copies'                    => 1
	];
}, $lines);

for($card_counter = 0; $card_counter < count($cards); $card_counter++)
{
	$card             = $cards[$card_counter];
	$number_of_copies = $card_counter + $card['number_of_winning_numbers'];

	for($i = $card_counter + 1; $i <= $number_of_copies; $i++)
	{
		$cards[$i]['copies'] += $card['copies'];
	}
}

$copies = array_column($cards, "copies");
$total  = array_sum($copies);

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

We rekenen hier wel vast uit wat de score is voor iedere kraskaart (in de array_map), zodat we dat niet steeds opnieuw moeten doen voor ieder kaartje.

Daarna heb ik wel een beetje een brute-force methode gekozen, en gewoon een for-loop in een for-loop gestopt.

Aan het einde hebben we dan een array met kaarten, die allemaal een copies-index hebben.

Dankzij array_column kunnen we in PHP heel makkelijk die index uitlezen voor iedere regel, en dan het geheel optellen met array_sum.