/**
* Return the cuboid intersection of two cuboids,
* plus all remaining cuboids resulting from their difference
*
* @param array $c1 Subject cuboid
* @param array $c2 Difference cuboid
* @return array [intersection, remaining cuboids]
*/
function cube_intersect($c1, $c2)
{
// Fully outside : no intersection
foreach ([0, 2, 4] as $ax) {
if ($c2[$ax+1] < $c1[$ax] && $c2[$ax+1] < $c1[$ax+1]) return [[], [$c1]];
if ($c2[$ax] > $c1[$ax] && $c2[$ax] > $c1[$ax+1]) return [[], [$c1]];
}
// Find intersection cube
$int = [];
foreach ([0, 2, 4] as $ax) {
$int[] = $c2[$ax] > $c1[$ax] ? $c2[$ax] : $c1[$ax];
$int[] = $c2[$ax+1] < $c1[$ax+1] ? $c2[$ax+1] : $c1[$ax+1];
}
// Split on each axis
$cubes = [$c1];
foreach ([0, 2, 4] as $ax) {
$cube = array_shift($cubes);
[$ca, $cb] = [$cube[$ax], $cube[$ax+1]];
[$ia, $ib] = [$int[$ax], $int[$ax+1]];
$ax_split = [[$ia, $ib]];
if ($ca < $ia) $ax_split[] = [$ca, $ia-1];
if ($cb > $ib) $ax_split[] = [$ib+1, $cb];
$cube_split = [];
foreach ($ax_split as $asp) {
$ncube = $cube;
$ncube[$ax] = $asp[0];
$ncube[$ax+1] = $asp[1];
$cube_split[] = $ncube;
}
$cubes = array_merge($cube_split, $cubes);
}
return [array_shift($cubes), $cubes];
}
function solve($part1) {
global $input;
$on = [];
foreach ($input->lines as $line) {
$new_on = [];
$zone = (array) $line->numbers();
if ($part1 && ($zone[0] < -50 || $zone[0] > 50)) break;
if ($line->split(" ")[0] == "on") $new_on[] = $zone;
foreach ($on as $other_zone) {
$new_on = array_merge($new_on, cube_intersect($other_zone, $zone)[1]);
}
$on = $new_on;
}
return array_reduce($on, function ($carry, $c) {
return $carry + abs($c[0]-$c[1]-1) * abs($c[2]-$c[3]-1) * abs($c[4]-$c[5]-1);
}, 0);
}
// ==================================================
// > SOLUTION
// ==================================================
$solution_1 = solve(true);
$solution_2 = solve(false);