簡體   English   中英

如何存儲深度未知的遞歸函數的結果?

[英]How to store results from recursive function with unknown depth?

我最近遇到了一個游戲,該游戲會生成一個NxN(2x2、4x4 ...)棋盤,並帶有編號為圖塊(1、2、3 ...),其中每個數字確定允許的移動。 目標是在可能的情況下清空整個電路板,而每個磁貼只能使用一次。

一個小板可能看起來像這樣:

| 1 1 |  
| 1 1 |

大板:

| 1 2 2 3 |  
| 2 1 1 1 |  
| 3 2 1 3 |  
| 2 2 3 1 | 

由於我經常偶然發現無法解決的情況,因此我嘗試編寫一個簡短的腳本,檢查在使用電路板之前是否可以找到解決方案。

盡管這部分起作用,但是檢查每種可能的組合並分別存儲所有結果變得更加復雜,我甚至不確定這是否完全可能。

這是簡化的示例:

$tiles[1][1] = 'p1';
$tiles[2][1] = 'p1';
$tiles[1][2] = 'p1';
$tiles[2][2] = 'p1';

$moves = array(
                array('x' => -1, 'y' => -1),
                array('x' =>  0, 'y' => -1),
                array('x' =>  1, 'y' => -1),
                array('x' => -1, 'y' =>  0),
                array('x' =>  1, 'y' =>  0),
                array('x' => -1, 'y' =>  1),
                array('x' =>  0, 'y' =>  1),
                array('x' =>  1, 'y' =>  1)
            );

function nextMove($x, $y, &$visited)
{
    global $moves;

    $max_loops = count($moves);
    $visited[] = $x. ', ' .$y;

    for ($j = 0; $j < $max_loops; $j++)
    {
        $new_x = $x + $moves[$j]['x'];
        $new_y = $y + $moves[$j]['y'];

        if (($new_x >= 1) && ($new_x <= 2) && ($new_y >= 1) && ($new_y <= 2))
        {
            $new_pos = $new_x. ', ' .$new_y;

            if (!in_array($new_pos, $visited))
            {
                $j = $max_loops - 1;

                nextMove($new_x, $new_y, $visited);
            }
        }
    }
}

nextMove(1, 1, $visited, $moves_done);
var_dump($visited);

因此,這里發生的事情很簡單:

該函數將使用初始坐標進行調用,計算最大移動量(針對該圖塊),然后將當前位置添加到$visited數組中。

之后, for循環會遍歷所有可能的移動,生成新坐標並檢查它們是否在板上,或者之前是否已“訪問”該圖塊。 如果找到有效的移動,則會使用新坐標再次調用該函數。

(如您所見, $j = $max_loops - 1;在此結束循環,以避免以后再找不到有效移動時將錯誤的值添加到$visited

這就是現在發生的事情:

array(4) {
  [0]=>
  string(4) "1, 1"
  [1]=>
  string(4) "1, 2"
  [2]=>
  string(4) "2, 1"
  [3]=>
  string(4) "2, 2"
}

到目前為止,腳本可以正常工作,但是一旦沒有可能的移動,腳本便會結束並且不檢查其他組合(使用$j = $max_loops - 1; )或向$visited添加錯誤的坐標。 為了避免這種情況,我要么必須單獨存儲結果,要么更改函數,這就是我遇到的問題。

一個大問題是未知數量的可能動作,因為有時游戲在2步之后結束,有時可以清除棋盤。

是否有任何方法可以讓函數迭代所有可能的組合並分別存儲/返回(可能處理起來太多,不是必需的,但如果僅使用1-2個圖塊,可能會很有趣), 或者至少檢查是否可以清除整個電路板並返回解決方案(這很重要,因為結果應在以后存儲和使用)?

該腳本應以這種方式工作:

array(4) {
  [0]=>
  string(4) "1, 1"
  [1]=>
  string(4) "1, 2"
  [2]=>
  string(4) "2, 1"
  [3]=>
  string(4) "2, 2"
}
array(4) {
  [0]=>
  string(4) "1, 1"
  [1]=>
  string(4) "1, 2"
  [2]=>
  string(4) "2, 2"
  [3]=>
  string(4) "2, 1"
}
array(4) {
  [0]=>
  string(4) "1, 1"
  [1]=>
  string(4) "2, 1"
  [2]=>
  string(4) "1, 2"
  [3]=>
  string(4) "2, 2"
}
array(4) {
  [0]=>
  string(4) "1, 1"
  [1]=>
  string(4) "2, 1"
  [2]=>
  string(4) "2, 2"
  [3]=>
  string(4) "1, 2"
}
array(4) {
  [0]=>
  string(4) "1, 1"
  [1]=>
  string(4) "2, 2"
  [2]=>
  string(4) "2, 1"
  [3]=>
  string(4) "1, 2"
}
array(4) {
  [0]=>
  string(4) "1, 1"
  [1]=>
  string(4) "2, 2"
  [2]=>
  string(4) "1, 2"
  [3]=>
  string(4) "2, 1"
}

[...]

好的,這是我想出的:

<?php

$width = 2;
$height = 2;

$tiles[2][1] = 1;
$tiles[1][2] = 1;
$tiles[1][1] = 1;
$tiles[2][2] = 1;

$directions = array(
                array('x' => -1, 'y' => 0),
                array('x' => -1, 'y' => 1),
                array('x' => 0, 'y' => 1),
                array('x' => 1, 'y' => 1),
                array('x' => 1, 'y' => 0),
                array('x' => 1, 'y' => -1),
                array('x' => 0, 'y' => -1),
                array('x' => -1, 'y' => -1)
            );

$valid_paths = array();

function nextMoves($position, $visited = array()){
    global $directions, $tiles, $valid_paths, $height, $width;

    $visited[] = $position;
    if(count($visited) == $width * $height){
        $valid_paths[] = $visited;
        return;
    }

    $next_moves = array();
    $position = explode(',', $position);
    $x = $position[0];
    $y = $position[1];

    $tile_value = $tiles[$x][$y];

    foreach($directions as $direction){
        $new_x = $x + $direction['x'] * $tile_value;
        $new_y = $y + $direction['y'] * $tile_value;
        $new_pos = "$new_x,$new_y";

        if (($new_x >= 1) && ($new_x <= $width) && ($new_y >= 1) && ($new_y <= $height) && !in_array($new_pos, $visited)){
            $next_moves[] = $new_pos;
        }
    }

    foreach($next_moves as $next_move){
        nextMoves($next_move, $visited);
    }   
}

nextMoves('1,1');

echo "<pre>";
var_dump($valid_paths);
echo "</pre>";

?>

說明

  1. nextMoves函數nextMoves給定位置開始的所有有效路徑添加到全局變量$valid_paths
  2. 首先,它檢查是否已訪問所有圖塊。 如果是這樣,則會將$visited數組添加到$valid_paths
  3. 如果尚未訪問所有圖塊,則會將當前的$position添加到$visited數組中。
  4. 接下來,在每個$direction迭代,如果可以沿該方向移動到網格中未訪問的圖塊,則將新圖塊添加為有效的下一個步驟。
  5. 在完成計算之后,所有可能的有效下一步移動都將針對每個新的$position帶有新的$visted $position重新開始。

我已經改善了一些代碼。 它可以生成具有一定數量可能答案的有效木板。 我不會在此處發布代碼,因為它與答案無關。 您可以在此PHPFiddle中檢查改進的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM