Generate random grid map

I’m trying to make a random grid map. It works already fine but:

#1. The last corner has always a “door” at the top and the left
#2. Dead end fields may never be “green”
#3. Not allowed to walk in cirlcles

My code as far I got

<?php

// Start Sessie
session_start();

// Map settings
$mapWidth		= 4;
$mapHeight		= 4;
$squareSize 	= 150;
$squareColor	= '#0f0';
$chestColor		= '#fc0';
$monsterColor	= '#f00';
$startColor		= '#0ff';
$exitColor		= '#369';

// Make SVG files
$svg[0] = '';
$svg[1] = '<rect width="10%" height="20%" x="90%" y="40%" />';
$svg[2] = '<rect width="20%" height="10%" x="40%" y="90%" />';
$svg[3] = $svg[1].$svg[2];
$svg[4] = '<rect width="10%" height="20%" x="0" y="40%" />';
$svg[5] = $svg[1].$svg[4];
$svg[6] = $svg[2].$svg[4];
$svg[7] = $svg[1].$svg[2].$svg[4];
$svg[8] = '<rect width="20%" height="10%" x="40%" y="0%" />';
$svg[9] = $svg[1].$svg[8];
$svg[10] = $svg[2].$svg[8];
$svg[11] = $svg[1].$svg[2].$svg[8];
$svg[12] = $svg[4].$svg[8];
$svg[13] = $svg[1].$svg[4].$svg[8];
$svg[14] = $svg[2].$svg[4].$svg[8];
$svg[15] = $svg[1].$svg[2].$svg[4].$svg[8];

// Function to count the values
function count_values($arr)
{
	$counting = 0;
	foreach ($arr as $key => $val)
	{
		$counting = $counting + $val;
	}
	return $counting;
}

// Calculate Monsters
$monsters = ceil($mapHeight * $mapWidth * 0.15);

// Calculate Chests
$chests = floor($mapHeight * $mapWidth * 0.25);

// Calculate Empty Squares
$empty = ($mapHeight * $mapWidth) - $monsters - $chests;

// Create Square Colors
$chests		= array_fill(1, $chests, $chestColor);
$monsters	= array_fill(1, $monsters, $monsterColor);
$squares	= array_fill(1, $empty, $squareColor);

// Set start and exit
$squares[1]	= $startColor;
$squares[2]	= $exitColor;

// Merge and mix all squares
$colorSquare = array_merge($chests, $monsters, $squares);
shuffle($colorSquare);

// Create squares
$squareNumber = 0;
for ($row=1; $row<=$mapWidth; $row++)
{
	for ($col=1; $col<=$mapHeight; $col++)
	{
		// Random
		$minUp		= 0;
		$minRight	= 0;
		$minBottom	= 0;
		$minLeft	= 0;
		$maxUp		= 1;
		$maxRight	= 1;
		$maxBottom	= 1;
		$maxLeft	= 1;
		$minimum	= 0;

		if ($row == 1){ $maxUp = 0; }
		if ($row == $mapWidth){ $maxBottom = 0; }
		if ($col == 1){ $maxLeft = 0; }
		if ($col == $mapHeight){ $maxRight = 0; }

		$setSquare[$row][$col] = array();

		$setSquare[($row - 1)][$col] = isset($setSquare[($row - 1)][$col]) ? $setSquare[($row - 1)][$col] : NULL;
		$setSquare[$row][($col - 1)] = isset($setSquare[$row][($col - 1)]) ? $setSquare[$row][($col - 1)] : NULL;

		if ($setSquare[($row - 1)][$col] != NULL)
		{
			$minUp = $setSquare[($row - 1)][$col]['bottom'];
			$maxUp = $setSquare[($row - 1)][$col]['bottom'];
		}

		if ($setSquare[$row][($col - 1)] != NULL)
		{
			$minLeft = $setSquare[$row][($col - 1)]['right'];
			$maxLeft = $setSquare[$row][($col - 1)]['right'];
		}

		$maxCount = 0; // Prevent get stuck
		$minimum = $minUp + $minLeft;
		while (count_values($setSquare[$row][$col]) <= $minimum && $maxCount < 20)
		{
			$setSquare[$row][$col]['up']		= rand($minUp, $maxUp);
			$setSquare[$row][$col]['right']		= rand($minRight, $maxRight);
			$setSquare[$row][$col]['bottom']	= rand($minBottom, $maxBottom);
			$setSquare[$row][$col]['left']		= rand($minLeft, $maxLeft);
			$maxCount++;
		}
		$imageDec = bindec($setSquare[$row][$col]['up'].$setSquare[$row][$col]['left'].$setSquare[$row][$col]['bottom'].$setSquare[$row][$col]['right']);
		print '<svg width="'.$squareSize.'px" height="'.$squareSize.'px" fill="'.$colorSquare[$squareNumber].'" xmlns="http://www.w3.org/2000/svg"><rect width="80%" height="80%" x="10%" y="10%" rx="5%" ry="5%" />'.$svg[$imageDec].'</svg>';
		$squareNumber++;
	}
	print '<br>';
}

?>

This is because by the time you get to the right column, the logic puts a ‘door’ on each up and down possibility and by the time you get to the bottom row, the logic puts a ‘door’ on each left and right possibility. Every square in the right column is connected up and down, and every square in the bottom row is connected left and right. I didn’t work out exactly why this is happening, but it is due to the rand() statements becoming rand(1,1) which always produces a 1.

I’ll get to how I think I would try to solve this later.

To solve this, you would need to detect if a green square has only one ‘door’.

To detect this, you would need to store the results, then scan through every path and detect if you pass through the same square again. I cannot think how to perform this scanning off of the top of my head.

BTW - some of the mapWidth and mapHeight values are being used in reverse. The rows go from 1 to the mapHeight and the columns go from 1 to the mapWidth. The only reason the code works now is because mapWidth and mapHeight are the same number.

Here’s how I think (untested) I would do this. Instead of generating random ‘doors’ for a square, I would generate a random number 0-15 for a square, converted to binary, this will give you a 0000-1111 value for the square. If the square is on an outside edge, convert any 1’s that are not permitted for that position into zeros. If the square has a left or an up neighbor, with a matching door, set the correct bit to a 1 to match those door(s). If the result has no ‘doors’, regenerate the random number, and loop. After successfully generating a random number for the square, if the square is green and it only has one ‘door’, regenerate the random number, and loop. You would store the resulting random number for each square, which would be used when comparing with later squares and to get the correct entry in the $svg array for the visual output.

You would only produce the visual output after you have successfully generated the random numbers for all the squares.

Thanks for your reply, after a good night I see there is a lot more mistakes.
I made complete new (with new errors of course)
#1. Sill possible to walk in circles (blue cirlce in image)
#2. Broken paths (red lines in image)
broken-path-walking-circles

<?php

// Start Sessie
session_start();

// Map settings
$mapWidth		= 5;
$mapHeight		= 5;
$squareSize 	= 70;
$squareColor	= '#333';

// Content settings
$monster		= '&#129430;';
$treasure		= '&#127873;';
$start			= '&#128578;';
$exit			= '&#128274;';

// Make SVG files
$fontSize = $squareSize * 2;
$svg['center']	= '<rect width="80%" height="80%" x="10%" y="10%" rx="5%" ry="5%" />';
$svg['right']	= '<rect width="10%" height="20%" x="90%" y="40%" />';
$svg['bottom']	= '<rect width="20%" height="10%" x="40%" y="90%" />';
$svg['left']	= '<rect width="10%" height="20%" x="0" y="40%" />';
$svg['top']		= '<rect width="20%" height="10%" x="40%" y="0%" />';

// Function to count the values in a field
function count_values($arr)
{
	$counting = 0;
	foreach ($arr as $key => $val)
	{
		if (is_numeric($val))
		{
			$counting = $counting + $val;
		}
	}
	return $counting;
}

// Calculate Monsters
$monsters = ceil($mapHeight * $mapWidth * 0.16);

// Calculate Chests
$chests = floor($mapHeight * $mapWidth * 0.24);

// Check map size
if ($monsters == 0 || $chests == 0 || ($monsters + $chests + 2) > ($mapHeight * $mapWidth))
{
	print 'Please change your mapsize';
	exit;
}

// Create content
$squareChests	= array_fill(1, $chests, 'treasure');
$squareMonsters	= array_fill(1, $monsters, 'monster');
$squareStart	= array(1 => 'start');
$squareEnd		= array(1 => 'exit');

// Merge and mix all content
$fillbox = array_merge($squareChests, $squareMonsters, $squareStart, $squareEnd);
shuffle($fillbox);

/******************************\
	Start Grid Map
\******************************/
// Build column
for ($row=1; $row<=$mapHeight; $row++)
{
	// Build row
	for ($col=1; $col<=$mapWidth; $col++)
	{
		// Default settings
		$squareMaxTop		= 1;
		$squareMaxLeft		= 1;
		$squareMaxBottom	= 1;
		$squareMaxRight		= 1;

		// Top row has never a door at top
		if ($row == 1){ $squareMaxTop = 0; }
		// First column has never a door at left
		if ($col == 1){ $squareMaxLeft = 0; }
		// Last row has never a door at the bottom
		if ($row == $mapHeight){ $squareMaxBottom = 0; }
		// Last column has never a door at the right
		if ($col == $mapWidth){ $squareMaxRight = 0; }

		// Create random square with at least 1 door
		$randomSquare = array();
		while (count_values($randomSquare) < 1)
		{
			$randomSquare = array(
				'top'		=> rand(0, $squareMaxTop),
				'right'		=> rand(0, $squareMaxRight),
				'bottom'	=> rand(0, $squareMaxBottom),
				'left'		=> rand(0, $squareMaxLeft),
			);
		}
		$field[$row][$col] = $randomSquare;
	}
}

/******************************\
	Check each field = connected
\******************************/
foreach ($field as $row => $colArr)
{
	foreach ($colArr as $col => $door)
	{
		// Check top door is connected with previous top field
		$previousTop = $row - 1;
		$field[$previousTop][$col] = isset($field[$previousTop][$col]) ? $field[$previousTop][$col] : NULL;
		if ($field[$previousTop][$col] != NULL)
		{
			$field[$row][$col]['top'] = $field[$previousTop][$col]['bottom'];
			if (count_values($field[$row][$col]) < 1)
			{
				$field[$row][$col]['top'] = 1;
				$field[$previousTop][$col]['bottom'] = 1;
			}
		} else {
			unset($field[$previousTop]);
		}

		// Check right door is connected with next right field
		$nextRight = $col + 1;
		$field[$row][$nextRight] = isset($field[$row][$nextRight]) ? $field[$row][$nextRight] : NULL;
		if ($field[$row][$nextRight] != NULL)
		{
			$field[$row][$col]['right'] = $field[$row][$nextRight]['left'];
			if (count_values($field[$row][$col]) < 1)
			{
				$field[$row][$col]['right'] = 1;
				$field[$row][$nextRight]['left'] = 1;
			}
		} else {
			unset($field[$row][$nextRight]);
		}

		// Check bottom door is connected with next bottom field
		$nextBottom = $row + 1;
		$field[$nextBottom][$col] = isset($field[$nextBottom][$col]) ? $field[$nextBottom][$col] : NULL;
		if ($field[$nextBottom][$col] != NULL)
		{
			$field[$row][$col]['bottom'] = $field[$nextBottom][$col]['top'];
			if (count_values($field[$row][$col]) < 1)
			{
				$field[$row][$col]['bottom'] = 1;
				$field[$nextBottom][$col]['top'] = 1;
			}
		} else {
			unset($field[$nextBottom]);
		}

		// Check left door is connected with previous left field
		$previousLeft = $col - 1;
		$field[$row][$previousLeft] = isset($field[$row][$previousLeft]) ? $field[$row][$previousLeft] : NULL;
		if ($field[$row][$previousLeft] != NULL)
		{
			$field[$row][$col]['left'] = $field[$row][$previousLeft]['right'];
			if (count_values($field[$row][$col]) < 1)
			{
				$field[$row][$col]['left'] = 1;
				$field[$row][$previousLeft]['right'] = 1;
			}
		} else {
			unset($field[$row][$previousLeft]);
		}

		// Give dead end always a monster / treasure / Start or Exit
		if (count_values($field[$row][$col]) == 1 && count($fillbox) > 0)
		{
			$field[$row][$col]['content'] = $fillbox[0];
			array_shift($fillbox);
		} else {
			$field[$row][$col]['content'] = '';
		}
	}
}

/**************************************************\
	Check broken paths
	If broken path, add entry to random field in broken path
\**************************************************/
// How to do ?????

/**************************************************\
	Check walking circles
	If circle, remove one entry from random field in cicle path
\**************************************************/
// How to do ?????

// Set leftover content to random fields
while (count($fillbox) > 0)
{
	$x = rand(1, $mapHeight);
	$y = rand(1, $mapWidth);
	if ($field[$x][$y]['content'] == '')
	{
		$field[$x][$y]['content'] = $fillbox[0];
		array_shift($fillbox);
	}
}

/******************************\
	Show grid
\******************************/
foreach ($field as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		// Create and show image SVG
		$image = '<svg width="'.$squareSize.'px" height="'.$squareSize.'px" fill="'.$squareColor.'" xmlns="http://www.w3.org/2000/svg">'.PHP_EOL;
		$image .= '	'.$svg['center'].PHP_EOL; // Center square
		// The doors
		if ($colArr['top']		== 1) { $image .= '	'.$svg['top'].PHP_EOL; }
		if ($colArr['right']	== 1) { $image .= '	'.$svg['right'].PHP_EOL; }
		if ($colArr['bottom']	== 1) { $image .= '	'.$svg['bottom'].PHP_EOL; }
		if ($colArr['left']		== 1) { $image .= '	'.$svg['left'].PHP_EOL; }
		// The text (content)
		$text = '';
		if ($colArr['content'] == 'monster'){ $text = $monster; }
		if ($colArr['content'] == 'treasure'){ $text = $treasure; }
		if ($colArr['content'] == 'start'){ $text = $start; }
		if ($colArr['content'] == 'exit'){ $text = $exit; }
		$image .= '	<text x="50%" y="50% "textLength="100%" font-size="'.$fontSize.'%" dominant-baseline="middle" text-anchor="middle">'.$text.'</text>'.PHP_EOL;
		$image .= '</svg>'; // Close SVG

		print $image; // Show image
	}
	print '<br>'; // Next row
}

?>

I’ve made the code a little different and added a better view
The chance for broken path is lesser but still possible

<?php

// Grid settings
$gridWidth	= 3;
$gridHeight	= 4;
$svgSize	= 100;
$svgColor	= '#333';

// Images (Icons)
$iconExit		= '&#128274;'; // Shows a lock
$iconMonster	= '&#129430;'; // Shows a dinosaur
$iconStart		= '&#128578;'; // Shows a smiley
$iconTreasure	= '&#127873;'; // Shows a gift

// Calculate Monsters
$monsters = ceil($gridHeight * $gridWidth * 0.15);

// Calculate Treasures
$treasures = floor($gridHeight * $gridWidth * 0.25);

// Make iconBox and shuffleBox
$iconBox = array_merge(
	array_fill(1, $treasures, $iconTreasure),
	array(1 => $iconExit),
	array_fill(1, $monsters, $iconMonster),
	array(1 => $iconStart)
);
$shuffleBox = $iconBox;
shuffle($shuffleBox);

