<?php

class Maze{
  var $maze = array();
  var $mx = 0;
  var $my = 0;
  var $debug = false;

  function Maze($mx, $my){
    $mx +=2;
    $my +=2;
    $this->mx = $mx;
    $this->my = $my;
    $dx = array( 0, 0, -1, 1 );
    $dy = array( -1, 1, 0, 0 );
    $todo = array(); 
    $todonum = 0;

    for ($x = 0; $x < $mx; ++$x){
      for ($y = 0; $y < $my; ++$y){
        if ($x == 0 || $x == $mx-1 || $y == 0 || $y == $my-1) {
          $this->maze[$x][$y] = 32;
        } else {
          $this->maze[$x][$y] = 63;
        }
      }
    }

    $x = rand(1, $mx-2);
    $y = rand(1, $my-2);
    $x = 1;
    $y = 1;
    
    $this->maze[$x][$y] &= ~48;

    for ($d = 0; $d < 4; ++$d){
      if (($this->maze[$x + $dx[$d]][$y + $dy[$d]] & 16) != 0) {
        $todo[$todonum++] = (($x + $dx[$d]) << 16) | ($y + $dy[$d]);
        $this->maze[$x + $dx[$d]][$y + $dy[$d]] &= ~16;
      }
    }

    while ($todonum > 0) {
      // We select one of the squares next to the maze.

      if ($this->debug)
        echo $this->render($x, $y);

      $n = rand(0, $todonum-1);

      $x = $todo[$n] >> 16; // the top 2 bytes of the data 
      $y = $todo[$n] & 65535; // the bottom 2 bytes of the data

      // We will connect it, so remove it from the queue.
      $todo[$n] = $todo[--$todonum];

      // Select a direction, which leads to the maze. 
      do {
        $d = rand(0, 3);
      } while (($this->maze[$x + $dx[$d]][$y + $dy[$d]] & 32) != 0);
      
      // Connect this square to the maze.
      $this->maze[$x][$y] &= ~((1 << $d) | 32);
      $this->maze[$x + $dx[$d]][$y + $dy[$d]] &= ~(1 << ($d ^ 1));

      // Remember the surrounding squares, which aren't queued
      for ($d = 0; $d < 4; ++$d){
        if (($this->maze[$x + $dx[$d]][$y + $dy[$d]] & 16) != 0) {
          // connected to the maze, and aren't yet queued to be
          $todo[$todonum++] = (($x + $dx[$d]) << 16) | ($y + $dy[$d]);
          $this->maze[$x + $dx[$d]][$y + $dy[$d]] &= ~16;
        }
        // Repeat until finished.
      }
    }
    $this->maze[1][1] &= ~1;
    $this->maze[$mx-2][$my-2] &= ~2;
  }
  
  function render($rx = -1, $ry = -1){
    $t = "<table>\n";
    for ($y = 1; $y < $this->my-1; ++$y) {
      $t .= "  <tr>\n";
      for ($x = 1; $x < $this->mx-1; ++$x){
        $c = '';
        if ($x == $rx && $y == $ry){
          $c = 'r ';
        }
        if (($this->maze[$x][$y] & 1) != 0) /* This cell has a top wall */
          $c .= 'tw ';
        if (($this->maze[$x][$y] & 2) != 0) /* This cell has a bottom wall */
          $c .= 'bw ';
        if (($this->maze[$x][$y] & 4) != 0) /* This cell has a left wall */
          $c .= 'lw ';
        if (($this->maze[$x][$y] & 8) != 0) /* This cell has a right wall */
          $c .= 'rw ';
        $t .= "  <td class=\"$c\">&nbsp;</td>\n";
      }
      $t .= "  </tr>\n";
    }
    $t .= "</table>\n";
    return $t;
  }
  function getStyle(){
    $style = 
'<style type="text/css">
table{font-size: 3px; border-collapse:collapse;float:left; margin: 5px}
td.tw{border-top:2px solid black}
td.bw{border-bottom:2px solid black}
td.lw{border-left:2px solid black}
td.rw{border-right:2px solid black}
td.r{background-color: red;}
td{width:5px; height:5px;}
</style>';
    return $style;
  }
}
  $maze = new Maze(25, 25);
  echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'."\n";
  echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
  echo '<head>'."\n";
  echo '<title>Maze generator</title>'."\n";
  echo $maze->getStyle();
  echo '</head>'."\n";
  echo '<body>'."\n";
  echo $maze->render();
  echo '</body>'."\n";
  echo '</html>'."\n";
?>