Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Created November 2, 2014 11:58
Show Gist options
  • Save CMCDragonkai/90250599fb0274265c3c to your computer and use it in GitHub Desktop.
Save CMCDragonkai/90250599fb0274265c3c to your computer and use it in GitHub Desktop.
PHP: Does the turtle cross a point that it has already visited? (Possibly useful in a snake games)
<?php
/**
* Logo Turtle Challenge
* A turtle starts at (0,0).
* You have an array of movements, where each element represents the distance of a single move.
* Directions are cycled every four elements going through north, east, south, west.
* Find the move where the turtle crosses through a point that it has passed through before.
* This solution is somewhat space inefficient, and could become time inefficient if the distance range for a particular move is huge!
* There is probably a solution that allows you to persist only the corner coordinates and then using line equations to figure out if they intersect.
* The space inefficiency could be partially solved with a xrange generator.
* Right now it's kind of like O(n * (m+m)) where m is the average size of the distance range.
* However if you create a custom xrange generator, that allows us to lazily build out the $coordinates_to_check, then it would become O(n*m) where m is the average size of the distance range.
* You would still need keep the $coordinates array though!
* Could be further micro-optimised by only checking the coordinates on the fourth[3] movement.
*/
function logo_turtle($movements) {
$coordinates = [0 => [0 => true]];
$current_coordinate = [
'x' => 0,
'y' => 0
];
$directions = ['n', 'e', 's', 'w'];
foreach($movements as $move => $distance){
// cycle through the directions
$current_direction = array_shift($directions);
array_push($directions, $current_direction);
// if the distance is less than 1, then skip it, but we still cycle the direction!
if ($distance < 1) {
continue;
}
// clean slate
$coordinates_to_check = [];
// for each direction, acquire a list of coordinates derived from its traverse
// these coordinates will be used to check if turtle crosses its own previous path
switch($current_direction){
case 'n':
$x_end = $current_coordinate['x'];
$y_end = $current_coordinate['y'] + $distance;
$start = $current_coordinate['y'] + 1;
foreach(range($start, $y_end) as $value){
$coordinates_to_check[] = [ 'x' => $current_coordinate['x'], 'y' => $value];
}
break;
case 'e':
$x_end = $current_coordinate['x'] + $distance;
$y_end = $current_coordinate['y'];
$start = $current_coordinate['x'] + 1;
foreach(range($start, $x_end) as $value){
$coordinates_to_check[] = [ 'x' => $value, 'y' => $current_coordinate['y']];
}
break;
case 's':
$x_end = $current_coordinate['x'];
$y_end = $current_coordinate['y'] - $distance;
$start = $current_coordinate['y'] - 1;
foreach(range($start, $y_end) as $value){
$coordinates_to_check[] = [ 'x' => $current_coordinate['x'], 'y' => $value];
}
break;
case 'w':
$x_end = $current_coordinate['x'] - $distance;
$y_end = $current_coordinate['y'];
$start = $current_coordinate['x'] - 1;
foreach(range($start, $x_end) as $value){
$coordinates_to_check[] = [ 'x' => $value, 'y' => $current_coordinate['y']];
}
break;
}
// if the traversal meets one of the existing coordinates, then the current move is an interception
foreach($coordinates_to_check as $xy){
if(
isset(
$coordinates[
$xy['x']
][
$xy['y']
]
)
){
return $move;
}
// add the point to the list of coordinates that has been traversed
$coordinates[$xy['x']][$xy['y']] = true;
}
// update the current coordinate for the next iteration
$current_coordinate = [
'x' => $x_end,
'y' => $y_end
];
}
return -1;
}
$moves = [1, 3, 2, 5, 4, 4, 6, 3, 2];
$turtle_move = logo_turtle($moves);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment