Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP - create a spiral

Tags:

arrays

php

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,
like image 693
RebeccaBlack Avatar asked Dec 27 '22 21:12

RebeccaBlack


2 Answers

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.

like image 171
Lightness Races in Orbit Avatar answered Dec 30 '22 09:12

Lightness Races in Orbit


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.

like image 28
Mikecito Avatar answered Dec 30 '22 10:12

Mikecito