Core JavaScript

Walkable Labyrinth

This JavaScript program shows how create a walkable labyrinth. Press the directions keys to move around the terrain.

GetJsonLabyrinth.html

<!DOCTYPE html>
<html>
	<head>
		<title>XoaX.net: PHP Labyrinth</title>
		<link rel="icon" href="data:,">
		<script language="javascript" type="text/javascript" src="ReadWalkLabyrinth.js"></script>
	</head>
	<body onload="Initialization()">
	</body>
</html>

ReadWalkLabyrinth.js

var gqView = null;
var gqController = null;

function Initialization() {
	gqView = new CView(800, 800);

	gqController = new CController();

	gqView.Refresh();
	
	document.onkeydown = KeyHandler;
}

function KeyHandler(qKeyEvent) {
	let iKeyDown = 0;
	let iLeftArrow = 37;
	let iUpArrow = 38;
	let iRightArrow = 39;
	let iDownArrow = 40;
	
	if (qKeyEvent) {
		iKeyDown = qKeyEvent.which;
	} else {
		iKeyDown = window.event.keyCode;
	}

	if (iKeyDown === iLeftArrow) {
		gqController.TurnLeft();
	} else if (iKeyDown === iRightArrow) {
		gqController.TurnRight();
	} else if (iKeyDown === iUpArrow) {
		gqController.Forward();
	} else if (iKeyDown === iDownArrow) {
		gqController.Backward();
	}
	return false;
}

class CController {
	constructor() {}
	#MoveRequest() {
		let qHttpRequest = new XMLHttpRequest();
		// Method, URL, Async
		qHttpRequest.open("POST", "Labyrinth.php", true);
		qHttpRequest.onload = function( e ) {
			gqView.Refresh();
		};
		return qHttpRequest; 
	}
	TurnLeft() {
		let qHttpRequest = this.#MoveRequest();
		qHttpRequest.send('{"iMove":1}');
	}
	TurnRight() {
		let qHttpRequest = this.#MoveRequest();
		qHttpRequest.send('{"iMove":3}');
	}
	Forward() {
		let qHttpRequest = this.#MoveRequest();
		qHttpRequest.send('{"iMove":2}');
	}
	Backward() {
		let qHttpRequest = this.#MoveRequest();
		qHttpRequest.send('{"iMove":4}');
	}
}

class CView {
	#mqGrid = null;
	constructor(iWidth, iHeight) {
		let qBody = document.body;
		let qGrid = document.createElement("div");
		qBody.appendChild(qGrid);
		qGrid.style.width = iWidth+"px";
		qGrid.style.height = iHeight+"px";
		qGrid.style.position = "absolute";
		this.#mqGrid = qGrid;
	}
	Refresh() {
		let qHttpRequest = new XMLHttpRequest();
		// Method, URL, Async
		qHttpRequest.open("GET", "Labyrinth.php", true);
		qHttpRequest.onload = function( e ) {
			let iaaGrid = JSON.parse(this.response);
			gqView.UpdateCells(iaaGrid);
		};
		qHttpRequest.send();
	}
	#AllocateNewGrid(iaaGrid) {
		// Remove any child nodes, if they exist.
		this.#mqGrid.replaceChildren();
		for (let iRow = 0; iRow < iaaGrid.length; ++iRow) {
			let qGridRow = this.#AllocteNewRow(iaaGrid.length, iRow);
			for (let iCol = 0; iCol < iaaGrid[iRow].length; ++iCol) {
				this.#AllocateNewCell(qGridRow, iaaGrid[iRow].length, iCol);
			}
		}
		this.UpdateCells(iaaGrid);
	}
	#AllocteNewRow(iGridRows, iRowIndex) {
		let qGridRow = document.createElement("div");
		this.#mqGrid.appendChild(qGridRow);
		let dRowPercent = 100/iGridRows;
		qGridRow.style.width = "100%";
		qGridRow.style.height = dRowPercent+"%";
		qGridRow.style.position = "absolute";
		qGridRow.style.top = dRowPercent*iRowIndex+"%";
		qGridRow.style.left = "0%";
		return qGridRow;
	}
	#AllocateNewCell(qGridRow, iGridCols, iCellIndex, iCellValue) {
		let qGridCell = document.createElement("div");
		qGridRow.appendChild(qGridCell);
		let dColPercent = 100/iGridCols;
		qGridCell.style.color = "black";
		qGridCell.style.width = dColPercent+"%";
		qGridCell.style.height = "100%";
		qGridCell.style.position = "absolute";
		qGridCell.style.top = "0%";
		qGridCell.style.left = dColPercent*iCellIndex+"%";
	}
	UpdateCells(iaaGrid) {
		// Verify that the grid has been allocated and is the correct size.
		let bReallocateCells = false;
		if (iaaGrid.length != this.#mqGrid.children.length) {
			bReallocateCells = true;
		} else {
			for (let iRow = 0; iRow < iaaGrid.length; ++iRow) {
				let qRow = this.#mqGrid.children[iRow];
				if (iaaGrid[iRow].length != qRow.children.length) {
					bReallocateCells = true;
					break;
				}
			}
		}
		if (bReallocateCells) {
			this.#AllocateNewGrid(iaaGrid);
		}
		for (let iRow = 0; iRow < iaaGrid.length; ++iRow) {
			for (let iCol = 0; iCol < iaaGrid[iRow].length; ++iCol) {
				this.#UpdateCell(iRow, iCol, iaaGrid[iRow][iCol]);
			}
		}
	}
	#UpdateCell(iRow, iCol, iCellValue) {
		let qRow = this.#mqGrid.children[iRow];
		let qCell = qRow.children[iCol];
		let iPosition = (iCellValue & 7);
		if (iPosition == 0) {
			qCell.innerHTML = "";
		} else {
			qCell.innerHTML = "<div style=\"position:relative;float: left;top: 50%;left: 50%;"+
				"transform: translate(-50%, -50%);font:normal normal normal normal 60px/90px arial;\">&#x"+
				(2189+iPosition)+";</div>";
		}
		if ((iCellValue & 248) != 0) {
			qCell.style.backgroundColor = "#DDDDDD";
		} else {
			qCell.style.backgroundColor = "#888888";
		}
	}
}

