function solve($input, $return = false) {
$grid = grid($input)->map(fn ($c) => $c->string);
$points = $input->numbers()->mapAssoc(fn ($i, $v) => [$v => $grid->search($v)]);
$walls = $grid->cells()->keep("#");
// Define graph
$graph = new Graph(function ($graph) use ($walls) {
$neighbors = array_map(fn ($xy) => implode(";", $xy), neighbors(explode(";", $graph->current)));
$neighbors = array_filter($neighbors, fn ($xy) => empty($walls[$xy]));
return array_fill_keys($neighbors, 1);
});
// Compute all shortest paths between each point
$paths = [];
foreach ($points->keys()->combinations(2, 2) as $comb) {
$path = $graph->explore(implode(";", $points[$comb[0]]), implode(";", $points[$comb[1]]));
$paths[$comb[0]][$comb[1]] = $path[1];
$paths[$comb[1]][$comb[0]] = $path[1];
}
// Look for the shortest permulation of all points
$shortest = INF;
foreach ($points->keys()->remove(0)->permutations() as $perm) {
array_unshift($perm, 0); // Start at 0
if ($return) array_push($perm, 0); // Return to 0
$dist = 0;
for ($i = 0; $i < count($perm) - 1; $i++) {
$dist += $paths[$perm[$i]][$perm[$i + 1]];
}
if ($dist < $shortest) {
$shortest = $dist;
}
}
return $shortest;
}
// ==================================================
// > SOLUTIONS
// ==================================================
$solution_1 = solve($input);
$solution_2 = solve($input, true);