// Build the full grid with all information
$grid = array(
	'grid'			=> array_fill(1, $gridHeight, array_fill(1, $gridWidth, array(
		'binary'		=> '0000',
		'decimal'		=> 0,
		'doors'			=> array(
			'bottom'	=> 0,
			'left'		=> 0,
			'right'		=> 0,
			'top'		=> 0
	),
		'icon'			=> NULL,
		'svg'			=> NULL
	))),
	'icons'			=> array(
		'exit'			=> $iconExit,
		'monster'		=> $iconMonster,
		'treasure'		=> $iconTreasure,
		'start'			=> $iconStart
	),
	'iconBox'		=> array(
		'default'		=> $iconBox,
		'shuffle'		=> $shuffleBox
	),
	'information'	=> array(
		'emptyFields'	=> (($gridHeight * $gridWidth) - ($monsters + $treasures + 2)),
		'gridHeight'	=> $gridHeight,
		'gridWidth'		=> $gridWidth,
		'monsters'		=> $monsters,
		'svgColor'		=> $svgColor,
		'svgSize'		=> $svgSize,
		'treasures'		=> $treasures,
		'totalFields'	=> ($gridHeight * $gridWidth),
		'totalIcons'	=> count($iconBox)
	)
);

// Function to count the values in a field
function count_values($arr)
{
	$counting = 0;
	foreach ($arr as $key => $val)
	{
		if (is_numeric($val))
		{
			$counting = $counting + $val;
		}
	}
	return $counting;
}

// Build the fields
foreach ($grid['grid'] as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		// Default random settings
		$randomBottom	= 1;
		$randomLeft		= 1;
		$randomRight	= 1;
		$randomTop		= 1;

		// Last row has never a door at the bottom
		if ($rowKey == $grid['information']['gridHeight']){ $randomBottom = 0; }
		// First column has never a door at left
		if ($colKey == 1){ $randomLeft = 0; }
		// Last column has never a door at the right
		if ($colKey == $grid['information']['gridWidth']){ $randomRight = 0; }
		// Top row has never a door at top
		if ($rowKey == 1){ $randomTop = 0; }

		// Create random square with at least 1 door
		while (count_values($grid['grid'][$rowKey][$colKey]['doors']) < 1)
		{
			$grid['grid'][$rowKey][$colKey]['doors'] = array(
				'bottom'	=> rand(0, $randomBottom),
				'left'		=> rand(0, $randomLeft),
				'right'		=> rand(0, $randomRight),
				'top'		=> rand(0, $randomTop)
			);

			// Get previous top and left field
			$previousLeft	= $colKey - 1;
			$previousTop	= $rowKey - 1;

			// Check connection with top field
			if ($previousTop > 0)
			{
				if ($grid['grid'][$previousTop][$colKey]['doors']['bottom'] == 1)
				{
					$grid['grid'][$rowKey][$colKey]['doors']['top'] = 1;
				} else {
					$grid['grid'][$previousTop][$colKey]['doors']['bottom'] = $grid['grid'][$rowKey][$colKey]['doors']['top'];
				}
			}

			// Check connection with left field
			if ($previousLeft > 0)
			{
				if ($grid['grid'][$rowKey][$previousLeft]['doors']['right'] == 1)
				{
					$grid['grid'][$rowKey][$colKey]['doors']['left'] = 1;
				} else {
					$grid['grid'][$rowKey][$previousLeft]['doors']['right'] = $grid['grid'][$rowKey][$colKey]['doors']['left'];
				}
			}

			// Check broken path with top
			if ($previousTop > 0)
			{
				if (count_values($grid['grid'][$rowKey][$colKey]['doors']) == 1 && count_values($grid['grid'][$previousTop][$colKey]['doors']) == 1)
				{
					$grid['grid'][$rowKey][$colKey]['doors']['top'] = 0;
				}
			}

			// Check broken path with left
			if ($previousLeft > 0)
			{
				if (count_values($grid['grid'][$rowKey][$colKey]['doors']) == 1 && count_values($grid['grid'][$rowKey][$previousLeft]['doors']) == 1)
				{
					$grid['grid'][$rowKey][$colKey]['doors']['left'] = 0;
				}
			}

		}
	}
}

// Add some extra information
foreach ($grid['grid'] as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		// Make a binary
		$grid['grid'][$rowKey][$colKey]['binary'] = 
			$grid['grid'][$rowKey][$colKey]['doors']['top'].
			$grid['grid'][$rowKey][$colKey]['doors']['left'].
			$grid['grid'][$rowKey][$colKey]['doors']['bottom'].
			$grid['grid'][$rowKey][$colKey]['doors']['right'];

		// Convert binary to decimal
		$grid['grid'][$rowKey][$colKey]['decimal'] = bindec($grid['grid'][$rowKey][$colKey]['binary']);

		// Always fill dead ends with an icon
		if (count_values($grid['grid'][$rowKey][$colKey]['doors']) == 1 && count($shuffleBox) > 0)
		{
			// This add an icon to a dead end
			$grid['grid'][$rowKey][$colKey]['icon'] = $shuffleBox[0];
			array_shift($shuffleBox);
		}
	}
}

// Set leftover from shuffleBox to random fields
while (count($shuffleBox) > 0)
{
	$x = rand(1, $grid['information']['gridWidth']);
	$y = rand(1, $grid['information']['gridHeight']);
	if ($grid['grid'][$y][$x]['icon'] == NULL)
	{
		$grid['grid'][$y][$x]['icon'] = $shuffleBox[0];
		array_shift($shuffleBox);
	}
}

