$grid = grid($input);
// Save positions of start and end
[$start, $end] = [$grid->search("S"), $grid->search("E")];
// Convert letters to height value
$grid = $grid->map(fn ($cell) => $cell == "S" ? 1 : ($cell == "E" ? 26 : ord($cell) - 96));
// Generate the list of nodes
$nodes = $grid->reduce(function ($nodes, $cell, $xy) use ($grid) {
$xy = xy($xy);
$nodes[(string) $xy] = $xy->getNeighbors()->filter(
// Keep only neighbors with a height difference of 1 or less
fn ($neighbor) => ($grid->get($neighbor) ?: INF) - $cell <= 1
)->mapAssoc(fn ($dir, $xy) => [(string) xy($xy) => 1]);
return $nodes;
}, set());
// ==================================================
// > PART 1
// ==================================================
$solution_1 = (new Graph($nodes))->explore((string) xy($start), (string) xy($end))[1];
// ==================================================
// > PART 2
// ==================================================
$starts = $grid->cells()->keep(1)->keys();
$nodes["S"] = $starts->mapAssoc(fn ($i, $xy) => [$xy => 0]);
$solution_2 = (new Graph($nodes))->setQueue("LIFO")->explore("S", (string) xy($end))[1];