Java 数独生成器的递归解法

Java 数独生成器的递归解法,java,javascript,backtracking,sudoku,Java,Javascript,Backtracking,Sudoku,我试图编写一个算法,用Java或Javascript创建合法的数独板。两者都不起作用,我也不完全确定原因 从本质上讲,这两个程序中的问题是,x或y的增量超过了它应该增加的量(跳过平方)。我一辈子都搞不清楚这是怎么回事。如果需要,我可以提供完成JS解决方案的HTML 我最好的猜测是它与我如何使用递归创建堆栈有关,但据我所知,它应该可以工作。 在我的旧代码中有一个不正确的for循环,我知道这一点。我粘贴了一个旧版本,现在已经修复了 爪哇: import java.util.*; public cl

我试图编写一个算法,用Java或Javascript创建合法的数独板。两者都不起作用,我也不完全确定原因

从本质上讲,这两个程序中的问题是,x或y的增量超过了它应该增加的量(跳过平方)。我一辈子都搞不清楚这是怎么回事。如果需要,我可以提供完成JS解决方案的HTML

我最好的猜测是它与我如何使用递归创建堆栈有关,但据我所知,它应该可以工作。 在我的旧代码中有一个不正确的for循环,我知道这一点。我粘贴了一个旧版本,现在已经修复了

爪哇:

import java.util.*;