// Make SVG files
$svg['center']	= '<rect width="80%" height="80%" x="10%" y="10%" rx="5%" ry="5%" />'; // A simple square
$svg['right']	= '<rect width="10%" height="20%" x="90%" y="40%" />'; // Put a door (path) to the right side of the square
$svg['bottom']	= '<rect width="20%" height="10%" x="40%" y="90%" />'; // Put a door (path) to the bottom side of the square
$svg['left']	= '<rect width="10%" height="20%" x="0" y="40%" />'; // Put a door (path) to the left side of the square
$svg['top']		= '<rect width="20%" height="10%" x="40%" y="0%" />'; // Put a door (path) to the top side of the square

// Create SVG for each field
foreach ($grid['grid'] as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		$grid['grid'][$rowKey][$colKey]['svg'] = '<svg width="'.$grid['information']['svgSize'].'px" height="'.$grid['information']['svgSize'].'px" fill="'.$grid['information']['svgColor'].'" xmlns="http://www.w3.org/2000/svg">';
		$grid['grid'][$rowKey][$colKey]['svg'] .= $svg['center'];
		// The doors
		if ($grid['grid'][$rowKey][$colKey]['doors']['top']		== 1) { $grid['grid'][$rowKey][$colKey]['svg'] .= $svg['top']; }
		if ($grid['grid'][$rowKey][$colKey]['doors']['right']	== 1) { $grid['grid'][$rowKey][$colKey]['svg'] .= $svg['right']; }
		if ($grid['grid'][$rowKey][$colKey]['doors']['bottom']	== 1) { $grid['grid'][$rowKey][$colKey]['svg'] .= $svg['bottom']; }
		if ($grid['grid'][$rowKey][$colKey]['doors']['left']	== 1) { $grid['grid'][$rowKey][$colKey]['svg'] .= $svg['left']; }
		// Add icon
		if ($grid['grid'][$rowKey][$colKey]['icon'] != NULL)
		{
			$grid['grid'][$rowKey][$colKey]['svg'] .= '<text x="50%" y="50%" textLength="100%" font-size="'.($grid['information']['svgSize'] * 2).'%" dominant-baseline="middle" text-anchor="middle">'.$grid['grid'][$rowKey][$colKey]['icon'].'</text>';
		}
		// Close SVG
		$grid['grid'][$rowKey][$colKey]['svg'] .= '</svg>';
	}
}

// Make information block
$information = '';
foreach($grid['information'] as $key => $content)
{
	$information .= '	<tr>
		<td>'.$key.'</td>
		<td>'.$content.'</td>
	</tr>';
}

$icons = '';
foreach($grid['icons'] as $key => $content)
{
	$icons .= '	<tr>
		<td>'.$key.'</td>
		<td>'.$content.'</td>
	</tr>'.PHP_EOL;
}

// Create image and table
$image = '';
$table = '';
foreach ($grid['grid'] as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		$image .= $colArr['svg'].PHP_EOL;
		$table .= '		<tr>
			<td>'.$rowKey.'</td>
			<td>'.$colKey.'</td>
			<td>'.$colArr['doors']['right'].'</td>
			<td>'.$colArr['doors']['bottom'].'</td>
			<td>'.$colArr['doors']['left'].'</td>
			<td>'.$colArr['doors']['top'].'</td>
			<td>'.$colArr['icon'].'</td>
			<td>'.$colArr['binary'].'</td>
			<td>'.$colArr['decimal'].'</td>
			<td>'.$colArr['svg'].'</td>
		</tr>'.PHP_EOL;
	}
}

/**************************************************\
	Just a simple HTML + CSS for a better view
	Don't look at the source code, it's not valid
	It's made very quick
\**************************************************/
print '<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Random Grid Map</title>
<style type="text/css">
html
{
	background: none #fff;
	display: block;
	height: 100%;
	margin: 0 0 0 0;
	overflow: hidden;
	padding: 0 0 0 0;
	position: relative;
	width: 100%;
}

body
{
	display: grid;
	font-family: "Verdana";
	font-size: 1em;
	font-weight: 100;
	grid-column-gap: 0;
	grid-row-gap: 0;
	grid-template-areas:
		"header header"
		"svg information"
		"svg table"
		"footer footer";
	grid-template-columns: 1fr 1fr;
	grid-template-rows: auto auto 1fr auto;
	height: 100%;
	margin: 0 0 0 0;
	overflow: hidden;
	padding: 0 0 0 0;
	width: 100%;
}

h1
{
	border-bottom: solid 1px #000;
	font-size: 3em;
	grid-area: header;
	margin: 0 0 0.5em 0;
	padding: 0 0 0.2em 0;
	text-align: center;
}

div.rgm
{
	background: none #369;
	display: inline-block;
	grid-area: svg;
	margin: 0 auto 0 auto;
	overflow: auto;
	padding: 0.5em 0.5em 0.5em 0.5em;
}

div.rgm svg
{
	background: none transparent;
	float: left;
	margin: 0 0 0 0;
	padding: 0 0 0 0;
}

div.rgm svg:nth-child('.$grid['information']['gridWidth'].'n+1)
{
	clear: left;
}

div.information
{
	grid-area: information;
	overflow: auto;
}

div.information table
{
	border: solid 1px #000;
	border-spacing: 0;
	border-collapse: separate;
	float:left;
	margin: 0 1em 0 1em;
}

div.information table tr td
{
	margin: 0 0 0 0;
	padding: 0.2em 0.2em 0.2em 0.2em;
	vertical-align: middle;
}

