I created script that generates maze or some kind of dungeons that looks like this: http://s13.postimage.org/4uify3jxj/blocks.jpg
I have problem with optimize, because when I've tried to add blockade to not overwrite existing blocks, script is executing most of times more than 60s.
So... any ideas how can I optimize this?
<?php
class dungeon_block {
public $left='EMPTY', $right='EMPTY', $top='EMPTY', $bottom='EMPTY', $visited=false, $action='NONE';
public $x, $y;
public function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
}
function rollDirection()
{
$direction = rand(0,3);
$dir = '';
switch($direction)
{
case 0: $dir = 'LEFT'; break;
case 1: $dir = 'RIGHT'; break;
case 2: $dir = 'TOP'; break;
case 3: $dir = 'BOTTOM'; break;
}
return $dir;
}
?>
<div class='dungeon'>
<?php
$count = rand(1,10);
$count = 20;
$index = 0;
$blocks = array();
$blocks[$index] = new dungeon_block(0,0);
$blocks[$index]->left = "BLOCKED";
$blocks[$index]->top = "BLOCKED";
$xy = array(array());
$dirOK = false;
$width = 25; $height = 25;
$x; $y;
echo "<div class='dungeon_block' style='top: ".$blocks[$index]->y."; left: ".$blocks[$index]->x."' id='block-".$index."'>S</div>";
$xy[0][0] = true;
while($count >=1 )
{
while($dirOK == false)
{
$dir = strtolower(rollDirection());
if($blocks[$index]->$dir == 'EMPTY')
{
$x = $blocks[$index]->x;
$y = $blocks[$index]->y;
$br = '';
$left='EMPTY';
$right='EMPTY';
$top='EMPTY';
$bottom='EMPTY';
switch($dir)
{
case 'left': $x -= $width; $right = 'BLOCKED';break;
case 'right': $x += $width; $left = 'BLOCKED';break;
case 'top': $y -= $height; $bottom = 'BLOCKED';break;
case 'bottom': $y += $height; $top = 'BLOCKED'; $br = '<br />'; break;
}
$i = 1;
if($x < 0 || $y < 0) {
if($i > 5) $dirOK = true;
$i++;
continue;
}
$i = 1;
if(array_key_exists($x, $xy)) {
if(array_key_exists($y, $xy[$x])) {
if($i > 15) $dirOK = true;
$i++;
continue;
}
}
$dirOK = true;
}
}
$index++;
echo "<div style='top: ".(int)$y."px; left: ".(int)$x."px;' class='dungeon_block' id='block-".$index."' >". $dir[0] ."</div>";
$blocks[$index] = new dungeon_block($x, $y);
$blocks[$index]->left = $left;
$blocks[$index]->right = $right;
$blocks[$index]->bottom = $bottom;
$blocks[$index]->top = $top;
$xy[$x][$y] = true;
$dirOK = false;
$count--;
}
?>
</div>
Edited code:
<?php
function rollDirection()
{
$direction = rand(0,3);
$directions = array(
'left',
'right',
'top',
'bottom'
);
return $directions[$direction];
}
function drawBlock($b)
{
echo "<div class='dungeon_block' style='top: ". $b['y'] ."px; left: ". $b['x']."px;' id='block-". $b['index'] ."'>".$b['text']."</div>";
}
?>
<div class='dungeon'>
<?php
$count = 10;
$length = 25;
$blocks = array();
$blocks[0] = array(
'text' => 'S', // for tests
'index' => 0,
'x' => 0,
'y' => 0
);
drawBlock($blocks[0]); // set start block
for($i=0; $i < $count; $i++) // draw others
{
$x = $blocks[$i]['x']; // get x from the previous block
$y = $blocks[$i]['y']; // get y from the previous block
$dir = rollDirection();
switch($dir)
{
case 'left': $x -= $length; break;
case 'right': $x += $length; break;
case 'top': $y -= $length; break;
case 'bottom': $y += $length; break;
}
$x = (int)$x;
$y = (int)$y;
// check if x or y are less than 0 - that is forbidden
// if so, repeat roll for that block
if($x < 0 || $y < 0) {
$i--;
continue;
}
$blocks[$i+1] = array(
'text' => $i.$dir[0], // for tests
'index' => $i,
'x' => $x,
'y' => $y
);
drawBlock($blocks[$i+1]);
}
?>
</div>
I have to think out this problems too: a) Blocks cannot overwrite themselves. (For example x=0 y=0 and 15 blocks laters, again x=0 y=0, so first blocks won't be visible). I have written this function:
function checkIsSpotFree($x, $y, $blocks, $length) // checks if spots is free and returns nearset free direction, if exist
{
$neighbours = array(
'left' => array('free' => true,
'x' => $x -= $length,
'y' => $y
),
'right' => array('free' => true,
'x' => $x += $length,
'y' => $y
),
'top' => array('free' => true,
'x' => $x,
'y' => $y -= $length
),
'bottom' => array('free' => true,
'x' => $x,
'y' => $y += $length
),
'center' => array('free' => true,
'x' => $x,
'y' => $y
)
);
foreach($blocks as $block)
{
if($neighbours['left']['x'] == $block['x'] && $neighbours['left']['y'] == $block['y'])
$neighbours['left']['free'] = false;
if($neighbours['right']['x'] == $block['x'] && $neighbours['right']['y'] == $block['y'])
$neighbours['right']['free'] = false;
if($neighbours['top']['x'] == $block['x'] && $neighbours['top']['y'] == $block['y'])
$neighbours['top']['free'] = false;
if($neighbours['bottom']['x'] == $block['x'] && $neighbours['bottom']['y'] == $block['y'])
$neighbours['bottom']['free'] = false;
if($neighbours['center']['x'] == $block['x'] && $neighbours['center']['y'] == $block['y'])
$neighbours['center']['free'] = false;
}
$free_spot = null; // declare nav to next free spot, default null
foreach($neighbours as $d)
{
if($d['free'] == true && $d['x'] >= 0 && $d['y'] >= 0)
{
$free_spot = $d;
break;
}
}
return $free_spot;
}
but there is still problem. If will be this situation ("B" refers to block, "X" proposal position):
X
->
BX
->
BBX
->
BBB
X
->
BBB
B
X
->
BBB
B
BX
->
BBB
B
BBX
->
BBB
B X
BBB
->
BBB
BXB
BBB
->
BBB
BXB
BBB
X = ?
There is no possible direction for new block, because it is surrounded by existings blocks. Than script runs into wall and endless loop. Any ideas how can I resolve this?