我正在努力在Java上实现connect 4 Game。我几乎完成了模拟游戏的程序。
我使用2D角色阵列try {
return SSLContext.getInstance("TLSv1.2");
} catch (NoSuchAlgorithmException e) {
LOGGER.error("error during initialization",e);
}
来表示游戏的网格。
我已经实现了char [][] board = new char[6][7];
方法来查找是否有4个连续相同的水平元素来检查胜利条件。我还实现了checkHorizontal
方法来查找是否有4个连续相同的垂直元素来检查胜利条件。
我在编写checkVertical
方法的算法时有点困惑,它检查了2D阵列中4个连续相同对角线元素的所有可能性。
以下是游戏中对角线胜利案例的2个例子
案例1:
checkDiagonal
案例2:
* * * * * * *
* * * * * * *
Y * * * * * *
R Y * * Y * *
Y R Y R Y R R
R Y R Y R Y R
如何检查 * * * * * * *
* * * * * * *
* * * * * R *
* * * * R Y *
* * * R Y R *
Y Y R Y R Y R
和rows
以解决这些问题?
答案 0 :(得分:5)
您只需要检查新type
类型的位置,因为游戏区域的其余部分保持不变。在那里,你可以这样做:
/**
* Counts pieces of the given type, starting at (y, x),
* in the direction denoted by (dy, dx).
* Stops at field boundaries or when a different field type is encountered.
*/
int count(char type, int x, int y, int dy, int dy) {
int count = 0;
x += dx; // Skip the piece at (y, x) to avoid counting it twice
y += dy; // when looking in both directions on a line.
while (x >= 0 && x < 7 && y >= 0 && y < 6 && board[y][x] == type) {
count++;
x += dx; // Move in the direction denoted by (dy, dx)
y += dy;
}
return count;
}
/**
* Main entry point after a new piece of type `type` was added at (y, x).
* Returns true if this connects 4 or more in any direction.
*/
boolean check(char type, int x, int y) {
return count(type, x, y, -1, 0) + 1 + count(type, x, y, 1, 0) >= 4 // horizontal
|| count(type, x, y, 0, -1) + 1 + count(type, x, y, 0, 1) >= 4 // vertical
|| count(type, x, y, -1, -1) + 1 + count(type, x, y, 1, 1) >= 4 // diagonal
|| count(type, x, y, -1, 1) + 1 + count(type, x, y, 1, -1) >= 4);
}
dx和dy检查参数用于向不同方向移动,而无需为每个方向设置单独的方法。
在你的水平检查代码中,你可能通过在循环中将x加1来保持下一个(保持y不变,即将y加0)。在垂直检查代码中,通过向y(和0到x)添加1来移动到下一个部分。要沿对角线移动,您需要在x和y坐标上添加1。
为了能够使用单一方法检查所有方向,check()使用移动方向的参数:dx = 1和dy = 0在每个步骤中将1添加到x和0到y,所以你做了一个水平检查。如果dx = 0且dy = 1,则进行垂直检查。
编辑:摆脱了支票帮助,因为它只在一个地方真正需要
答案 1 :(得分:3)
另一个效率较低但可能更容易理解的解决方案是将行换1到另一个数组并重用你的垂直赢代码。
例如,将左数组从左到右对角线移动到更大的数组中,如下所示:
* * * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * R * * * * * * R *
* * * * R Y * * * * * R Y *
* * * R Y R * * * * R Y R *
Y Y R Y R Y R Y Y R Y R Y R
从右到左对角线:
* * * * * * * * * * * * * *
* * * * * * * * * * * * * *
Y * * * * * * Y * * * * * *
R Y * * Y * * R Y * * Y * *
Y R Y R Y R R Y R Y R Y R R
R Y R Y R Y R R Y R Y R Y R
现在,您可以重复使用垂直获胜代码进行对角线获胜。
答案 2 :(得分:2)
检查对角线类似于检查水平线,增加阵列偏移的复杂性。你可以做到的一种方法是对阵列进行蛮力行走。
您可以选择主要专业或专业专业。随时增加你的位置。即下面显示了一行主要步行。
首先检查
* * * X * * *
* * X * * * *
* X * * * * *
X * * * * * *
* * * * * * *
* * * * * * *
下一步:
* * * * X * *
* * * X * * *
* * X * * * *
* X * * * * *
* * * * * * *
* * * * * * *
等等。 一旦到达第一行的末尾,就增加行并重复。 即下一行的第一次迭代将是。
* * * * * * *
* * * X * * *
* * X * * * *
* X * * * * *
X * * * * * *
* * * * * * *
对所有行重复,并且您已覆盖该方向上的所有对角线。现在重复对角线的相反方向。
数组明智,因为你知道从位置4(索引3)开始,你可以简单地使用直接偏移。即
if( board[row][column] == board[row+1][column-1] == board[row+2][column-2] == board[row+3][column-3] ){
/* You have a match */
}
答案 3 :(得分:0)
我喜欢用于许多基于网格的问题的概念称为dx/dy
。基本思路是你有2个数字数组,一个用于delta x,另一个用于delta y,指定在这个方向上要走多远。例如:这是一个8方向dx / dy数组对。
int[] dx = {0, 0, 1, 1, 1,-1,-1,-1}
int[] dy = {1,-1, 0, 1,-1, 0, 1,-1}
一个较小的4方向阵列对:
int[] dx = {0, 0, 1,-1}
int[] dy = {1,-1, 0, 0}
用于检查连接4的简明版本,因为反向指示对于我们的目的是相同的(即向上 - 左= =向下 - 右):
int[] dx = {1, 0, 1,-1}
int[] dy = {0,-1, 1, 1}
打破这个我们看到可以看到假装堆积的数字是x,y对。因此,如果我们想要8个移动方向,请考虑下面我们当前位置S = (x, y)
的电路板:
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - S - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
如果查看两个数组的i-th
索引,您将得到一对dx / dy坐标(这些对在上面的数组中垂直对齐):
dx[4] = 1
dy[4] = -1
这将为我们提供x和y的delta(或变化)以达到我们的新位置。现在看一下这个板,你可以看到8个dx / dy对中的每个对你带来的位置(根据数组的索引编号):
- - - - - - - -
- - - - - - - -
- - - 6 0 3 - -
- - - 5 S 2 - -
- - - 7 1 4 - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
所以你可以在这里看到第4位是
( S.x + 1, S.y - 1 )
对应于dx / dy数组
( S.x + dx[4], S.y + dy[4] )
现在,如果您将其置于for循环中,则可以检查x,y位置周围的所有8个方块。
这个概念可以通过简单地构建不同的对来以许多不同的方式应用(例如,骑士在国际象棋中的运动)。考虑一下骑士运动的阵列:
int[] dx = {1, 1, 2, 2,-1,-1,-2,-2}
int[] dy = {2,-2, 1,-1, 2,-2, 1,-1}
骑士的网格(K)及其所有可能的动作:
- - - - - - - -
- - - - - - - -
- - 4 - 0 - - -
- 7 - - - 2 - -
- - - K - - - -
- 6 - - - 3 - -
- - 5 - 1 - - -
- - - - - - - -
有了这些知识,我们可以通过几个步骤解决您的问题。
第1步:遍历网格中的每个x,y坐标:
for(int x = 0; x < width; x++)
for(int y = 0; y < height; y++)
第2步:现在我们应用dx / dy检查8个方向的所有邻居:
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
for(int i = 0; i < dx.length; i++) {
int xTemp = x + dx[i];
int yTemp = y + dy[i];
}
}
}
第3步:检查我们是否有相同颜色的邻居:
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
if( GRID(x, y) == EMPTY) continue;
for(int i = 0; i < dx.length; i++) {
int xTemp = x + dx[i];
int yTemp = y + dy[i];
if( GRID(x, y).color == GRID(xTemp, yTemp).color)
checkLine( GRID(x, y), dx[i], dy[i], GRID(x,y).color)
}
}
}
第4步: checkLine(Grid, xOrigin, yOrigin, dx, dy)
现在我们只需检查一行,看看我们是否连续4行。
boolean checkLine(GRID, x, y, dx, dy, color) {
for(int i = 0; i < 4; i++)
if( GRID(x + dx*i, y + dy*i) != color) return false;
return true;
}
第5步:最后我们需要设置胜利者。这只是检查checkLine()
的结果。
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
if( GRID(x, y) == EMPTY) continue;
for(int i = 0; i < dx.length; i++) {
int xTemp = x + dx[i];
int yTemp = y + dy[i];
if( GRID(x, y).color == GRID(xTemp, yTemp).color) {
if( checkLine( GRID(x, y), dx[i], dy[i], color) ) {
winner = color;
return;
}
}
}
}
}
P.S 对于所有这些伪代码,您需要处理网格上的索引越界。我把它留下来以减少混乱。
P.P.S 我使用GRID(x, y)
来表示网格上的x,y或行,列对。这可以很容易地用2D阵列代替。同样,这只是伪代码,所以我使用GRID(x, y)
来表示清晰。