Robson » Code Viewer

<?

/*
   Maze Generator v1.0
   http://iceyboard.no-ip.org/projects/maze_generator/
   Copyright (C) 2006-2008 Robson
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   The license can be viewed at
       http://www.gnu.org/licenses/gpl-2.0.txt
*/

  // don't allow too much processing on the server
  // if you run this script on your computer, you can remove this
  set_time_limit(20);

  // this checks to see if any spaces are left in the array
  function has_spaces($array)
  {
      // loop through each record
      foreach($array as $record)
      {
          // check if there is space anywhere inside that record
          if (in_array(' ', $record))
              // if so, save that
              $spaces = TRUE;
      }
      // return if the array has space available
      return $spaces;
  }

  // check user entered data

  if (intval($_GET['size']) >= 5 && intval($_GET['size'] <= 60))
      $size = $_GET['size'];
  else
      $size = 20;
     
  if ($size < 6)
      $size = 6;
  // the moon shape requires more space    
  if ($_GET['shape'] == 'moon' && $size < 10)
      $size = 10;
     
  if (intval($_GET['size_corridor']) > 0 && intval($_GET['size_corridor']) <= 100)
      $thickness = $_GET['size_corridor'];
  else
      $thickness = 10;

  if (intval($_GET['corridors']) >= 0)
      $straight = intval($_GET['corridors']);
  else
      $straight = 3;

  $image_size = ($size*$thickness)+1;
  // create the blank image
  $im = imagecreate($image_size, $image_size);

  $add = ceil($thickness/2);
 
  // allocate colours to the image
  // white first, so that's the background
  $white = imagecolorallocate($im, 255, 255, 255);
  $black = imagecolorallocate($im, 0, 0, 0);
  $red   = imagecolorallocate($im, 255, 0, 0);
  $green = imagecolorallocate($im, 0, 255, 0);
  $blue  = imagecolorallocate($im, 0, 0, 255);

  // various directions that we can go
  $directions = array(
          array(0, 1, 'down', 'up'),
          array(1, 0, 'right', 'left'),
          array(0, -1, 'up', 'down'),
          array(-1, 0, 'left', 'right')
                      );
 
  // fill with spaces
  for ($n = 0; $n < $size; $n++)
      // rooms in the maze
      $squares[$n] = array_fill(0, $size, ' ');
 
  // create an identical array that will contain the solution    
  $path = $squares;
     
  // removes squares in the grid to create shapes
     
  switch ($_GET['shape'])
  {    
      // or is it a half-strike? ;)
      case 'strike':
          for ($a = 0; $a < $size-floor($size/5); $a++)
          {
              for ($b = 0; $b < $a; $b++)
              {
                  $squares[$b][$a+floor($size/5)] = 2;
                  $squares[$a+floor($size/5)][$b] = 2;
              }
          }
          $begin = array(0, 0);
          $end = array($size-1, $size-1);
      break;
      case 'diamond':
          $mid = floor($size/2);
          if (!($size % 2))
              $even = 1;
          for ($a = 0; $a < $size-$mid; $a++)
          {
              for ($b = 0; $b < $a; $b++)
              {
                  $squares[$b][$a+$mid] = 2;
                  $squares[$a+$mid][$b] = 2;
                  $squares[$mid-($a+$even)][$b] = 2;
                  $squares[$a+$mid][$size-($b+1)] = 2;
              }
          }
          $begin = array($mid, 0);
          $end = array($mid, $size-1);
      break;
      // star is a diamond with a small square in the middle
      // that creates eight points
      case 'star':
          $mid = floor($size/2);
          if (!($size % 2))
              $even = 1;
          for ($a = 0; $a < $size-$mid; $a++)
          {
              for ($b = 0; $b < $a; $b++)
              {
                  $squares[$b][$a+$mid] = 2;
                  $squares[$a+$mid][$b] = 2;
                  $squares[$mid-($a+$even)][$b] = 2;
                  $squares[$a+$mid][$size-($b+1)] = 2;
              }
          }
          for ($a = intval($size*0.16); $a < intval($size*0.84); $a++)
          {
              for ($b = intval($size*0.16); $b < intval($size*0.84); $b++)
                  $squares[$a][$b] = ' ';
          }
          $begin = array($mid, 0);
          $end = array($mid, $size-1);        
      break;
      // triangle slices off the top right corner
      // similar to a sandwich container
      case 'triangle':
          for ($a = 0; $a < $size; $a++)
          {
              for ($b = 0; $b < $a; $b++)
                  $squares[$a][$b] = 2;
          }
          $begin = array(0, 0);
          $end = array($size-1, $size-1);            
      break;
      // circles are a bit trickier because it's necessary to work out
      // the cells that are included inside the circle
      case 'circle':
          $mid = $image_size/2;
          for ($a = 0; $a < $size; $a++)
          {
              for ($b = 0; $b < $size; $b++)
              {
                  $x_dst = ($a * $thickness)-$mid;
                  $y_dst = ($b * $thickness)-$mid;
                  $distance = sqrt(($x_dst*$x_dst) + ($y_dst*$y_dst));
             
                  if ($distance > ($image_size*0.48))
                      $squares[$a][$b] = 2;
             
              }
          }
          if ($size>=50)
              $begin = array(floor($size/2), 2);
          else
              $begin = array(floor($size/2), 1);
          if ($size>=55)
              $end = array(floor($size/2), $size-2);            
          else
              $end = array(floor($size/2), $size-1);            
      break;
      // moon is a circle with a small circle just off center to the right
      case 'moon':
          $mid = $image_size/2;
          for ($a = 0; $a < $size; $a++)
          {
              for ($b = 0; $b < $size; $b++)
              {
                  $x_dst = ($a * $thickness)-$mid;
                  $y_dst = ($b * $thickness)-$mid;
                  $distance = sqrt(($x_dst*$x_dst) + ($y_dst*$y_dst));
             
                  if ($distance > ($image_size*0.48))
                      $squares[$a][$b] = 2;
             
              }
          }
          $mid = $image_size/2;
          $left = $image_size*0.75;
          for ($a = 0; $a < $size; $a++)
          {
              for ($b = 0; $b < $size; $b++)
              {
                  $x_dst = ($a * $thickness)-$left;
                  $y_dst = ($b * $thickness)-$mid;
                  $distance = sqrt(($x_dst*$x_dst) + ($y_dst*$y_dst));
             
                  if ($distance < ($image_size*0.45))
                      $squares[$a][$b] = 2;
             
              }
          }            
          $begin = array(floor($size/2), 1);
          $end = array(floor($size/2), $size-1);            
      break;        
      // the two rooms shape has two corridors
      // although one usually gets closed off
      case 'two-rooms':
          for ($a = 0; $a < ceil($size/2)+2; $a++)
          {
              for ($b = 0; $b < ceil($size/2)+2; $b++)
              {
                  $squares[$size-$a][$b] = 2;
                  $squares[$a][$size-$b] = 2;
              }
          }    
          for ($a = 0; $a < floor($size/2); $a++)
          {
              for ($b = intval($size/4); $b < intval($size*0.75); $b++)
              {
                  $squares[intval($size*0.25)][$b] = ' ';
                  $squares[intval($size*0.75)][$b] = ' ';
                  $squares[$b][intval($size*0.25)] = ' ';
                  $squares[$b][intval($size*0.75)] = ' ';
                  $squares[intval($size*0.25)+1][$b] = ' ';
                  $squares[intval($size*0.75)+1][$b] = ' ';
                  $squares[$b][intval($size*0.25)+1] = ' ';
                  $squares[$b][intval($size*0.75)+1] = ' ';
              }
          }        
          $begin = array(0, 0);
          $end = array($size-1, $size-1);    
      break;          
      // six rooms doesn't actually exist, but everything has a purpose
      case 'six-rooms':
          exit(chr(82).chr(111).chr(98).chr(115).chr(111).chr(110));
      break;    
      // four rooms is four filled squares and one thick square to make the corridors
      case 'four-rooms':
          $center = floor($size/2);
          $quarter = floor($size/4);
          for ($n = 0; $n < $size; $n++)
          {
              if ($n <> $quarter && $n <> $size-$quarter && $n <> $quarter+1 && $n <> $size-$quarter-1)
              {
                  $squares[$n][$center] = 2;
                  $squares[$center][$n] = 2;
                  $squares[$n][$center-1] = 2;
                  $squares[$center-1][$n] = 2;
                  $squares[$n][$center+1] = 2;
                  $squares[$center+1][$n] = 2;
              }
          }
          $begin = array(0, 0);
          $end = array($size-1, $size-1);                
      break;
      case 'l':
          for ($n = $size-intval($size*0.75); $n < $size; $n++)
          {
              for ($b = 0; $b < intval($size*0.75); $b++)
                  $squares[$n][$b] = 2;
          }
          $begin = array(0, 0);
          $end = array($size-1, $size-1);                
      break;
      // box is cretaed by placing a square in the middle
      case 'box':
          for ($n = $size-intval($size*0.75); $n < intval($size*0.75); $n++)
          {
              for ($b = $size-intval($size*0.75); $b < intval($size*0.75); $b++)
                  $squares[$n][$b] = 2;
          }
          $begin = array(0, 0);
          $end = array($size-1, $size-1);                
      break;
      // the default has all the squares shown
      default:
          $begin = array(0, 0);
          $end = array($size-1, $size-1);            
      break;
  }    
 
  // generate paths around the grid
     
  do
  {
      // find an available starting square
      do
      {
          // random cell
          $start = array(mt_rand(0, $size-1), mt_rand(0, $size-1));
          // if the first, use any, if not, pick an already taken cell to start
          if ((!$started && $squares[$start[0]][$start[1]] == ' ') || $squares[$start[0]][$start[1]] == 1)
              $current = $start;
      } while($current <> $start);
     
      $squares[$current[0]][$current[1]] = 1;
      $started = true;
     
      do
      {
          // shuffle the directions based on twisted value
          // lower means more shuffling and more direction changes
          if (!mt_rand(0, $straight))
              shuffle($directions);
             
          // loop through the directions (up, down, left, right)    
          foreach ($directions as $way)
          {
              $next[0] = $current[0] + $way[0];
              $next[1] = $current[1] + $way[1];
              // check if this cell is empty
              if ($squares[$next[0]][$next[1]] == ' ')
              {
                  // yes, so move the path into this cell
                  $sq[$current[0]][$current[1]][$way[2]] = 1;
                  $sq[$next[0]][$next[1]][$way[3]] = 1;
                  $current = $next;
                  $squares[$next[0]][$next[1]] = 1;                    
                  break;
              }
          }
      } while ($current == $next && has_spaces($squares));
  // when there are no spaces left, exit this loop    
  } while (has_spaces($squares));
 
  // draw the borders of the squares to create the maze walls

  for ($a = 0; $a < count($squares); $a++)
  {
      for ($b = 0; $b < count($squares); $b++)
      {
          // only draw borders on cells which have paths
          if ($squares[$a][$b] == 1)
          {
              // check directions
              if (!$sq[$a][$b]['down'])
                  imageline($im, $a * $thickness, ($b+1) * $thickness, ($a+1) * $thickness, ($b+1) * $thickness, $black);
              if (!$sq[$a][$b]['up'])
                  imageline($im, $a * $thickness, $b * $thickness, ($a+1) * $thickness, $b * $thickness, $black);
              if (!$sq[$a][$b]['left'])
                  imageline($im, $a * $thickness, $b * $thickness, $a * $thickness, ($b+1) * $thickness, $black);
              if (!$sq[$a][$b]['right'])
                  imageline($im, ($a+1) * $thickness, $b * $thickness, ($a+1) * $thickness, ($b+1) * $thickness, $black);
          }
      }
  }

  // add the start and end dots
  // green = start / red = end
  imagefilledellipse($im, ($begin[0]*$thickness)+$add, ($begin[1]*$thickness)+$add, $thickness*0.75, $thickness*0.75, $green);
  imagefilledellipse($im, ($end[0]*$thickness)+$add, ($end[1]*$thickness)+$add, $thickness*0.75, $thickness*0.75, $red);
 
  // solve the maze
 
  if ($_GET['solution'])
  {
      $step = $begin;
      $path[$step[0]][$step[1]] = 1;

      // solve
      do
      {
          $is_backtrack = false;
          $here = $step;
          // go down
          if ($sq[$step[0]][$step[1]]['down'] && $path[$step[0]][$step[1]+1] == 0)
              $step[1]+=1;
          // go right
          else if ($sq[$step[0]][$step[1]]['right'] && $path[$step[0]+1][$step[1]] == 0)
              $step[0]+=1;
          // go up
          else if ($sq[$step[0]][$step[1]]['up'] && $path[$step[0]][$step[1]-1] == 0)
              $step[1]-=1;
          // go left
          else if ($sq[$step[0]][$step[1]]['left'] && $path[$step[0]-1][$step[1]] == 0)
              $step[0]-=1;
         
          if ($step <> $here)
              // if an available cell was found, move the current position to there
              $path[$step[0]][$step[1]] = 1;
          else
          {
              $is_backtrack = true;
              $path[$step[0]][$step[1]] = 2;
              // go up
              if ($sq[$step[0]][$step[1]]['up'] && $path[$step[0]][$step[1]-1] == 1)
                  $step[1]-=1;
              // go down
              else if ($sq[$step[0]][$step[1]]['down'] && $path[$step[0]][$step[1]+1] == 1)
                  $step[1]+=1;
              // go left
              else if ($sq[$step[0]][$step[1]]['left'] && $path[$step[0]-1][$step[1]] == 1)
                  $step[0]-=1;
              // go right
              else if ($sq[$step[0]][$step[1]]['right'] && $path[$step[0]+1][$step[1]] == 1)
                  $step[0]+=1;
          }    
             
          // was this a backtrack from a dead end    
          if ($is_backtrack)    
          {
              // if they want to see backtracks
              if ($_GET['backtrack'])
              {
                  // creates three dots each time and nice rounded corners
                  imagesetstyle($im, array($white, $white, $red));
                  // display the backtrack
                  imageline($im, ($here[0] * $thickness)+($thickness/2), ($here[1] * $thickness)+($thickness/2),
                      ($step[0] * $thickness)+($thickness/2), ($step[1] * $thickness)+($thickness/2), IMG_COLOR_STYLED);    
              }
              else
                  // if the user doesn't want to see backtracks, just override the green with white
                  imageline($im, ($here[0] * $thickness)+($thickness/2), ($here[1] * $thickness)+($thickness/2),
                      ($step[0] * $thickness)+($thickness/2), ($step[1] * $thickness)+($thickness/2), $white);    
          }
          else
          {
              // creates three dots each time and nice rounded corners
              imagesetstyle($im, array($white, $white, $blue));
              // this is a potential correct path, so colour in
              imageline($im, ($here[0] * $thickness)+($thickness/2), ($here[1] * $thickness)+($thickness/2),
                          ($step[0] * $thickness)+($thickness/2), ($step[1] * $thickness)+($thickness/2), IMG_COLOR_STYLED);    
          }
                 
      // loop until we reach the end                    
      } while ($step <> $end);
  }
 
  // output as a png graphic
  header('Content-type: image/png');    
  // echo out the contents of the image
  imagepng($im);        
 
?>