在Go棋盘游戏中捕获石头

时间:2013-06-11 23:48:11

标签: java recursion

我正在尝试用Java重新创建棋盘游戏“go”。我目前正在研究捕获系统。基本上,一旦石头四面被敌人的石头包围(对角线不计算),你就会移走那块石头。如下面的截图。

enter image description here

如果连接了多个相同的宝石,则必须围绕所有开放的边。如下面的截图。

enter image description here

在这两种情况下,此时应移除黑色宝石。此链接更多地解释了捕获石头的规则。 societies.cam。 AC。英国/cugos/go/rules_03.html

我被告知最好使用递归来做到这一点。在对递归进行一些研究后,我设法编写了一些代码。但它不起作用。它似乎只是在游戏的第二步中发现敌人的石头。每次在我的鼠标中放置一块石头时,我都会调用我的方法。

public static boolean checkCapture(int x, int y)
{
    {
        if ((board[x][y + 1] != move) && (board[x][y + 1] != 0)) //bellow
        {
            System.out.println("enemy is bellow");
            if (checkCapture(x, y + 1))
                board[x][y] = 0;
        } else if (board[x][y + 1] == 0)
        {
            return false;
        }

        if ((board[x][y - 1] != move) && (board[x][y - 1] != 0)) //above
        {
            System.out.println("enemy is above");
            if (checkCapture(x, y - 1))
                board[x][y] = 0;
        } else if (board[x][y - 1] == 0)
        {
            return false;
        }

        if ((board[x + 1][y] != move) && (board[x + 1][y] != 0)) // right
        {
            System.out.println("enemy is right");
            if (checkCapture(x + 1, y))
                board[x][y] = 0;
        } else if (board[x + 1][y] == 0)
        {
            return false;
        }

        if ((board[x - 1][y] != move) && (board[x - 1][y] != 0)) //left
        {
            System.out.println("enemy is left");
            if (checkCapture(x - 1, y))
                board[x][y] = 0;
        } else if (board[x - 1][y] == 0)
        {
            return false;
        }
    }
    return true;
}

我的int x是我的列,我的int是我的行,move是我的变量,它保持轮到它(1 =黑色,2 =白色)board是我的2d数组,它保存所有石头的位置董事会。

4 个答案:

答案 0 :(得分:2)

我认为递归使这个解决方案变得更加复杂。如果我要实现这样的东西,我会采取以下步骤:

  1. 查找已连接的宝石组。如果你可以通过两只眼睛检测一个群体是否还活着,你可以将其限制为龙。

  2. 对于每组连接的宝石,纵向和横向计算自由度。 (自由是与相连的一组石头相邻的未占据位置。)如果自由数为0,则该组被捕获。

  3. 如果您在移动后检查捕获,那么您实际上只需要检查与最近移动相邻的连接组,而不是所有连接组。

答案 1 :(得分:1)

首先,从显式开始,关于你的功能是什么。

/**
 *  Checks to see if the grid point passed in is captured.
 *  @param...(you should say what your params are here
 **/
public static boolean checkCapture(int x, int y) {
   //some code
}

这很重要:如果此函数检查网格点是否正在捕获其他任意点,该怎么办?此外,我们立即看到一个问题......由谁捕获?每当解决递归问题时,你需要理解基本情况:这里没有没有被敌人占据的垂直或水平相邻区域。

因此,我们必须检查以查看特定颜色:

/**
 *  Checks to see if the grid point passed in is captured.
 *  @param...(you should say what your params are here
 **/
public static boolean checkCapture(int x, int y) {
   if (!isOccupied(x,y)) {//writing this function should be trivial
     return false;//can't be captured; no one is there!
   }

   Color color = getColor(x,y);//similarly, get the color of whoever is there.
   Status status = checkFlanked(x, y, color);
   if (status = Status.FLANKED) {
     return true;
   }
}

private static Status checkFlanked(int x, int y, Color color) {
   //check to see that this location is valid for the board
   //check to see if this square is occupied at all
     //if it is not, return LIBERTY (an empty space means no capture, right?)
     //if it is, is it occupied by the opposite color? --> Return a FLANKED result!
     //if it is, is it occupied by the same color? --> recurse!
}

现在我们已经解决了我们的问题!并且很容易看出基本案例是如何解决的:如果广场未被占用,则它不能是侧翼...因此它返回LIBERTY结果。如果它被相反的颜色占据,那么这个方块就在你最初检查的任何一个侧面。唯一困难的部分是检查是否,如果被原始颜色占用,​​任何其他地点是否有自由。

 //get all valid adjacent locations
 //call checkFlanked on those locations.
 //If any return LIBERTY, return LIBERTY. Otherwise return FLANKED.

(注意:为了清楚起见,我假设LIBERTYFLANKED被定义为枚举。)

我希望这可以帮助您以更明智的方式解决问题。记住:当你使用递归时,你关心两种情况:基本情况和'+1迭代'情况。请注意,即使使用上述内容,您也必须解决一些问题:

  • 你需要聪明地不要回到你已经去过的广场。 (调查尾部递归,但您也可以传递另外的状态,指示已经检查过的方块。)
  • 如果你这样做,你需要确保你不会脱离董事会并返回适当的结果。基本上,你需要解决'什么是有效位置?'问题。

其他一些有趣的问题是:

  • 您是按广度还是深度搜索?
  • 这是否适合作为静态方法,还是应该在类中捕获?

答案 2 :(得分:-1)

我有一些代码可以让你玩和捕捉石头。请参阅此答案:https://gamedev.stackexchange.com/questions/23291/go-game-placing-stones-on-grid-intersections/23406#23406

诀窍是跟踪连续的石块,然后在每次移动后检查以查看该移动是否捕获了一块。

还有担心的问题。

答案 3 :(得分:-3)

在这种情况下递归的问题是很容易陷入无限循环。检查两块石头,检查正确的石头将检查左石头将再次检查右边等。您需要跟踪已经检查过的石头。你将需要通过一些你已经检查过的石头状态。