Labyrinth.php

<?php
header('Content-type: application/json');

$iaaLabyrinth = [
	[8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
	[8, 0, 0, 8, 8, 0, 0, 0, 0, 8],
	[8, 0, 0, 0, 0, 0, 0, 0, 0, 8],
	[8, 0, 0, 8, 8, 0, 0, 0, 0, 8],
	[8, 8, 8, 8, 8, 8, 0, 8, 8, 8],
	[8, 0, 0, 8, 8, 2, 0, 0, 8, 8],
	[8, 0, 0, 8, 8, 0, 0, 0, 8, 8],
	[8, 0, 0, 8, 8, 0, 0, 0, 0, 8],
	[8, 0, 0, 0, 0, 0, 8, 0, 0, 8],
	[8, 8, 8, 8, 8, 8, 8, 8, 8, 8]
];

function IsOpen($iRow, $iCol) {
	global $iaaLabyrinth;
	if ($iRow >= count($iaaLabyrinth) || $iRow < 0 || $iCol >= count($iaaLabyrinth[$iRow]) || $iCol < 0) {
		return false;
	} else if (($iaaLabyrinth[$iRow][$iCol] & 248) != 0) {
		return false;
	}
	return true;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
	// Read the raw POST data from the input stream
	$sJsonRaw = file_get_contents('php://input');
	// The input comes in as { iMove: 1 }, 
	// where the number is a value 1-4 to represent left, forward, right, backward
	// Note: left is counter-clockwise; right is clockwise
	$qPost = json_decode($sJsonRaw);

	// Read the Labyrinth file
	if (file_exists("Labyrinth.txt")) {
		$qNewFile = fopen("Labyrinth.txt", "r") or die("Unable to open file!");
		$sJsonLabyrinth = fread($qNewFile, filesize("Labyrinth.txt"));
		$iaaLabyrinth = json_decode($sJsonLabyrinth);
		fclose($qNewFile);
	}
	
	// Find the current position of the user
	$iCurrState = 0;
	$bFound = false;
	$iPosRow = -1;
	$iPosCol = -1;
	$iRowCount = count($iaaLabyrinth);
	for ($iRow = 0; $iRow < $iRowCount; ++$iRow) {
		$iColCount = count($iaaLabyrinth[$iRow]);
		for ($iCol = 0; $iCol < $iColCount; ++$iCol) {
			if (($iaaLabyrinth[$iRow][$iCol] & 7) != 0) {
				$iCurrState = ($iaaLabyrinth[$iRow][$iCol] & 7);
				$iPosRow = $iRow;
				$iPosCol = $iCol;
				$bFound = true;
			}
		}
	}
	
	// Move the user according to the input
	switch($qPost->iMove) {
		case 1:
			$iCurrState -= 1;
			if ($iCurrState == 0) {
				$iCurrState = 4;
			}
			$iaaLabyrinth[$iPosRow][$iPosCol] = (($iaaLabyrinth[$iPosRow][$iPosCol] & 248) + $iCurrState);
			break;
		case 3:
			$iCurrState += 1;
			if ($iCurrState == 5) {
				$iCurrState = 1;
			}
			$iaaLabyrinth[$iPosRow][$iPosCol] = (($iaaLabyrinth[$iPosRow][$iPosCol] & 248) + $iCurrState);
			break;
		case 2:
			switch ($iCurrState) {
				case 1:
					if (IsOpen($iPosRow, $iPosCol - 1)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow][$iPosCol - 1] = ($iaaLabyrinth[$iPosRow][$iPosCol - 1] & 248) + $iCurrState;
					}
					break;
				case 2:
					if (IsOpen($iPosRow - 1, $iPosCol)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow-1][$iPosCol] = ($iaaLabyrinth[$iPosRow-1][$iPosCol] & 248) + $iCurrState;
					}
					break;
				case 3:
					if (IsOpen($iPosRow, $iPosCol + 1)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow][$iPosCol + 1] = ($iaaLabyrinth[$iPosRow][$iPosCol + 1] & 248) + $iCurrState;
					}
					break;
				case 4:
					if (IsOpen($iPosRow + 1, $iPosCol)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow+1][$iPosCol] = ($iaaLabyrinth[$iPosRow+1][$iPosCol] & 248) + $iCurrState;
					}
					break;
			}
			break;
		case 4:
			switch ($iCurrState) {
				case 1:
					if (IsOpen($iPosRow, $iPosCol + 1)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow][$iPosCol + 1] = ($iaaLabyrinth[$iPosRow][$iPosCol + 1] & 248) + $iCurrState;
					}
					break;
				case 2:
					if (IsOpen($iPosRow + 1, $iPosCol)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow+1][$iPosCol] = ($iaaLabyrinth[$iPosRow+1][$iPosCol] & 248) + $iCurrState;
					}
					break;
				case 3:
					if (IsOpen($iPosRow, $iPosCol - 1)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow][$iPosCol - 1] = ($iaaLabyrinth[$iPosRow][$iPosCol - 1] & 248) + $iCurrState;
					}
					break;
				case 4:
					if (IsOpen($iPosRow - 1, $iPosCol)) {
						$iaaLabyrinth[$iPosRow][$iPosCol] = ($iaaLabyrinth[$iPosRow][$iPosCol] & 248);
						$iaaLabyrinth[$iPosRow-1][$iPosCol] = ($iaaLabyrinth[$iPosRow-1][$iPosCol] & 248) + $iCurrState;
					}
					break;
			}
			break;
		break;
	}

	// Write the labyrinth back to the file
	$qNewFile = fopen("Labyrinth.txt", "w") or die("Unable to open file!");
	$sJsonLabyrinth = json_encode($iaaLabyrinth);
	fwrite($qNewFile, $sJsonLabyrinth);
	fclose($qNewFile);

} else if ($_SERVER['REQUEST_METHOD'] === 'GET') {
	$sJsonLabyrinth = "";
	if (file_exists("Labyrinth.txt")) {
		// Read the file.
		$qNewFile = fopen("Labyrinth.txt", "r") or die("Unable to open file!");
		$sJsonLabyrinth = fread($qNewFile, filesize("Labyrinth.txt"));
		fclose($qNewFile);
	} else {
		$sJsonLabyrinth = json_encode($iaaLabyrinth);
	}
	echo $sJsonLabyrinth;
}
?>
 

Labyrinth.txt

[[8,8,8,8,8,8,8,8,8,8],[8,0,0,8,8,0,0,0,0,8],[8,0,0,0,0,0,0,0,0,8],[8,0,0,8,8,0,0,0,0,8],[8,8,8,8,8,8,0,8,8,8],[8,0,0,8,8,0,0,0,8,8],[8,0,0,8,8,0,0,0,8,8],[8,0,0,8,8,0,0,0,0,8],[8,0,0,0,0,1,8,0,0,8],[8,8,8,8,8,8,8,8,8,8]]
 

Output

 
 

© 2007–2026 XoaX.net LLC. All rights reserved.