// Build rules index with every rotation and flip
$rules = [];
foreach ($input->lines as $line) {
// Parse rule
$rule = explode(" => ", $line);
[$pattern, $expand] = [explode("/", $rule[0]), explode("/", $rule[1])];
$pattern = array_map("str_split", $pattern);
// Rotate + flip 4 times
for ($i = 0; $i < 4; $i++) {
// Rotate & register
$pattern = array_map(null, ...$pattern);
$pattern = array_map("array_reverse", $pattern);
$rules[implode("/", array_map("implode", $pattern))] = $expand;
// Flip & register
$fliped = array_map("array_reverse", $pattern);
$rules[implode("/", array_map("implode", $fliped))] = $expand;
}
}
// Enhance square one time
function enhance($square, $rules) {
$len = strlen($square[0]) % 2 == 0 ? 2 : 3;
$cnt = count($square) / $len;
// Split square intro subsquares of size $len
$squares = array_merge(...array_map(fn ($chunk) =>
array_map(fn ($square) => implode("/", $square), array_map(null, ...$chunk))
, array_chunk(array_map(fn ($row) => str_split($row, $len), $square), $len)));
// Enhance subsquares
$squares = array_map(fn ($square) => $rules[$square], $squares);
// Merge subsquares into square
return $cnt > 1 ? array_merge(...array_map(fn ($chunk) =>
array_map("implode", array_map(null, ...$chunk))
, array_chunk($squares, $cnt))) : $squares[0];
}
function solve($count, $rules) {
$square = explode("/", ".#./..#/###");
for ($i = 0; $i < $count; $i++) {
$square = enhance($square, $rules);
}
return substr_count(implode("", $square), "#");
}
// ==================================================
// > SOLUTONS
// ==================================================
$solution_1 = solve(5, $rules);
$solution_2 = solve(18, $rules);