[英]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>";
?>
說明
nextMoves
函數nextMoves
給定位置開始的所有有效路徑添加到全局變量$valid_paths
。 $visited
數組添加到$valid_paths
$position
添加到$visited
數組中。 $direction
迭代,如果可以沿該方向移動到網格中未訪問的圖塊,則將新圖塊添加為有效的下一個步驟。 $position
帶有新的$visted
$position
重新開始。 我已經改善了一些代碼。 它可以生成具有一定數量可能答案的有效木板。 我不會在此處發布代碼,因為它與答案無關。 您可以在此PHPFiddle中檢查改進的代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.