assuming I have $rows = 4
, and $cols = 4;
, How do I create a array with 16 elements in a spiral order, like:
1, 2, 3, 4,
12,13,14,5,
11,16,15,6,
10,9, 8, 7,
My solution is quite verbose, because the intent is for you to examine it and learn how it works.
<?php
/**
* Creates a 2D array with the given dimensions,
* whose elements are numbers in increasing order
* rendered in a 'spiral' pattern.
*/
function createSpiral($w, $h) {
if ($w <= 0 || $h <= 0) return FALSE;
$ar = Array();
$used = Array();
// Establish grid
for ($j = 0; $j < $h; $j++) {
$ar[$j] = Array();
for ($i = 0; $i < $w; $i++)
$ar[$j][$i] = '-';
}
// Establish 'used' grid that's one bigger in each dimension
for ($j = -1; $j <= $h; $j++) {
$used[$j] = Array();
for ($i = -1; $i <= $w; $i++) {
if ($i == -1 || $i == $w || $j == -1 || $j == $h)
$used[$j][$i] = true;
else
$used[$j][$i] = false;
}
}
// Fill grid with spiral
$n = 0;
$i = 0;
$j = 0;
$direction = 0; // 0 - left, 1 - down, 2 - right, 3 - up
while (true) {
$ar[$j][$i] = $n++;
$used[$j][$i] = true;
// Advance
switch ($direction) {
case 0:
$i++; // go right
if ($used[$j][$i]) { // got to RHS
$i--; $j++; // go back left, then down
$direction = 1;
}
break;
case 1:
$j++; // go down
if ($used[$j][$i]) { // got to bottom
$j--; $i--; // go back up, then left
$direction = 2;
}
break;
case 2:
$i--; // go left
if ($used[$j][$i]) { // got to LHS
$i++; $j--; // go back left, then up
$direction = 3;
}
break;
case 3:
$j--; // go up
if ($used[$j][$i]) { // got to top
$j++; $i++; // go back down, then right
$direction = 0;
}
break;
}
// if the new position is in use, we're done!
if ($used[$j][$i])
return $ar;
}
}
/**
* Assumes the input is a 2D array.
*/
function print2DGrid($array) {
foreach ($array as $row) {
foreach ($row as $col) {
print sprintf("% 2d ", $col);
}
print "\n";
}
}
$width = 12;
$height = 8;
print2DGrid(createSpiral($width, $height));
?>
Here it is in action, giving the following output:
0 1 2 3 4 5 6 7 8 9 10 11
35 36 37 38 39 40 41 42 43 44 45 12
34 63 64 65 66 67 68 69 70 71 46 13
33 62 83 84 85 86 87 88 89 72 47 14
32 61 82 95 94 93 92 91 90 73 48 15
31 60 81 80 79 78 77 76 75 74 49 16
30 59 58 57 56 55 54 53 52 51 50 17
29 28 27 26 25 24 23 22 21 20 19 18
Hope this helps.
Use a vector and boolean values. Iterate on the X axis to start with until you reach the end of the row. Set the value to true for each position as you traverse it. Anytime you reach a border or boolean true, turn right.
So on the first row your "vector" would change the X increment to zero and the Y increment to 1. Then you would check the value of the increment at each turn and accommodate the 4 scenarios.
This is the first way I thought of.
The second way would not use booleans, but would instead simply keep track of how many columns or rows are left in front of the cursor on its path, decreasing the X or Y remaining on each turn. The rest of the logic would remain the same.
When you reach the center, you will hit a loop where there are no more iterations possible. You can catch this by verifying the number of possibilities around the square, or simply counting down from N number of total squares from where you began, and stopping when the number hits zero.
You can use the above method for a square of any size.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With