div.information table tr td[colspan="2"]
{
	font-weight: 900;
	text-align: center;
}

div.information table tr:nth-child(odd) td
{
	background-color: #fff;
}

div.information table tr:nth-child(even) td
{
	background-color: #ddd;
}

div.table
{
	grid-area: table;
	margin: 1em 0 0 0;
	overflow: auto;
}

div.table table
{
	border: none 0 transparent;
	border-spacing: 0;
	border-collapse: separate;
}

div.table table thead tr th
{
	background: none #fff;
	border-bottom: solid 1px #000;
	margin: 0 0 0 0;
	padding: 0.2em 0.3em 0.2em 0.3em;
	position: sticky;
	top: 0;
}

div.table table tbody td
{
	margin: 0 0 0 0;
	padding: 0.5em 0 0.5em 0;
	text-align: center;
}

footer
{
	border-top: solid 1px #000;
	grid-area: footer;
	margin: 0 0 0 0;
	padding: 0 0 0 0;
}

footer p
{
	margin: 0 0 0 0;
	padding: 0.5em 0 0.5em 0;
	text-align: center;
}
</style>
</head>

<body>
<h1>Random Grid Map</h1>
<div class="rgm">
'.$image.'</div>
<div class="information">
<table>
	<tr>
		<td colspan="2">Information</td>
	</tr>
'.$information.'
</table>
<table>
	<tr>
		<td colspan="2">Icons</td>
	</tr>
'.$icons.'
</table>
</div>
<div class="table">
<table>
	<thead>
		<tr>
			<th>Row</th>
			<th>Column</th>
			<th>Right Door</th>
			<th>Bottom Door</th>
			<th>Left Door</th>
			<th>Top Door</th>
			<th>Icon</th>
			<th>Binary</th>
			<th>Decimal</th>
			<th>SVG</th>
		</tr>
	</thead>
	<tbody>
'.$table.'	</tbody>
</table>
</div>
<footer>
	<p><a href="'.$_SERVER['PHP_SELF'].'">Click here to refresh the page and make a new Random Grid Map</a> or press "F5" on your keyboard</p>
</footer>
</body>
</html>';

?>

I fixed the “Broken Path” source
New in this update:
You can set the setWrong to true or false
When false it will build a random grid, when true it will show a selfmade wrong grid to show better where to fix the broken paths. If you refresh the page you will see the doors will be random added when a path is broken.

<?php

// Start a new session
session_start();

/**************************************************\
	Settings
\**************************************************/
// Grid settings
$gridWidth	= 6;
$gridHeight	= 7;
$svgSize	= 50;
$svgColor	= '#333';
$setWrong	= true;

/**************************************************\
	Functions
\**************************************************/
// Function to count the values in a field
function count_values($arr)
{
	$counting = 0;
	foreach ($arr as $key => $val)
	{
		if (is_numeric($val))
		{
			$counting = $counting + $val;
		}
	}
	return $counting;
}

// Function to show the grid on screen
function viewGrid($thisGrid = array(), $thisSize = 50)
{
// SVG
	$svg = array(
		'center'	=> '<rect width="80%" height="80%" x="10%" y="10%" rx="5%" ry="5%" />',
		'top'		=> '<rect width="20%" height="10%" x="40%" y="0%" />',
		'right'		=> '<rect width="10%" height="20%" x="90%" y="40%" />',
		'bottom'	=> '<rect width="20%" height="100%" x="40%" y="90%" />',
		'left'		=> '<rect width="10%" height="20%" x="0%" y="40%" />',
		'start'		=> '<text x="50%" y="50% "textLength="100%" font-size="'.($thisSize * 2).'%" dominant-baseline="middle" text-anchor="middle">&#128578;</text>',
		'exit'		=> '<text x="50%" y="50% "textLength="100%" font-size="'.($thisSize * 2).'%" dominant-baseline="middle" text-anchor="middle">&#128274;</text>',
		'monster'	=> '<text x="50%" y="50% "textLength="100%" font-size="'.($thisSize * 2).'%" dominant-baseline="middle" text-anchor="middle">&#129430;</text>',
		'treasure'	=> '<text x="50%" y="50% "textLength="100%" font-size="'.($thisSize * 2).'%" dominant-baseline="middle" text-anchor="middle">&#127873;</text>',
	);

	foreach ($thisGrid as $rowKey => $rowArr)
	{
		foreach ($rowArr as $colKey => $colArr)
		{
			$thisColor = $colArr['color'];
			// Create and show image SVG
			$image = '<svg width="'.$thisSize.'px" height="'.$thisSize.'px" fill="'.$thisColor.'" xmlns="http://www.w3.org/2000/svg">';
			$image .= $svg['center']; // Center square
			// The doors
			if ($colArr['doors']['top']		== 1) { $image .= $svg['top']; }
			if ($colArr['doors']['right']	== 1) { $image .= $svg['right']; }
			if ($colArr['doors']['bottom']	== 1) { $image .= $svg['bottom']; }
			if ($colArr['doors']['left']	== 1) { $image .= $svg['left']; }
			if ($thisGrid[$rowKey][$colKey]['content'] != NULL)
			{
				$image .= $svg[$thisGrid[$rowKey][$colKey]['content']];
			}
			$image .= '</svg>'; // Close SVG

			print $image; // Show image
		}
		print '<br>'.PHP_EOL; // Next row
	}
}

