递归函数只返回早期检查一条路径

时间:2017-06-14 01:18:22

标签: javascript recursion

我正在创建一个连接四游戏,我正在使用递归来检查所做的移动是否是一个成功的举动。 x和y是7x6网格上移动的坐标。

我还没有实现检查点的方向是否正确匹配(所以现在如果4个部分以任何方式接触,它仍应检测到胜利)。但在我这样做之前,我遇到了一个问题。即使所做的移动应该导致获胜,如果存在连续不存在四个的另一个路径,则该函数返回false。

函数示例错误地未检测到胜利(绿线是应该检测到的,红线是我认为该函数提前返回假的路径):https://prnt.sc/fjhia1

这是我的代码:

function isVisited(x,y,visited){
    var pointStr = x + "," + y;
    var result = visited.some(function(e){
      return e.join() == pointStr;
    });
    return result;
}

function checkWin(x, y, color, visited, count) {
    if(count==3) return true;
    for(i=-1; i<2; i++) {
        for (j=-1; j<2; j++) {
            if(!(i==0 && j==0) && (x+i)<7 && (y+j)<6 && (x+i)>-1 && (y+j)>-1 && grid[x+i][y+j] != null) {
                if (grid[x+i][y+j] == color && !isVisited(x+i,y+j,visited)) {
                    visited.push([x, y]);
                    if(checkWin(x+i, y+j, color, visited, count+1)) return true;
                }
            }
        }
    }
    return false;
}

为了澄清,i和j是用于检查起点周围所有点的偏移量。

颜色参数是&#34;黑色&#34;或&#34;红色&#34;。网格是一个7x6 2D阵列,用于存储哪些玩家棋子在哪里,并在玩家移动时更新。整个checkWin()函数在每次移动后调用,x和y参数是刚刚播放的移动的坐标。数组中的颜色示例显示在图片链接中。

来自图像的网格样本,当在x = 5,y = 3,color =&#34; black&#34;中传递给checkWin()时应返回true,但它不会:

[[null,null,null,null,null,null],[null,null,null,null,null,null],[null,null,null,null,null,null],[null,null,null,null,null,"black"],[null,null,null,null,"black","red"],[null,null,null,"black","black","black"],[null,null,null,"red","red","red"]]

2 个答案:

答案 0 :(得分:1)

这是一些有效的代码。我试图将grid放入代码中。

您的代码存在一些问题,但我认为主要的问题是您没有正确地总结计数。在您的代码中,您将遇到这种情况:

  starting here
    |
    v
R R R R

您将首先探索此节点的左侧,并且您会发现连续没有四个红色。然后你会向右探索,发现连续没有四个红色。但你需要做的是 sum 这些。你需要计算起始节点,然后是左边的两个,然后是右边的两个,以便连续获得正确的四个。

以下代码采用该策略。这是一个重写,但我试图保持它有点类似于您的原始代码。如果不清楚,请告诉我。 (这个代码与你的代码一样,并不真正关心“连续”,而只是“触摸”。)

const N = null, B = "black", R = "red";
const grid = [
//   0  1  2  3  4  5  6
    [N, N, N, N, N, N, N],  // 0
    [N, N, N, N, N, N, N],  // 1
    [N, N, N, N, N, N, N],  // 2
    [N, N, N, N, N, B, R],  // 3
    [N, N, N, N, B, B, R],  // 4
    [N, N, N, B, R, B, R],  // 5
];

function isVisited(x, y, visited) {
    var pointStr = [x, y].join();
    return visited.some(function (e) {
        return e.join() == pointStr;
    });
}

function checkWin(x, y) {
    function countNeighbors(x, y, color, visited) {
        if (y > 5 || x > 6) {  // out of bounds
            return 0;
        }

        if (isVisited(x, y, visited)) {  // already visited
            return 0;
        }
        visited.push([x, y]);

        if (grid[y][x] !== color) {  // wrong color
            return 0;
        }

        var count = 1;  // Count ourselves first.

        // For each neighbor,
        for (var i = -1; i < 2; i++) {
            for (var j = -1; j < 2; j++) {
                // add the count starting at that neighbor.
                count += countNeighbors(x+i, y+j, color, visited);
            }
        }

        // Return the total found.
        return count;
    }

    // There's a win if the count is at least four.
    return countNeighbors(x, y, grid[y][x], []) >= 4;
}

console.log(checkWin(3, 5));  // true
console.log(checkWin(5, 3));  // true
console.log(checkWin(6, 3));  // false

答案 1 :(得分:0)

您将错误的网格单元索引推送到visited列表。它应该是[x + i, y + j]

或者,您可以将语句移动到函数顶部并保持原样,这在我看来更好。函数本身会检查一个单元格,将该单元格标记为已检查或在开始时访问它更有意义。