$grid = (array) $input->lines->map(fn ($l) => str_split($l));
$carts = [];
$crash = [];
$dirs = "^>v<";
// Scan grid for carts
for ($x = 0; $x < count($grid[0]); $x++) {
for ($y = 0; $y < count($grid); $y++) {
if (($dir = strpos($dirs, $grid[$y][$x])) !== false) {
$carts[] = [$x, $y, $dir, 0];
$grid[$y][$x] = $dir == 0 || $dir == 2 ? "|" : "-";
}
}
}
while (count($crash) < count($carts) - 1) {
// Move carts in order : top-left to bottom-right
$order = array_keys($carts);
usort($order, function ($a, $b) use ($carts) {
if ($carts[$a][1] == $carts[$b][1]) return $carts[$a][0] <=> $carts[$b][0];
return $carts[$a][1] <=> $carts[$b][1];
});
foreach ($order as $i) {
$cart = $carts[$i];
// Skip crashed carts
if (!empty($crash[$i])) continue;
// Move
match ($cart[2]) {
0 => $cart[1]--,
1 => $cart[0]++,
2 => $cart[1]++,
3 => $cart[0]--,
};
// Rotate at intersections
$cart[2] = match ($grid[$cart[1]][$cart[0]]) {
"+" => match ($cart[3]++ % 3) {
0 => ($cart[2] + 3) % 4,
1 => $cart[2],
2 => ($cart[2] + 1) % 4,
},
"/" => $cart[2] = [1, 0, 3, 2][$cart[2]],
"\\" => $cart[2] = [3, 2, 1, 0][$cart[2]],
"|", "-" => $cart[2]
};
$carts[$i] = $cart;
// Check for collision
foreach ($carts as $j=>$other) {
if (empty($crash[$j]) && $i != $j && $other[0] == $cart[0] && $other[1] == $cart[1]) {
$crash[$i] = true;
$crash[$j] = true;
}
}
}
}
// ==================================================
// > PART 1
// ==================================================
$first_crash = $carts[array_keys($crash)[0]];
$solution_1 = $first_crash[0] . "," . $first_crash[1];
// ==================================================
// > PART 2
// ==================================================
$cart_left = array_values(array_diff_key($carts, $crash))[0];
$solution_2 = $cart_left[0] . "," . $cart_left[1];