/**
* Direct value of a bin
*
* @param string $bin
* @return array [value, remaining bits]
*/
function direct_value($bin) {
$num = "";
for ($i = 0;; $i += 5) {
$num .= substr($bin, $i + 1, 4);
if (!$bin[$i]) break;
}
return [bindec($num), substr($bin, $i + 5)];
}
/**
* Decode a bin that has subpackets
*
* @param string $bin
* @return array [version total, values, remaining bits]
*/
function sub_decode($bin) {
$v = 0;
$values = [];
[$i, $bin] = [$bin[0], substr($bin, 1)];
$l = bindec(substr($bin, 0, $i ? 11 : 15));
$bin = substr($bin, $i ? 11 : 15);
while (true) {
[$sv, $sn, $rest] = decode($bin);
$v += $sv;
$values[] = $sn;
$l -= $i ? 1 : strlen($bin) - strlen($rest);
$bin = $rest;
if (!$l) break;
}
return [$v, $values, $rest];
}
/**
* Decode a bin
*
* @param string $bin
* @return array [version total, value, remaining bits]
*/
function decode($bin) {
[$v, $t, $bin] = [bindec(substr($bin, 0, 3)), bindec(substr($bin, 3, 3)), substr($bin, 6)];
// Direct value : return has is
if ($t == 4) return [$v, ...direct_value($bin)];
// Operation : get values of all subpackets and then apply operation
[$sv, $values, $bin] = sub_decode($bin);
$v += $sv;
$value = match($t) {
0 => array_sum($values),
1 => array_product($values),
2 => min($values),
3 => max($values),
5 => (int) ($values[0] > $values[1]),
6 => (int) ($values[0] < $values[1]),
7 => (int) ($values[0] == $values[1]),
default => 0
};
return [$v, $value, $bin];
}
// ==================================================
// > SOLVE
// ==================================================
$bin = $input->chars()->map(fn ($c) =>
str_pad(base_convert($c, 16, 2), 4, "0", STR_PAD_LEFT)
)->join();
[$solution_1, $solution_2] = decode($bin);