/**************************************************\
	Grid building
\**************************************************/
// Build an empty grid
$grid = array_fill(1, $gridHeight, array_fill(1, $gridWidth, array(
	'doors'			=> array(
		'bottom'	=> 0,
		'left'		=> 0,
		'right'		=> 0,
		'top'		=> 0
	),
	'color'			=> $svgColor,
	'content'		=> NULL,
	'check'			=> NULL
)));

// Fill empty grid with random fields
foreach ($grid as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		// Default random doors
		$randomTop = 1;
		$randomRight = 1;
		$randomBottom = 1;
		$randomLeft = 1;

		// Borders can never have a door
		if ($rowKey == 1) { $randomTop = 0; }
		if ($rowKey == $gridHeight) { $randomBottom = 0; }
		if ($colKey == 1) { $randomLeft = 0; }
		if ($colKey == $gridWidth) { $randomRight = 0; }

		// Set random doors
		while (count_values($grid[$rowKey][$colKey]['doors']) == 0)
		{
			$grid[$rowKey][$colKey]['doors']['top'] = rand(0, $randomTop);
			$grid[$rowKey][$colKey]['doors']['right'] = rand(0, $randomRight);
			$grid[$rowKey][$colKey]['doors']['bottom'] = rand(0, $randomBottom);
			$grid[$rowKey][$colKey]['doors']['left'] = rand(0, $randomLeft);
		}
	}
}

// Get a wrong grid
if ($setWrong == true)
{
	unset($grid);

	// Create a broken grid to check
	$wrongGrid[1][1]['doors'] = array(
		'top' => 0,
		'right' => 0,
		'bottom' => 1,
		'left' => 0,
	);

	$wrongGrid[1][2]['doors'] = array(
		'top' => 0,
		'right' => 1,
		'bottom' => 0,
		'left' => 0,
	);

	$wrongGrid[1][3]['doors'] = array(
		'top' => 0,
		'right' => 0,
		'bottom' => 0,
		'left' => 1,
	);

	$wrongGrid[2][1]['doors'] = array(
		'top' => 0,
		'right' => 1,
		'bottom' => 0,
		'left' => 0,
	);

	$wrongGrid[2][2]['doors'] = array(
		'top' => 0,
		'right' => 0,
		'bottom' => 0,
		'left' => 1,
	);

	$wrongGrid[2][3]['doors'] = array(
		'top' => 0,
		'right' => 0,
		'bottom' => 1,
		'left' => 0,
	);

	$wrongGrid[3][1]['doors'] = array(
		'top' => 0,
		'right' => 1,
		'bottom' => 0,
		'left' => 0,
	);

	$wrongGrid[3][2]['doors'] = array(
		'top' => 0,
		'right' => 0,
		'bottom' => 0,
		'left' => 1,
	);

	$wrongGrid[3][3]['doors'] = array(
		'top' => 1,
		'right' => 0,
		'bottom' => 0,
		'left' => 0,
	);

	// Set new width en height
	$gridHeight	= count($wrongGrid);
	$gridWidth	= count($wrongGrid[$gridHeight]);

	foreach ($wrongGrid as $rowKey => $rowArr)
	{
		foreach ($rowArr as $colKey => $colArr)
		{
			$grid[$rowKey][$colKey]['doors'] = $colArr['doors'];
			$grid[$rowKey][$colKey]['color'] = '#300';
			$grid[$rowKey][$colKey]['content'] = NULL;
			$grid[$rowKey][$colKey]['check'] = NULL;
		}
	}
	print 'Fill Grid with wrong grid<br>';
} else {
	print 'Fill Grid with random doors<br>';
}

viewGrid($grid, $svgSize);

// Connect all doors
foreach ($grid as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		if ($grid[$rowKey][$colKey]['doors']['top'] == 1)
		{
			$grid[$rowKey][$colKey]['doors']['top'] = 1;
			$grid[($rowKey - 1)][$colKey]['doors']['bottom'] = 1;
		}

		if ($grid[$rowKey][$colKey]['doors']['right'] == 1)
		{
			$grid[$rowKey][$colKey]['doors']['right'] = 1;
			$grid[$rowKey][($colKey + 1)]['doors']['left'] = 1;
		}

		if ($grid[$rowKey][$colKey]['doors']['bottom'] == 1)
		{
			$grid[$rowKey][$colKey]['doors']['bottom'] = 1;
			$grid[($rowKey + 1)][$colKey]['doors']['top'] = 1;
		}

		if ($grid[$rowKey][$colKey]['doors']['left'] == 1)
		{
			$grid[$rowKey][$colKey]['doors']['left'] = 1;
			$grid[$rowKey][($colKey - 1)]['doors']['right'] = 1;
		}
	}
}
print 'Show grid with all connected doors<br>';
viewGrid($grid, $svgSize);

