// Define which person to sit next
$graph = new Graph(function ($graph) {
$seated = explode(">", $graph->current);
$person = $seated[count($seated) - 1];
$left = $graph->people->removeKeys($seated);
// No more people : close the loop with Alice
if ($left->empty() && $person != "Alice") {
return [
$graph->current . ">" . "Alice" =>
$graph->people[$person]["Alice"] + $graph->people["Alice"][$person]
];
}
// Pruning : if we can't go beyond the best relation yet, stop
$best_arrangement = empty($graph->values) ? 0 : max($graph->values);
$max_left = $left->callEach()->values()->merge()->max();
if (($graph->values[$graph->current] ?? 0) + $left->count() * $max_left * 2 < $best_arrangement) return [];
return $left->mapAssoc(function ($next, $relation) use ($person, $graph) {
return [
$graph->current . ">" . $next =>
$graph->people[$next][$person] + $graph->people[$person][$next]
];
});
}, "highest");
// Parse relations
$graph->people = set();
foreach ($input->lines as $line) {
preg_match("/^(\w+) would (gain|lose) (\d+) happiness units by sitting next to (\w+).$/", $line, $matches);
$graph->people[$matches[1]][$matches[4]] = (int) ($matches[2] == "gain" ? $matches[3] : $matches[3] * -1);
}
// ==================================================
// > PART 1
// ==================================================
// Start with Alice (doesn't matter who, it's a loop)
$solution_1 = $graph->explore("Alice")[1];
// ==================================================
// > PART 2
// ==================================================
// Add yourself
$graph->people = $graph->people->mapAssoc(fn ($person, $relations) =>
[$person => array_merge($relations, ["Me" => 0])]
);
$graph->people["Me"] = $graph->people->mapAssoc(fn ($person, $relations) =>
[$person => 0]
);
$solution_2 = $graph->explore("Alice")[1];