2

我有一个我正在编写的程序,它的工作原理是填充一个二维数组来检查获胜条件,它是 noughts 和 crosss,所以二维数组是在单击按钮时填充的,1 代表一个圆圈,2 代表一个交叉,那么 checkWin() 将按照这个原则工作,而不是实际的代码......

if (myArray[0][0] == 1 && myArray[0][1] == 1 && myArray[0][2] == 1){
    setBoolWinVal = true;
} else {
    if(myArray[0][0] == 2 && myArray[0][1] == 2 && myArray[0][2] == 2){
    setBoolWinVal = true;
}

您可以立即看到,对于每一个获胜条件,这都会很混乱,有没有办法重写这个获胜检查以缩短一点?

4

12 回答 12

7

这看起来像家庭作业,所以我不会完全放弃它。但请注意以下几点:

  • 当你在一行、一列或沿对角线上拥有三个相同的东西时,你就赢了。

  • 不是你需要检查一行中是否有三个零或三个十字,而是一行中是否有三个相同的东西

您可以从编写一个函数开始,该函数确定行、列或对角线是否具有三个相同类型的东西(并且那个东西不是空白单元格)。然后为每一行、每一列和对角线调用一次该函数。

于 2009-03-18T22:33:40.950 回答
3

这是(未经测试的)代码。这肯定不是生产质量:)

请注意其他答案的一些优化:

  1. for循环的使用
  2. 我们检查相同的玩家价值,而不是特定的玩家价值
  3. 对角线获胜必须通过单元格[1][1]

.

int find_winner(int[][] arr) {

    // check rows
    for (int i = 0; i < 3; ++i) {
        int player = arr[i][0];
        if (player < 1) continue; // nb: prior version didn't check for empty cells
        if (arr[i][1] == player && arr[i][2] == player) return player;
    }

    // check cols
    for (int i = 0; i < 3; ++i) {
        int player = arr[0][i];
        if (player < 1) continue;
        if (arr[1][i] == player && arr[2][i] == player) return player;
    }

    // check diagonals
    int player = arr[1][1];
    if (player < 1) return -1;

    if ((arr[0][0] == player && arr[2][2] == player) ||
        (arr[2][0] == player && arr[0][2] == player)) return player;

    // no winner found
    return -1;
}
于 2009-03-18T22:43:47.573 回答
2

显而易见的方法是循环遍历行、列或对角线中的 3 个元素并检查它们是否相同。

另一种方法是使用更紧凑的表示 - 例如,一个 int,其中 9 个单元由每个 2 位表示,或者两个短裤,每个玩家一个。然后使用查找表或按位运算来映射状态以输赢。

如果单个位表示一个单元格,并且您有一个填充位,则每个玩家的图块都是 3 个十六进制数字 0-7。

对角线是:

cells & 0x421 == 0x421
cells & 0x124 == 0x124

垂直线是:

cells & (cells>>4) & (cells>>8) != 0

水平线

cells & (cells>>1) & (cells>>2) != 0

使用 64 位模式使用类似的技术来表示国际象棋游戏中可能的移动。

于 2009-03-18T22:43:40.567 回答
1

两个有趣的想法:(我假设底层的一维数组,因为它让生活更轻松。)

第一:对要测试的位置进行编码。就像您有描述您的字段的一维数组一样:

diag[] = { { 0, 1, 2}, {3, 4, 5}, {6, 7, 8},
           { 0, 3, 6}, {1, 4, 7}, {2, 5, 8},
           { 0, 4, 8}, {6, 4, 2}};

然后遍历 diag: 对于其中的每个元素,测试三个相应的字段(diag[i]用作字段数组的索引)。

第二:使用位域来表示您的字段。像 java.util.BitSet。然后将解决方案编码为位域,如 {1, 1, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0} 等。然后你可以测试(循环) if (field & solution[i] == solution[i])。对于第二个玩家,只需!field在 if 语句中使用。

有趣,不是吗?ps:由你来制作工作的Java代码!

于 2009-03-18T22:45:19.800 回答
0

家庭作业的气味。

小提示 - 使用 for 循环,它适用于您想要的任何大小。如果您改用递归,则可以加分。

定义:递归 -> 参见递归

于 2009-03-18T22:36:43.080 回答
0

您也可以迭代地解决这个问题:

  1. 为每个列、行和对角线的每种类型的标记生成一个数组。初始化为零。
  2. 对于网格中的每个条目,如果它有一个标记,则为该标记增加相应的列、行和对角线条目。
  3. 如果这些条目中的任何一个等于棋盘的尺寸,则该标记获胜。
于 2009-03-19T04:22:46.243 回答
0

一个简单而优雅的解决方案 - 您可以通过以下方式将数字 1 到 9 分配给您的电路板:

8 1 6
3 5 7
4 9 2

这个正方形有一个独特的特点,即每行、每列和每对角线的总和为 15,并且除非 它们共享一行、列或对角线,否则无法从三个单元格中得到 15 的总和。

对于每个玩家,您保留两个布尔数组:

boolean squarePairs[PAIRSMAXSUM+1];
boolean chosenSquares[NUMSQUARES+1];

其中 PAIRSMAXSUM = 9+8 和 NUMSQUARES = 9

然后,您可以通过调用此函数轻松检查获胜动作:

boolean hasWon(int squareIndex) {
    return squarePairs[WINNINGSUM - squareIndex];
}

