class Monkey
{
function __construct($monkey)
{
preg_match("/Starting items\: ?([^\n]+)/", $monkey->string, $items);
$this->items = set(explode(", ", $items[1]));
preg_match("/new = old ([^\n]+)/", $monkey->string, $op);
$this->op = explode(" ", $op[1]);
preg_match("/divisible by ([0-9]+)/", $monkey->string, $test);
$this->test = (int) $test[1];
preg_match_all("/throw to monkey ([0-9]+)/", $monkey->string, $pass);
$this->pass = $pass[1];
$this->inspected = 0;
}
function inspect($monkeys, $divider, $reductor)
{
global $ops;
$worry = $this->items->shift();
$this->inspected++;
$worry = ($this->op[0] == "+" ? $worry + $this->op[1] : (
$this->op[1] == "old" ? ($worry * $worry) : ($worry * $this->op[1])
));
$worry = floor($worry / $divider);
$worry = $worry % $reductor; // Avoid numbers too large while keeping testing integrity
$next = $worry % $this->test ? $this->pass[1] : $this->pass[0];
$monkeys[$next]->items[] = $worry;
}
}
function get_solution($input, $rounds, $divider)
{
$monkeys = $input->split("\n\n")->map(fn($monkey) => new Monkey($monkey));
$reductor = $monkeys->column("test")->multiply();
for ($i = 0; $i < $rounds; $i++) {
foreach ($monkeys as $monkey) {
while ($monkey->items->count()) {
$monkey->inspect($monkeys, $divider, $reductor);
}
}
}
return $monkeys->column("inspected")->sort()->slice(-2)->multiply();
}
// ==================================================
// > SOLUTIONS
// ==================================================
$solution_1 = get_solution($input, 20, 3);
$solution_2 = get_solution($input, 10000, 1);