Advent of code 2016/22
Ajax Direct

Answer

Part 1 :
Part 2 :
// ==================================================
// > PART 1
// ==================================================
// X, Y, Size, Used, Avail, Use%
$nodes = $input->lines->slice(2)->map(fn ($l) => $l->numbers());

$solution_1 = 0;
foreach ($nodes as $a) foreach ($nodes as $b) {
    if ($a[0] == $b[0] && $a[1] == $b[1]) continue;
    if (empty($a[3])) continue;
    if ($b[4] < $a[3]) continue;
    $solution_1++;
}

// ==================================================
// > PART 2
// ==================================================

// Define graph : empty space can move everywhere except to heavy nodes
$graph = new Graph(function ($graph) {
    $neighbors = neighbors(explode(";", $graph->current), false, 0, $graph->width, 0, $graph->height);
    $neighbors = array_filter($neighbors, fn ($n) => !in_array($n, $graph->heavy));
    return array_fill_keys(array_map(fn ($xy) => implode(";", $xy), $neighbors), 1);
});

// Compute nodes
$cells = $input->lines->slice(2)->mapAssoc(function ($i, $line) {
    [$x, $y, $size, $used] = $line->numbers;
    return ["$x;$y" => [$x, $y, $used, $size]];
});

$graph->width = $cells->column(0)->max();
$graph->height = $cells->column(1)->max();

$average_space = $cells->column(3)->average();
$graph->heavy = (array) $cells->filter(fn ($n) => $n[3] > $average_space)->keys()->map(fn ($k) => explode(";", $k));

// Start exploring : shortest path to move empty cell to the left of the target
$solution_2 = $graph->explore(
    $cells->column(2)->search(0),
    ($graph->width - 1).";0"
);

// Move the target to the goal (0;0) by moving the empty cell around it (5 moves per cell)
$solution_2 = $solution_2[1] + ($graph->width - 1) * 5 + 1;