// Check broken path
foreach ($grid as $rowKey => $rowArr)
{
	foreach ($rowArr as $colKey => $colArr)
	{
		// Set Keys
		$oldRow = $rowKey;
		$oldCol = $colKey;
		$newRow = $rowKey;
		$newCol = $colKey;
		// Set check grid
		$checkGrid = $grid;
		// Fall back by dead end
		$fallBack = array();
		// Start walking
		if ($colKey == $gridWidth && $rowKey == $gridHeight)
		{
			$grid[$rowKey][$colKey]['check'] = 1;
			$keepGoing = false;
		} elseif ($grid[$rowKey][$colKey]['check'] == 1)
		{
			$keepGoing = false;
		} else {
			$grid[$rowKey][$colKey]['check'] = '1';
			$keepGoing = true;
			// Remember walking
			$rememberWalking = array();
		}
		// Start check
		while ($keepGoing === true)
		{
			// Remember Walking Path
			$addPath = array(
				'row' => $newRow,
				'col' => $newCol
			);
			$rememberWalking[count($rememberWalking)] = $addPath;
			// Set Fall Back
			if (count_values($checkGrid[$newRow][$newCol]['doors']) > 1)
			{
				$rememberPosition = array(
					'row' => $oldRow,
					'col' => $oldCol
				);
				$fallBack[] = $rememberPosition;
			}

			// Go to next field
			if ($checkGrid[$newRow][$newCol]['doors']['right'] == 1)
			{
				$newCol++;
				$checkGrid[$oldRow][$oldCol]['doors']['right'] = 0;
				$checkGrid[$newRow][$newCol]['doors']['left'] = 0;
			} elseif ($checkGrid[$newRow][$newCol]['doors']['bottom'] == 1)
			{
				$newRow++;
				$checkGrid[$oldRow][$oldCol]['doors']['bottom'] = 0;
				$checkGrid[$newRow][$newCol]['doors']['top'] = 0;
			} elseif ($checkGrid[$newRow][$newCol]['doors']['left'] == 1)
			{
				$newCol--;
				$checkGrid[$oldRow][$oldCol]['doors']['left'] = 0;
				$checkGrid[$newRow][$newCol]['doors']['right'] = 0;
			} elseif ($checkGrid[$newRow][$newCol]['doors']['top'] == 1)
			{
				$newRow--;
				$checkGrid[$oldRow][$oldCol]['doors']['top'] = 0;
				$checkGrid[$newRow][$newCol]['doors']['bottom'] = 0;
			} elseif (count($fallBack) > 0)
			{
				$lastPosition = end($fallBack);
				array_pop($fallBack);
				$newRow = $lastPosition['row'];
				$newCol = $lastPosition['col'];
				$grid[$newRow][$newCol]['check'] = 0;
			} else {
				// Broken Path Found
				$lastRow = 0;
				$lastCol = 0;
				foreach ($rememberWalking as $color)
				{
					if ($color['row'] > $lastRow)
					{
						$lastRow = $color['row'];
						$lastCol = $color['col'];
					} elseif ($color['col'] > $lastCol)
					{
						$lastCol = $color['col'];
					}
				}
				$directions = array('top', 'right', 'bottom', 'left');
				if ($lastRow == 1 || $grid[$lastRow][$lastCol]['doors']['top'] == 1)
				{
					$key = array_search('top', $directions);
					unset($directions[$key]);
				}
				if ($lastCol == 1 || $grid[$lastRow][$lastCol]['doors']['left'] == 1)
				{
					$key = array_search('left', $directions);
					unset($directions[$key]);
				}
				if ($lastRow == $gridHeight || $grid[$lastRow][$lastCol]['doors']['bottom'] == 1)
				{
					$key = array_search('bottom', $directions);
					unset($directions[$key]);
				}
				if ($lastCol == $gridWidth || $grid[$lastRow][$lastCol]['doors']['right'] == 1)
				{
					$key = array_search('right', $directions);
					unset($directions[$key]);
				}
				shuffle($directions);
				$grid[$lastRow][$lastCol]['doors'][$directions[0]] = 1;
				$checkGrid[$lastRow][$lastCol]['doors'][$directions[0]] = 1;
				if ($directions[0] == 'top')
				{
					$grid[($lastRow - 1)][$lastCol]['doors']['bottom'] = 1;
					$checkGrid[($lastRow - 1)][$lastCol]['doors']['bottom'] = 1;
				} elseif ($directions[0] == 'bottom')
				{
					$grid[($lastRow + 1)][$lastCol]['doors']['top'] = 1;
					$checkGrid[($lastRow + 1)][$lastCol]['doors']['top'] = 1;
				} elseif ($directions[0] == 'left')
				{
					$grid[$lastRow][($lastCol - 1)]['doors']['right'] = 1;
					$checkGrid[$lastRow][($lastCol - 1)]['doors']['right'] = 1;
				} elseif ($directions[0] == 'right')
				{
					$grid[$lastRow][($lastCol + 1)]['doors']['left'] = 1;
					$checkGrid[$lastRow][($lastCol + 1)]['doors']['left'] = 1;
				}
				$grid[$newRow][$newCol]['check'] = 0;
				$newCol = $lastCol;
				$newRow = $lastRow;
				$grid[$newRow][$newCol]['check'] = 0;
			}





			if (($newCol == $gridWidth && $newRow == $gridHeight))
			{
				// Remember Walking Path
				$addPath = array(
					'row' => $newRow,
					'col' => $newCol
				);
				unset($rollBack);
				$keepGoing = false;
			} else {
				$grid[$newRow][$newCol]['check'] = 1;
				$oldCol = $newCol;
				$oldRow = $newRow;
			}

		}
	}
}

print 'Show new grid without broken paths.<br>';
viewGrid($grid);

?>

Sponsor our Newsletter | Privacy Policy | Terms of Service