PHP 生成迷宮路線

jcc123發表於2019-07-29

最近在下五子棋~理論上來說,先手一定會勝,就想研究一番。
發現和迷宮有很多相同點,就先用php生成一個迷宮路線

線上體驗
PHP 生成迷宮路線

PHP 生成迷宮路線
[2019-7-30更新]

原理:

    1. 每一個點的定義,比如 [0,0],[1,0]......表示迷宮的每一個通道。 即以向右的直線為x 軸的正方向,以向下的直線為y軸的正方向,畫平面直角座標系
    1. 每一個點上下左右點的定義。比如[0,0] 這個點 ,上點 0,-1(在平面外舍去),下點[0,1],左點-1,0(在平面外舍去),右點1,0。
    1. 從開始點[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];
}

NOT IS BECAUSE I WANT TO WRITE,
BUT I WANT TO INCREASE,
SO I GO TO WRITE~~

相關文章