[$polymer, $rules] = $input->split("\n\n");
$pairs = [];
for ($i = 0; $i < $polymer->length() - 1; $i++) {
$pair = $polymer[$i] . $polymer[$i + 1];
$pairs[$pair] = ($pairs[$pair] ?? 0) + 1;
}
$rules = $rules->lines->mapAssoc(function ($i, $rule) {
[$from, $ins] = $rule->split(" -> ");
return [(string) $from => [$from[0] . $ins, $ins . $from[1]]];
});
$solve = function($steps) use ($pairs, $rules) {
for ($i = 0; $i < $steps; $i++) {
$npairs = [];
foreach ($pairs as $pair=>$count) {
foreach ($rules[$pair] as $p) {
$npairs[$p] = ($npairs[$p] ?? 0) + $count;
}
}
$pairs = $npairs;
}
$occ = [];
foreach ($pairs as $pair=>$c) {
foreach (str_split($pair) as $l) $occ[$l] = ($occ[$l] ?? 0) + $c;
}
// Divide by 2, because each letter is counted in two pairs
$occ = set($occ)->map(fn ($o) => ceil($o / 2));
return $occ->max() - $occ->min();
};
$solution_1 = $solve(10);
$solution_2 = $solve(40);