PHP 生成迷宫路线
最近在下五子棋~理论上来说,先手一定会胜,就想研究一番。
发现和迷宫有很多相同点,就先用php生成一个迷宫路线
[2019-7-30更新]
原理:
-
- 每一个点的定义,比如 [0,0],[1,0]......表示迷宫的每一个通道。 即以向右的直线为x 轴的正方向,以向下的直线为y轴的正方向,画平面直角坐标系
-
- 每一个点上下左右点的定义。比如[0,0] 这个点 ,上点 0,-1(在平面外舍去),下点[0,1],左点-1,0(在平面外舍去),右点1,0。
-
- 从开始点[x,y],随机上下左右点中的一个,作为下一点,然后以下一点作为开始点,不断递归,直到x值达到最大值,结束,返回经过的点。
这一段代码使用的莽撞法...,避免一个点被一个多边形围着出不来
$i=0;
while (in_array($nextDot,$placedDot)||in_array($nextDot,$notPlacedDotAll)){
$i++;
if(badDot($nextDot,$placedDot,$notPlacedDot,$n)){//是否是坏点,即这个点的周围点已经放过了或者在平面外的点
$notPlacedDotAll[]=$nextDot;
$startDot=$placedDot[count($placedDot)-1];
$dotWrapper=GetDotWrappers($startDot);
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
if(badDot($startDot,$placedDot,$notPlacedDotAll,$n)){//已经放置的最后一个点,是否是坏点,即这个点的周围点已经放过了或者在平面外的点
$notPlacedDotAll[]= array_pop($placedDot);
$startDot=$placedDot[count($placedDot)-1];
$dotWrapper=GetDotWrappers($startDot);
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
}
}else{
$key=rand(0,3);
$nextDot = $dotWrapper[$key];//有可能,四次都随机到不能放置的点,然后在下面的if判断会把这个点杀掉,有莽撞的意味。
}
if($i>4&&count($placedDot)>1){//循环大于4次 还没找到去除该点。
$i=0;
$notPlacedDot[]= array_pop($placedDot);
$startDot=$placedDot[count($placedDot)-1];
$dotWrapper=GetDotWrappers($startDot);
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
}
}
<?php
$n=30;
$positions=[];
for ($i=0;$i<=$n;$i++){
for ($j=0;$j<=$n;$j++){
$positions[] =[$j,$i] ;
}
}
//开始的点
$startDot=[0,0];
//已经放置的点
$placedDot=[];
//不可放置的点
$notPlacedDot=notPlacedDot($positions,$n);
$placedDot[]=$startDot;
//所有穿过的点
$lineDot=line($positions,$startDot,$placedDot,$notPlacedDot,$n);
echo getHtml($positions,$lineDot,$n);
function line($positions,$startDot,$placedDot,$notPlacedDot,$n){
$dotWrapper=GetDotWrappers($startDot);
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
$i=0;
$notPlacedDotAll =array_merge($notPlacedDot,[]);
while (in_array($nextDot,$placedDot)||in_array($nextDot,$notPlacedDotAll)){
$i++;
if(badDot($nextDot,$placedDot,$notPlacedDot,$n)){//是否是坏点
$notPlacedDotAll[]=$nextDot;
$startDot=$placedDot[count($placedDot)-1];
$dotWrapper=GetDotWrappers($startDot);
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
if(badDot($startDot,$placedDot,$notPlacedDotAll,$n)){//本身是否是坏点
$notPlacedDotAll[]= array_pop($placedDot);
$startDot=$placedDot[count($placedDot)-1];
$dotWrapper=GetDotWrappers($startDot);
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
}
}else{
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
}
if($i>4&&count($placedDot)>1){//循环大于3次 还没找到去除该点
$i=0;
$notPlacedDot[]= array_pop($placedDot);
$startDot=$placedDot[count($placedDot)-1];
$dotWrapper=GetDotWrappers($startDot);
$key=rand(0,3);
$nextDot = $dotWrapper[$key];
}
}
$placedDot[]=$nextDot;
if($nextDot[0]>=$n&&$nextDot[1]>0&&$nextDot[1]<=$n){
return $placedDot;
}
return line($positions,$nextDot,$placedDot,$notPlacedDot,$n);
}
function getHtml($positions,$lineDot,$n){
$str="<table border='1'>";
foreach (array_chunk($positions,$n+1) as $row){
$str.="<tr>";
foreach ($row as $tr){
if(in_array($tr,$lineDot)){
$str.="<td style='color: white;background-color: red'>点{$tr[0]},{$tr[1]}</td>";
}else{
$str.="<td>{$tr[0]},{$tr[1]}</td>";
}
}
$str.="<tr>";
};
$str.="</table>";
return $str;
}
function notPlacedDot($positions,$n)
{
$notPlacedDot=[];
foreach ($positions as $position){
$dotWrapper=GetDotWrappers($position);
foreach ($dotWrapper as $dot){
if($dot[0]<0||$dot[1]<0||$dot[0]>$n||$dot[1]>$n){
$notPlacedDot[]=$dot;
}
}
}
return $notPlacedDot;
}
/**
* 是否是坏点
* @param $dotWrapper
* @param $placedDot
* @param $notPlacedDot
* @return bool
*/
function badDot($position,$placedDot,$notPlacedDot,$n){
$dotWrapper=GetDotWrappers($position);
$i=0;
foreach ($dotWrapper as $dot){
if($dot[0]<0||$dot[1]<0||$dot[1]>$n||in_array($dot,$placedDot)||in_array($dot,$notPlacedDot)){
$i++;
}
}
if($i==4){
return true;
}
return false;
}
function GetDotWrappers($placementEd){
$top = calculateXY($placementEd[0],$placementEd[1],'top');
$bottom = calculateXY($placementEd[0],$placementEd[1],'bottom');
$left = calculateXY($placementEd[0],$placementEd[1],'left');
$right = calculateXY($placementEd[0],$placementEd[1],'right');
return [$top,$bottom,$left,$right];
}
function calculateXY($x,$y,$default='top')
{
switch ($default){
case 'top':
$y=$y+1;
break;
case 'bottom':
$y=$y-1;
break;
case 'left':
$x=$x-1;
break;
case 'right':
$x=($x+1);
break;
case 'left_top':
$x=($x-1);
$y=($y+1);
break;
case 'right_top':
$x=($x+1);
$y=($y+1);
break;
case 'right_bottom':
$x=($x+1);
$y=($y-1);
break;
case 'left_bottom':
$x=($x-1);
$y=($y-1);
break;
}
return [$x,$y];
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
能说一下原理吗,读代码太麻烦了~
+1 能稍微讲一下原理吗?
@wanghan @BradStevens 原理已加上~
@jcc123 谢谢啦
这代码有意思,
我去看了你博客,控制台超干净,点赞!
@L学习不停 哈哈,生命不息,学习不止
😁😁😁
走迷宫,,哈哈
http://toys.lzis.me/maze/
@largezhou 可以结合起来奥,给你提供数据,你去走~~