public class SudokuGenerator
{
//credit:cachao
//http://stackoverflow.com/questions/9959172/recursive-solution-to-sudoku-generator
public static final int BOARD_WIDTH = 9;
public static final int BOARD_HEIGHT = 9;

public SudokuGenerator() {
    board = new int[BOARD_WIDTH][BOARD_HEIGHT];
}
//Recursive method that attempts to place every number in a square
public int[][] nextBoard()
{
    nextBoard(0,0);
    return board;
}

public void nextBoard(int x, int y)
{
    int nextX = x;
    int nextY = y;
    //int[] toCheck = Collections.shuffle(Arrays.asList({1,2,3,4,5,6,7,8,9}));
    int[] toCheck = {1,2,3,4,5,6,7,8,9};
    Collections.shuffle(Arrays.asList(toCheck));

    for(int i=0;i<toCheck.length;i++)
    {
        if(legalMove(x, y, toCheck[i]))
        {
            board[x][y] = toCheck[i];
            if(x == 8)
            {
                if(y == 8)
                    break;//We're done!  Yay!
                else
                {
                    nextX = 0;
                    nextY++;
                }
            }
            else
            {
                nextX++;
            }
            nextBoard(nextX, nextY);
        }
    }
    board[x][y] = 0;
}

public boolean legalMove(int x, int y, int current) {
    for(int i=0;i<9;i++) {
        if(current == board[x][i])
            return false;
    }
    for(int i=0;i<9;i++) {
        if(current == board[i][y])
            return false;
    }
    int cornerX = 0;
    int cornerY = 0;
    if(x > 2)
        if(x > 5)
            cornerX = 6;
        else
            cornerX = 3;
    if(y > 2)
        if(y > 5)
            cornerY = 6;
        else
            cornerY = 3;
    for(int i=cornerX;i<10 && i<cornerX+3;i++)
        for(int j=cornerY;j<10 && j<cornerY+3;j++)
            if(current == board[i][j])
                return false;
    return true;
}

public void print()
{
    for(int i=0;i<9;i++)
    {
        for(int j=0;j<9;j++)
            System.out.print(board[i][j] + "  ");
        System.out.println();
    }
}

public static void main(String[] args)
{
    SudokuGenerator sg = new SudokuGenerator();
    sg.nextBoard();
    sg.print(); 
}
int[][] board;
}
import java.util.*;
公共级数独发生器
{
//信用:卡超
//http://stackoverflow.com/questions/9959172/recursive-solution-to-sudoku-generator
公共静态最终int板_宽度=9;
公共静态最终内板高度=9;
公共数独生成器(){
线路板=新的整数[线路板宽度][线路板高度];
}
//尝试将每个数字放在一个正方形中的递归方法
public int[]nextBoard()
{
下一个板(0,0);
返回板;
}
下一块板上的公共空白(整数x,整数y)
{
int-nextX=x;
int-nextY=y;
//int[]toCheck=Collections.shuffle(Arrays.asList({1,2,3,4,5,6,7,8,9}));
int[]toCheck={1,2,3,4,5,6,7,8,9};
Collections.shuffle(Arrays.asList(toCheck));
对于(int i=0;i 2)
如果(y>5)
y=6;
其他的
cornerY=3;
对于(var i=cornerX;iJava:

你的循环迭代器在nextBoard中的范围是1到9。我想你不是这个意思。函数legalMove中也是如此……将cornerX和cornerY初始化为0。

Java:

  • 您应该初始化
    变量,您可能需要在构造函数中初始化它:

    public class SudokuGenerator {
    
        public static final int BOARD_WIDTH = 9;
        public static final int BOARD_HEIGHT = 9;
    
        public SudokuGenerator() {
            board = new int[BOARD_WIDTH][BOARD_HEIGHT];
        }
    }
    
  • 我认为函数nextBoard中的循环迭代器是错误的:


    用于(int i=1;i在Java数组中,索引是从零开始的。在
    nextBoard
    中,您将
    1..9
    循环到
    i
    中,并将其用作
    中的索引来检查
    ,这将跳过索引
    0
    处的第一个元素,并超过数组的末尾。如果行包含ng
    toCheck[i]
    在Java代码中,当
    i
    等于
    9

    时达到: 我将把它翻译成psuedocode:

    for all z values:
        If for current (x,y), the number 'z' is legal then:
            insert z to current (x,y)
            if finished
                hooray!
            else 
                go to next square
        else try next number
    
    但是,如果你不能把任何数字放在那里,因为它最终是非法的(也就是一块你不能在一个特定的方块中插入任何数字的板),那该怎么办

    您不需要解决这个问题。您需要做的是通过回溯实现它:

    for all z values:
        If for current (x,y) the number 'z' is legal then:
            insert z to current (x,y)
            go to next(x,y)
                try to complete the board    // recursive call
            if you completed the board       // == the result of the recursion is legal
                return the completed board
        If all z values have been attempted
            return "cannot complete board"
        increment z, try again with current (x,y)
    

    有趣的问题是,我刚刚注意到Java代码中有一个bug:调用Collection.shuffle()是否没有用,因为toCheck数组在调用后将保持未修改(未缓冲)状态?下面是我的快速修复方法(我相信还有更聪明的方法):

    List lst=Arrays.asList(1,2,3,4,5,6,7,8,9);
    收藏。洗牌(lst);
    对于(inti=0;i
    import java.io.File;
    导入java.io.FileNotFoundException;
    导入java.util.array;
    导入java.util.Scanner;
    导入java.util.logging.Level;
    导入java.util.logging.Logger;
    公共级SudokuNrupen{
    公共静态int[][]p;
    公共静态int tmp[];
    公共静态int tmp2D[]];
    公共静态void main(字符串[]args){
    tmp=新整数[9];
    tmp2D=新整数[3][3];
    p=新整数[9][9];
    System.out.print(“在下面输入文件名”);
    扫描仪扫描=新扫描仪(System.in);
    字符串名称=scan.nextLine();
    文件文件=新文件(名称);
    如果(file.exists()){
    试一试{
    扫描仪内嵌=新扫描仪(文件);
    
    对于(int i=0;iWhoops,看起来我粘贴了一个旧版本的代码。我会解决这个问题。把代码放在问题中,而不是放在粘贴箱中。我知道你在那里做什么,我明白了。我以为我已经通过使用递归堆栈来处理了。如果平方P在4是合法的,那么就转到平方Q,那里没有任何东西是合法的,递归不是回到P,然后在5处尝试它?它不会-你没有参与回溯的代码。问题的核心是一个决定:如果它有效,很好,否则,尝试下一个选项。你没有一个条款来处理“如果我的猜测是合法的,但我不能从那里解决它怎么办?”-这基本上意味着您需要保存当前电路板,在第一次合法猜测的情况下尝试,如果没有解决方案,请将其视为错误的猜测。我已经做了您建议的更改,但问题仍然存在。我仍然不完全理解为什么在递归调用失败后,函数停止运行。您需要对ac进行递归调用除了x和y值、数字和要处理的电路板。这样,您只需发送一个带有合法猜测的电路板的.clone()(例如,如果失败,将平方0标记为-1)。首先执行结束条件,然后在开始时进行迭代(如果x==8,然后尝试x==0和y++,等等),然后执行类似于:int[][]board=对下一个x,y使用this.clone()进行递归调用…如果board[0][0]==-1,递归调用并递增值尝试检查此错误,然后发布一个更具体的问题。我已经修复了这些错误。正如我所说,这是旧代码。如果您想解释x和/或y如何设置为9,那就太好了!完美@SomeKittens。我现在更新了我的问题,希望它有帮助。我已经修复了,但e问题仍然存在。看起来x和/或y不知何故被设置为9,我不知道为什么。哇,这是过去的一次爆炸。你是对的,当我在全班面前演示时,我们发现了这一点。令人尴尬。请更新你以前的答案,而不是创建一个全新的答案。
    for all z values:
        If for current (x,y) the number 'z' is legal then:
            insert z to current (x,y)
            go to next(x,y)
                try to complete the board    // recursive call
            if you completed the board       // == the result of the recursion is legal
                return the completed board
        If all z values have been attempted
            return "cannot complete board"
        increment z, try again with current (x,y)
    
    List<Integer> lst = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    Collections.shuffle(lst);
    for (int i=0; i<lst.size(); i++)
        toCheck[i] = lst.get(i);
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.util.Arrays;
    import java.util.Scanner;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    
    public class SudokuNrupen {
    
         public static int[][] p;
         public static int tmp[] ;
         public static int tmp2D[][] ;
    
    
        public static void main(String[] args){
    
            tmp = new int[9];
            tmp2D = new int[3][3];
            p = new int[9][9];
    
             System.out.print("Enter the name of he file below ");
             Scanner scan = new Scanner (System.in);
             String name = scan.nextLine();
             File file = new File( name );
    
             if ( file.exists()){   
                try {
                    Scanner inFile = new Scanner( file );
                    for(int i=0; i<9; i++){
                         for(int j=0; j<9; j++){
                             if(inFile.hasNextInt()){
                                 p[i][j] = inFile.nextInt();
                             }
                         }
                     }   
                inFile.close();
                } catch (FileNotFoundException ex) {
                    Logger.getLogger(SudokuNrupen.class.getName()).log(Level.SEVERE, null, ex);
                }
           }
    
          display(p);
          solve(p);
          System.out.println("Solved Sudoku is:");
          display(p);      
    
    
         }
    
         public static void display(int [][] p)
        {
            for(int i=0; i<p.length;i++)
            {
                for(int j=0; j<p[i].length;j++)
                {
                    System.out.print("   ");
                    if(p[i][j]<10)     System.out.print(p[i][j] + " ");
                    else                    System.out.print(p[i][j]);
                    System.out.print("  ");
                }
                System.out.println();
            }    
        }  
    
        public static boolean solve(int [][] p)
        {
            if(!isValidSudoku(p))
            {
                 return false;
            }
            if(isComplete(p)==true)
            {
                return true;
            }
            for(int i=0; i<9; i++)
            {
                for(int j=0 ; j<9 ; j++)
                {
                    if(p[i][j]==0) 
                    {
                        int k=1;
                        while(k<=9)
                        {
                            p[i][j]=k;
                            if(solve(p))
                            {
                                return true;
                            }
                            else    k++;
                        }    
                        p[i][j]=0; 
                        return false; 
                    }
                }
            }
            return true;
        }
    
    
        public static boolean isComplete(int [][]p)
        {
            for(int i=0; i<9; i++)
            {
                for(int j=0 ; j<9 ; j++)
                {
                    if(p[i][j]==0){
                        return false;
                    }
                }
            }
            return true;
        }    
    
    
        public static boolean isRepeated(int [] a)
        {
            for(int i=0; i<8; i++)
            {
                if((a[i]!=0 || a[i+1]!=0))
                {
                         if(a[i]==a[i+1]){
                             return true;
                         }
                }  
            }
            return false;    
        }
    
    
     public static boolean isDuplicateEx0(int [][]p)
        {
    
            for(int i=0; i<p[0].length; i++)
            {
                for(int j=0 ; j<9 ; j++)
                {
                    tmp[j]=p[i][j];
                }
                Arrays.sort(tmp);
    
                System.out.println(Arrays.toString(tmp));
    
                if(isRepeated(tmp)==true)
                {
                    System.out.println("Duplicates are found in row");
                    return true;
                }
    
            }
    
            display(p);
            for(int j=0; j<p[0].length; j++)
            {
                for(int i=0 ; i<9 ; i++)
                {
                    tmp[i]=p[i][j];
                }
                Arrays.sort(tmp);
    
                if(isRepeated(tmp)==true)
                {
                    System.out.println("Duplicates are found in columns");
                    return true;
                }
    
            }
    
            display(p);
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
    
            int x=0,y=0;
    
            for(int i=0; i<3;i++)
            {   
                y=0;
                for(int j=0;j<3;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=0; i<3;i++)
            {   
                y=0;
                for(int j=3;j<6;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=0; i<3;i++)
            {   
                y=0;
                for(int j=6;j<9;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=3; i<6;i++)
            {   
                y=0;
                for(int j=0;j<3;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=3; i<6;i++)
            {   
                y=0;
                for(int j=3;j<6;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=3; i<6;i++)
            {   
                y=0;
                for(int j=6;j<9;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=6; i<9;i++)
            {   
                y=0;
                for(int j=0;j<3;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=6; i<9;i++)
            {   
                y=0;
                for(int j=3;j<6;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
            for(int z=0;z<9;z++){
                tmp[z]=0;
            }
            x=0;
            y=0;
    
            for(int i=6; i<9;i++)
            {   
                y=0;
                for(int j=6;j<9;j++)
                {
                    tmp2D[x][y]=p[i][j];
                    y++;
                }
                x++;
            }
            for(int i=0; i<3; i++)
            {
                for(int j=0; j<3; j++)
                {
                    tmp[(i*tmp2D.length) + j] = tmp2D[i][j];
                }
            }
            Arrays.sort(tmp);
            if(isRepeated(tmp)==true)
            {
                return true;
            }
    
    
            return false;
        }
    
    
    
         public static boolean isValidSudoku(int [][] p)
         {
               return (!isDuplicateEx0(p));  
         }
    }