Advent of code 2021/14
Ajax Direct

Answer

Part 1 :
Part 2 :
[$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);