在Stratego中检测不可移动部件的算法

时间:2010-04-06 22:05:05

标签: java algorithm

我正在创建一个Stratego游戏并且我在创建一个算法时遇到问题,该算法可以检测何时没有更多可能的移动,因为所有碎片都已消失或其余部分无法移动或被禁止的方块,不可移动的碎片或其他被困物体困住件。

为简单起见,您可以将电路板视为可以包含碎片的正方形阵列。

Square[][] gameBoard = new Square[10][10]

Squares具有易于检查的状态,例如hasPiece(),hasEnemyPiece(),hasUnMovablePiece(),hasMoveablePiece(),isBlocked()。

如果每次玩家移动时都没有运行此算法,但可能在开始时检查,然后在玩家移动时仅检查某些条件,那也可能会很好。

[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[B][ ][ ][ ][ ][ ][B][B][ ][ ]
[F][B][ ][ ][ ][B][3][4][B][ ]

这是游戏结束时的一个示例情况,您需要能够检查每个不可移动的部件(3和4)以查看它们是否可移动[未被水困住(被阻挡),其他不可动摇的碎片(炸弹或旗帜)或其他被困物品。

5 个答案:

答案 0 :(得分:4)

Stratego的运动规则非常基本。有两个州。可以移动,并且应该移动。

CAN移动很容易。 CAN移动实际上是一个简单的空间检查。

为什么不简单:

boolean canMove() {
    return squareEmpty(myX - 1, myY) ||
        squareEmpty(myX + 1, myY) ||
        squareEmpty(myX, myY - 1) ||
        squareEmpty(myX, myY + 1));
}

显然,旗帜和炸弹“canMove”常规会一直返回false。这适用于侦察兵,因为他们至少需要移动一个空白,所以这是重要的。

唯一不跟踪的是“后退5次”限制,但是,这几乎不是很难。

最后:

movesAvailable = 0;
for(Piece p : pieces) {
    if (p.canMove()) {
        movesAvailable++;
    }
}

这不是一个昂贵的过程。

答案 1 :(得分:3)

我认为这样的事情会起作用:

// Cardinal directions
int[] dx = { 1, 0, -1,  0 };
int[] dy = { 0, 1,  0, -1 };

// Loop through each space
for (int j=0; j<10; j++) {
    for (int i=0; i<10; i++) {

        // Check if you have a movable piece there
        if(gameBoard[i][j].hasMovablePiece() && !gameBoard[i][j].hasEnemyPiece()) {

            // Check neighbors
            for (int k=0; k<4; k++) {
                int ni = i+dx[k];
                int nj = j+dy[k];

                // Bounds check
                if(ni >= 0 && nj >=0 && ni < 10 && nj < 10) {

                    // Check if space is an enemy or empty and not blocked
                    // If so we still have a move
                    if((!gameBoard[ni][nj].hasPiece() || gameBoard[ni][nj].hasEnemyPiece()) && !gameBoard[ni][nj].isBlocked()){
                        return false;
                    }
                }

            }
        }
    }
}

// We made it without finding a movable piece
return true;

这简单地遍历每个方块并检查它是否有你的作品,并且它是一个可移动的类型。然后它检查周围的空间,看是否有敌人的碎片,或者是否有一个没有阻挡的空间。如果找到一个,我们知道还有剩下的动作,所以我们退出。

最糟糕的是,你检查每个空间和每个邻居(约500个支票),这实际上并不多。您可以通过计算每件作品来加快速度,如果达到剩下的件数,也可以退出。

答案 2 :(得分:1)

我没有看到任何理由为什么威尔的答案会太昂贵,但我会提出另一个想法只是为了笑容。一种选择是维护当前可移动的棋子列表,每个玩家一个列表。检查玩家是否没有动作就像查看该列表的当前大小一样简单。

但是,成本是你必须在每一步中保持清单。单件的移动可以解锁其周围的任何部件,以及免费的块件。从概念上讲,你可以看到,这比检查电路板上的每个方块要困难得多。

答案 3 :(得分:1)

我认为计算自由可能在这里有意义。

这个想法是要计算你的集体棋子可以移动多少个方向。这相当于你的可移动棋子旁边的空心方块或敌人棋子(可用方格)的数量。如果多个部分触及可用的方块,则会多次计数。我们将每个可用的方形/潜在移动方向称为自由。

首先计算初始自由的数量。您只需计算前排可移动部件的数量而不接触水。没有其他作品可以移动,每件作品只有一个可以移动的方向。

之后,更新自由数的算法非常简单。你计算旧位置的自由数量,减去它阻挡的碎片数量,并计算新位置的自由数量,再次减去它阻挡的碎片数量。你可以将它添加到总自由度中,并获得新值。

我有一段时间没有编写java代码,所以我的例子将是伪代码/ python,但这个想法应该转移。

directions = [(0,1),(0,-1),(1,0),(-1,0)]
for d in directions:
   if (SpaceIsAvailable(oldPosition + d)):
      liberties--
   if (SpaceIsMovable(oldPosition + d)):
      liberties++
   if(SpaceIsAvailable(newPosition + d)):
      liberties++
   if(SpaceIsMovable(newPosition + d)):
      liberties--
如果该位置为空或对手,则

SpaceIsAvailable为真。 SpaceIsMovable如果斑点是你的作品并且是可移动的,那就是真的。

当对手移动他的作品时,你的自由无法改变。 SpaceIsAvailableSpaceIsMovable都不会更改值。

如果你的作品被移除,你只需运行相同的算法,但放弃newPosition部分。

for d in directions:
   if (SpaceIsAvailable(position + d)):
      liberties--
   if (SpaceIsMovable(position + d)):
      liberties++

现在,如果liberties > 0,你有可动件。您需要做的就是跟踪两个玩家的整数,并且您可以跳过任何计算,确定是否有任何碎片可用。

如果您强制执行防止移动重复的规则,则这不起作用。我不确定你将如何实现它。如果你通过确定哪些部分不允许移动来做到这一点,你可以简单地将自由总数与他们的自由进行比较而不是0。如果它相等,那么就没有动作了。如果总自由度低于无法移动的部分的自由度,那么我的算法或代码就会出现问题。

如果我正确地阅读了重复规则,那么一次只能有一件不能移动的规则,因此只需要考虑一组自由。

frozenLiberties = 0
if (frozenPiece):
   for d in directions:
      if (SpaceIsAvailable(frozenPiece + d)):
         frozenLiberties++
if (liberties > frozenLiberties):
    // moves available.
else:
    // No moves available.

答案 4 :(得分:0)

有一点需要注意的是,这里的所有算法要么忽略边界条件,要么检查它们。另一种可能性就是让你的电路板12x12并沿着边缘放水。您必须在所有代码中考虑到这一点,但如果您有一个带有访问器的Board对象来获取有关特定方块的信息,则只需在获得结果之前减去一个。然后board.GetSquare(0,0)将返回角落中的棋子,而board.GetSquare(-1,5)会返回水,board.GetSquare(3,10)也是如此。 board.GetSquare(-2,1)会抛出异常。

我认为,所有的算法都会简单得多,而且不会使访问变得复杂。