其中 WINNNINGSUM 为 15。如果该函数返回 false,则通过调用此函数来更新布尔数组:

void update(int squareIndex) {
    for (int i = 1; i <= NUMSQUARES; i++) {
        if (chosenSquares[i]) {     {
            squarePairs[i + squareIndex] = true;
        }
    }
    chosenSquares[squareIndex] = true;
}


就那么简单!

于 2009-03-19T04:35:43.233 回答
0

因此,如果您考虑一下,您正在检查以下条件:

www   xxx   xxx  wxx
xxx   www   xxx  xwx
xxx   xxx   www  xxw

ETC

其中 w 是要检查胜利的,而 x 是要忽略的。

(0,0),(0,1),(0,2) 是第一个正确解中“w”的位置。1,0、1,1 和 1,2 是第二个,以此类推。

这在我看来应该是数据而不是代码。诀窍是,如何有效地输入和存储数据。

请注意,此数据开始看起来像您的数组索引。

因此,假设您有一组“解决方案”,其中包含 8 个 x,y 对(每个都表示获胜的解决方案组合)

然后你所要做的就是遍历这个集合,提取三个 x,y 对并测试它们。所以它与你所拥有的类似,但在你有数字的地方使用变量。

if(myArray[x0][y0] == 2 && myArray[x1][y1] == 2 && myArray[x2][y2] == 2){
    win();

当您对其进行迭代时,索引变量将被您的数据的下一行替换。

由于您不想在获胜后报告损失,因此您将不得不稍微调整一下逻辑以确保您的循环停止,但这对于家庭作业式问题可能已经有太多帮助了。

于 2009-03-18T22:52:34.367 回答
0

这听起来确实有点像家庭作业,但我会帮助解决遍历行和列的简单问题,检查它们是否都已满,对角线稍微难一些,我把它留给你。同样,我相信嵌套的 for 循环将是最好的主意:

java.util.Arrays;

public yourClass{

public void findAnswer{

int initialVal = 0;

int copy = 0;

int column = 0;

boolean columnVal = true;

boolean rowVal = false;

for (int j = 0; j< myArray.length; j++){ //presuming myArray and myArray[] are same length

boolean firstRun = true;

    for (int i = 0; i <myArray.length; i++){

        initialVal = myArray[i][column];
        if (firstRun == true){
            copy = intialVal; //makes a copy for the first time, to compare
            firstRun = false;
        }
        if (intialVal != copy){
            columnVal = false; //realises this column isnt a full column i.e. 3 1's or 2's in column
            return;
        }else
            columnVal = true;

        }//end nested for loop

    rowVal = findRow(j); 
    if(rowVal = true)
    return;
}

public boolean findRow(int row){

    int[] tempRow1, tempRow2;
    Arrays.fill(tempRow1, 1); 
    Arrays.fill(tempRow2, 2); //fills temp arrays for comparison
    boolean answer = false;
    if (Arrays.equals(myArray[], tempRow1) || Arrays.equals(myArray[], tempRow2) //this tests either, || being logical OR
        answer = true;
    return answer;
}
}

注意这段代码没有测试,而且很快就编码了,所以看起来不太好,可以细化,我也没有实现对角线。ps 如果是家庭作业,最好在网上查资料,自己动手做,而不是找别人帮你做。

于 2009-03-19T01:41:38.673 回答
0
  1. 将 board 表示为 0..19683(第 3 到第 9)中的 int
  2. 预先生成获胜板并确定谁是每个板上的获胜者,也许是手动的
  3. 在运行时在您预先计算的地图中查找当前板
于 2009-03-19T02:11:23.050 回答
0

对于 n X n 矩阵...

//Check all horizontal rows
for(i=0; i<n && !setBoolWinVal; i++) //row
{
    setBoolWinVal = true;
    for(j=0; j<n-1; j++)
    {
        if( myArray[i][j] != myArray[i][j+1] ) //column
        {
            setBoolWinVal = false;
            break;
        }
    }

    if(setBoolWinVal) declareWinner(myArray[i][0]);
}

//Check all vertical columns
if(!setBoolWinVal)
{
    for(i=0; i<n && !setBoolWinVal; i++) //column
    {
        setBoolWinVal = true;
        for(j=0; j<n-1; j++) //row
        {
            if( myArray[j][i] != myArray[j+1][i] ) 
            {
                setBoolWinVal = false;
                break;
            }
        }
    }

    if(setBoolWinVal) declareWinner(myArray[0][i]);
}


//Check forward diagonal
if(!setBoolWinVal)
{
    setBoolWinVal = true;
    for(i=0; i<n-1; i++)
    {
        if( myArray[i][i] != myArray[i+1][i+1])
        {
            setBoolWinVal = false;
            break;
        }
    }

    if(setBoolWinVal) declareWinner(myArray[0][0]);
}

//Check reverse diagonal
if(!setBoolWinVal)
{
    setBoolWinVal = true;
    for(i=0, j=n-1; i<n-1 && j>0; i++, j--)
    {
        if( myArray[i][j] != myArray[i+1][j-1])
        {
            setBoolWinVal = false;
            break;
        }
    }

    if(setBoolWinVal) declareWinner(myArray[0][n-1]);
}
于 2009-03-19T03:46:49.607 回答
-1

如果数组的长度都相同,那么以下内容应该会有所帮助。

Arrays.equals(myArray[0], {1,1,1})

否则,编写一个循环遍历myArray[0].

于 2009-03-18T22:39:15.773 回答