我正在创建一个Stratego游戏并且我在创建一个算法时遇到问题,该算法可以检测何时没有更多可能的移动,因为所有碎片都已消失或其余部分无法移动或被禁止的方块,不可移动的碎片或其他被困物体困住件。
为简单起见,您可以将电路板视为可以包含碎片的正方形阵列。
Square[][] gameBoard = new Square[10][10]
Squares具有易于检查的状态,例如hasPiece(),hasEnemyPiece(),hasUnMovablePiece(),hasMoveablePiece(),isBlocked()。
如果每次玩家移动时都没有运行此算法,但可能在开始时检查,然后在玩家移动时仅检查某些条件,那也可能会很好。
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[B][ ][ ][ ][ ][ ][B][B][ ][ ]
[F][B][ ][ ][ ][B][3][4][B][ ]
这是游戏结束时的一个示例情况,您需要能够检查每个不可移动的部件(3和4)以查看它们是否可移动[未被水困住(被阻挡),其他不可动摇的碎片(炸弹或旗帜)或其他被困物品。
答案 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
如果斑点是你的作品并且是可移动的,那就是真的。
当对手移动他的作品时,你的自由无法改变。 SpaceIsAvailable
或SpaceIsMovable
都不会更改值。
如果你的作品被移除,你只需运行相同的算法,但放弃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)
会抛出异常。
我认为,所有的算法都会简单得多,而且不会使访问变得复杂。