如何在Java中验证数独谜题的有效性?

3
我正在尝试创建一个数独程序,以检查数独网格是否有效。我已经找到了如何检查每一行和每一列的有效性。然而,我正在努力编写代码来检查网格中的9个小方框之一。 以下是我尝试使用的方法来检查每个小方框。在小方格中,每个空间只能出现一个数字,否则该方法将返回false。
    public static boolean isValidSquare(int[][] grid, int i, int j) {
    int[][] square = new int[3][3];
    int row = 0; int column = 0;
    for (int x = i; x < i + 3; x++) {
        for (int y = j; y < j + 3; y++) {
            square[row][column] = grid[x][j];
            column++;
        }
        row++;
    }
    return true;
}

然而,当我运行它时,该方法始终返回true。我尝试将for循环中的条件分别更改为i + 2和j + 2,但仍然存在相同的问题。
还是与这段代码有关,它抛出到该方法中?
    for (int i = 0; i < grid.length; i += 3) {
        for (int j = 0; j < grid[i].length; j += 3) {
            if (isValidSquare(grid, i, j) == false)
                return false;
        }
    }

更新:刚刚测试了哪些方法有效,程序甚至没有到达ValidSquare部分,返回false的是Column方法:

    public static boolean isValidColumn(int[][] grid, int i) {
    for (int j = 0; j < grid[0].length - 1; j++) {
        for (int k = j; k < grid.length; k++) {
            if ((grid[j][i] < 1 || grid[j][i] > 9) || grid[j][i] == grid[k][i])
                return false;
        }
    }
    return true;

我无法弄清楚是什么原因导致它不断地声明为false,我打印并检查了每一列,看起来没问题。

编辑2:好吧,第一列只是因为我将k设置为j而不是j+1。关于子方格方法的另一个问题仍然困扰着我,因为它在'3'处抛出了OutOfBoundsException异常。


你说的“返回3”是什么意思?难道不应该是return true;吗? - WW.
为什么是grid[x][j]而不是grid[x][y]? 检查数字是否只出现了一次的测试在哪里?看起来你只是将3x3方格复制到一个数组中。你还应该在每一行的开头将列重置为零。 - samgak
4个回答

1
你的方法
public static boolean isValidSquare(int[][] grid, int i, int j) {
    int[][] square = new int[3][3];
    int row = 0; int column = 0;
    for (int x = i; x < i + 3; x++) {
        for (int y = j; y < j + 3; y++) {
            square[row][column] = grid[x][j];
            column++;
        }
        row++;
    }
    return true;
}

始终返回true。只有一个return语句。

还是与这段代码有关,它将抛出到方法中吗?

我不确定"throw"到方法是什么意思,但条件是

isValidSquare(grid, i, j) == false

基于之前的假设,这将永远不会成立。
我对这里的总体设计提出疑问:为什么 isValidSquare 是一个 static 函数呢?
为什么不创建一个数独网格的类,并提供设置数字、检查有效性等方法呢?
你的 static 方法适用于任何 int[][],包括那些不合法的数独网格。如果有一个良好封装的 SudokuGrid 类,你可以安全地假设内部的 private 数据结构已被正确地初始化和设置大小。例如,isValidSquare 愉快地接受一个 2x2 的 int 网格,这是不可取的。

1
你的代码中有一个拼写错误:

你的代码中有一个拼写错误:

public static boolean isValidSquare(int[][] grid, int i, int j) {
 int[][] square = new int[3][3];
 int row = 0; int column = 0;
 for (int x = i; x < i + 3; x++) {
     for (int y = j; y < j + 3; y++) {
         square[row][column] = grid[x][j]; // j should be y
         column++;
     }
     row++;
 }
return true;
}

我猜这就是它不能按你期望的执行的原因。
而且,正如其他人所说,你的方法从不返回false,因此它无法正常工作,但这是相当明显的。
我建议通过将其内容写入集合并在方法yourSet.add(number)返回false时返回false来验证小框的有效性。

不知怎么的,尽管我已经修复了拼写错误,并且该方法始终应该返回true,但是在程序中我仍然得到了false。 - Daveguy
您提供的代码(使用始终为真的方法)可以封装为 for (int i = 0; i < grid.length; i += 3) { for (int j = 0; j < grid[i].length; j += 3) { if (true == false) return false; } } 如您所见,此部分无法返回false,因此您的问题必须出现在其他地方,也许是父方法?*对于格式化不便,敬请谅解。 - fleczycki

1
< p > isValidSquare 的最大问题是你总是会 return true。即使对代码进行了粗略的查看,也找不到任何一行代码可以 return false


0

我想我理解了问题,并很高兴提供一些帮助,也许可以帮到你...希望如此。

我不能具体地说JavaScript,但我很久以前用C写过类似的程序。如果您将值存储在9x9数组中,则可以通过一些简单的乘法来完成此操作。

如果您认为-您有9个小块或正方形,每个块或正方形都是3x3,因此3是一个黄金数字。

我们可以将它们排列成行和列,就像这样:

    # # # | # # # | # # #
    # # # | # # # | # # #
    # # # | # # # | # # #
    ---------------------
    # # # | # # # | # # #
    # # # | # # # | # # #
    # # # | # # # | # # #
    ---------------------
    # # # | # # # | # # #
    # # # | # # # | # # #
    # # # | # # # | # # #

这将把它排列成需要检查的那些块,我们需要能够引用一个块,因此让我们给它们坐标 - 我们可以说我们整个数独网格是一个3x3的块网格。坐标-0,0引用左上角的块,1,0引用中上方的块,0,2引用右上角的块,等等...直到我们到达2,2,它引用右下角的块。

现在我们可以引用一个块,我们可以编写一个基本函数来循环遍历给定块中的每个值,例如...

/**
 * We can reference any block by setting row and col, for example:
 *
 *    check_block(grid, 0, 0);
 *
 * To reference the upper-left block, or:
 *
 *    check_block(grid, 2, 2);
 *
 * To reference the bottom-right block.
 */
function check_block(grid, row, col) {
    /**
     * We'll use x to index the elements of the horizontal row of a given
     * block, and y to index the elements of the vertical column.
     */
    var x, y;

    /**
     * We know each block is a 3x3 square - we can cycle through these
     * using a couple of nested loops...
     */
    for (y = 0; y < 3; y++) {
       for (x = 0; x < 3; x++) {
          /**
           * To index the digit within the block we simply multiply our
           * row with 3 and add it to y and our col with 3 and add that
           * to x...
           */
          grid[(y + (row * 3))][(x + (col * 3))] ...
       }
    }
}

如果你坐下来用笔和纸计算 - 假设我们想要检查第2行第2列的值。

由于每个块都是一个3x3的数组,而3是我们的黄金数字,将行(2)和列(2)乘以3,因此实际上我们正在引用单元格6,6。

因此,通过循环遍历3x3方块并添加x和y值,我们正在处理该个体块:

y = 0, x = 0      y = 0, x = 1      y = 0, x = 2
6,6               6,7               6,8

y = 1, x = 0      y = 1, x = 1      y = 1, x = 2
7,6               7,7               7,8

等等……抱歉讲得有点啰嗦,也不确定这是否有帮助。但这是一段很好的代码,对各种事情都很有用,包括数独格子。它可能与您现有的代码不完全匹配,但其背后的理论是可靠且非常实用的。

希望您从中获得一些有用的东西,并祝您编码顺利。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接