mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-10 17:28:40 +00:00
163 lines
4.0 KiB
PHP
Executable File
163 lines
4.0 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Jingga
|
|
*
|
|
* PHP Version 8.2
|
|
*
|
|
* @package phpOMS\Algorithm\Maze
|
|
* @copyright Dennis Eichhorn
|
|
* @license OMS License 2.0
|
|
* @version 1.0.0
|
|
* @link https://jingga.app
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
namespace phpOMS\Algorithm\Maze;
|
|
|
|
/**
|
|
* Maze generator
|
|
*
|
|
* @package phpOMS\Algorithm\Maze
|
|
* @license OMS License 2.0
|
|
* @link https://jingga.app
|
|
* @since 1.0.0
|
|
*/
|
|
class MazeGenerator
|
|
{
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @since 1.0.0
|
|
* @codeCoverageIgnore
|
|
*/
|
|
private function __construct()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Generate a random maze
|
|
*
|
|
* @param int<0, max> $width Width
|
|
* @param int<0, max> $height Height
|
|
*
|
|
* @return array
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public static function random(int $width, int $height) : array
|
|
{
|
|
$n = $height * $width - 1;
|
|
$horizontal = \array_fill(0, $height, []);
|
|
$vertical = \array_fill(0, $height, []);
|
|
|
|
$pos = [\mt_rand(0, $height) - 1, \mt_rand(0, $width) - 1];
|
|
$path = [$pos];
|
|
$unvisited = [];
|
|
|
|
for ($i = 0; $i < $height + 2; ++$i) {
|
|
$unvisited[] = [];
|
|
|
|
for ($j = 0; $j < $width + 1; ++$j) {
|
|
$unvisited[$i][] = $i > 0 && $i < $height + 1 && $j > 0 && ($i !== $pos[0] + 1 || $j != $pos[1] + 1);
|
|
}
|
|
}
|
|
|
|
while ($n > 0) {
|
|
$potential = [
|
|
[$pos[0] + 1, $pos[1]],
|
|
[$pos[0], $pos[1] + 1],
|
|
[$pos[0] - 1, $pos[1]],
|
|
[$pos[0], $pos[1] - 1],
|
|
];
|
|
|
|
$neighbors = [];
|
|
|
|
for ($i = 0; $i < 4; ++$i) {
|
|
if ($unvisited[$potential[$i][0] + 1][$potential[$i][1] + 1] ?? false) {
|
|
$neighbors[] = $potential[$i];
|
|
}
|
|
}
|
|
|
|
if (!empty($neighbors)) {
|
|
--$n;
|
|
|
|
$next = $neighbors[\array_rand($neighbors, 1)];
|
|
$unvisited[$next[0] + 1][$next[1] + 1] = false;
|
|
|
|
if ($next[0] === $pos[0]) {
|
|
$horizontal[$next[0]][($next[1] + $pos[1] - 1) / 2] = true;
|
|
} else {
|
|
$vertical[($next[0] + $pos[0] - 1) / 2][$next[1]] = true;
|
|
}
|
|
|
|
$path[] = $next;
|
|
$pos = $next;
|
|
} else {
|
|
$pos = \array_pop($path);
|
|
|
|
if ($pos === null) {
|
|
break; // @codeCoverageIgnore
|
|
}
|
|
}
|
|
}
|
|
|
|
$maze = [];
|
|
for ($i = 0; $i < $height * 2 + 1; ++$i) {
|
|
$line = [];
|
|
|
|
if ($i % 2 === 0) {
|
|
for ($j = 0; $j < $width * 4 + 1; ++$j) {
|
|
if ($j % 4 === 0) {
|
|
$line[$j] = '+'; // 9
|
|
} else {
|
|
$line[$j] = $i > 0 && ($vertical[$i / 2 - 1][(int) \floor($j / 4)] ?? false) ? ' ' : '-'; // 9
|
|
}
|
|
}
|
|
} else {
|
|
for ($j = 0; $j < $width * 4 + 1; ++$j) { // 2
|
|
if ($j % 4 === 0) {
|
|
$line[$j] = $j > 0 && ($horizontal[($i - 1) / 2][$j / 4 - 1] ?? false) ? ' ' : '|'; // 0 | 9
|
|
} else {
|
|
$line[$j] = ' '; // 0
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($i === 0) {
|
|
$line[1] = $line[2] = $line[3] = ' '; // 0
|
|
}
|
|
|
|
if ($height * 2 - 1 === $i) {
|
|
$line[4 * $width] = ' '; // 2 - 0
|
|
}
|
|
|
|
$maze[] = $line;
|
|
}
|
|
|
|
return $maze;
|
|
}
|
|
|
|
/**
|
|
* Render a maze
|
|
*
|
|
* @param array<int, int[]> $maze Maze to render
|
|
*
|
|
* @return string
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public static function render(array $maze) : string
|
|
{
|
|
$rendered = '';
|
|
foreach ($maze as $row) {
|
|
foreach ($row as $column) {
|
|
$rendered .= $column;
|
|
}
|
|
|
|
$rendered .= "\n";
|
|
}
|
|
|
|
return $rendered;
|
|
}
|
|
}
|