function get_solution($self, $grid, $steps, $rotations, $wrap_selection = null)
{
$facings = set([">", "v", "<", "^"]);
$facing = ">";
while ($steps->count() || $rotations->count()) {
// Move steps but stop at first rock hit
$direction = direction($facing);
$infront = $grid->slice($self, $direction);
$step = (int) $steps->shift();
$edge = $infront->count();
$rock = $infront->search("#");
$self->direction(
$direction,
min($step, $edge, $rock === false ? INF : $rock)
);
// Wrap arround if we met the edge before finishing our steps
if ($rock === false && $step > $edge) {
$step -= $edge;
if ($wrap_selection) {
[$wrap, $new_facing] = $wrap_selection($self, $facing, $grid);
} else {
[$wrap, $new_facing] = [$grid->wrap($self->getNeighbor($direction), $direction), $facing];
}
// Not a rock, go to the wrap point and continue from there
if ($grid->get($wrap) != "#") {
$self->setXY($wrap);
$steps->unshift($step - 1);
$facing = $new_facing;
continue;
}
}
// Apply rotation
if (!$rotations->count()) continue;
$facing = $facings[($facings->search($facing) + ["R" => 1, "L" => 3][$rotations->shift()]) % 4];
}
return ($self[1] + 1) * 1000 + ($self[0] + 1) * 4 + $facings->search($facing);
}
// Parse the input, make a grid and get steps/rotations
[$map, $moves] = $input->split("\n\n");
// Grid and start position
$grid = grid($map, 1)->filter();
$start = xy([$grid->rows[0]->keys()->first(), 0]);
// Steps and rotations
preg_match_all("/[0-9]+/", $moves, $steps);
preg_match_all("/[A-Z]+/", $moves, $rotations);
// Solution 1 : default wrap method
$solution_1 = get_solution(clone $start, clone $grid, set($steps[0]), set($rotations[0]));
// Solution 2 : custom wrap using a cube
$edges = [
"1:0" => ["^" => ["0:3", ">", false], "<" => ["0:2", ">", true]],
"2:0" => ["^" => ["0:3", "^", false], ">" => ["1:2", "<", true], "v" => ["1:1", "<", false]],
"1:1" => [">" => ["2:0", "^", false], "<" => ["0:2", "v", false]],
"0:2" => ["^" => ["1:1", ">", false], "<" => ["1:0", ">", true]],
"1:2" => [">" => ["2:0", "<", true], "v" => ["0:3", "<", false]],
"0:3" => [">" => ["1:2", "^", false], "v" => ["2:0", "v", false], "<" => ["1:0", "v", false]],
];
$solution_2 = get_solution(clone $start, clone $grid, set($steps[0]), set($rotations[0]), function ($pos, $facing, $grid) use ($edges) {
$face = floor($pos[0] / 50).":".floor($pos[1] / 50);
[$x, $y] = [$pos[0] % 50, $pos[1] % 50];
[$new_face, $new_facing, $invert] = $edges[$face][$facing];
switch ($new_facing) {
case ">":
$nx = 0;
$ny = abs(($invert ? 49 : 0) - (in_array($facing, ["v", "^"]) ? $x : $y));
break;
case "<":
$nx = 49;
$ny = abs(($invert ? 49 : 0) - (in_array($facing, ["v", "^"]) ? $x : $y));
break;
case "^":
$nx = abs(($invert ? 49 : 0) - (in_array($facing, ["v", "^"]) ? $x : $y));
$ny = 49;
break;
case "v":
$nx = abs(($invert ? 49 : 0) - (in_array($facing, ["v", "^"]) ? $x : $y));
$ny = 0;
break;
}
$mult = explode(":", $new_face);
$wrap = [[$mult[0]*50 + $nx, $mult[1]*50 + $ny], $new_facing];
return $wrap;
});