【问题标题】:Java recursive sudoku solver, recursive function does not return correct valueJava递归数独求解器,递归函数不返回正确值
【发布时间】:2023-12-26 16:45:01
【问题描述】:

我正在使用数独求解器,但无法正确返回/结束求解器函数。 moveOn() 函数中的 show() 被调用,它显示已完成的数独,但求解返回 false。我试图在解决问题时让解决返回 true,在无法解决时返回 null,但不知道如何完成此操作。

L 是棋盘的长度(9 x 9 数独的 L = 9)

getSquare(r,c) 返回代表数独板的二维数组中的值

不同的检查功能检查一个值是否适合特定位置。他们不是问题。

show() 函数在控制台中打印出数组,因此它看起来像一个合适的数独板。

我还有一个isSolved() 函数来检查二维数组,如果它是一个有效的已解决数独,则返回 true,否则返回 false。我也尝试在 solve() 方法中实现这一点,希望使用它来返回 true,尽管没有成功

//This method's only purpose it to call the findNum function on the next location in the sudoku
public void moveOn(int row, int column) {
    //if the previous location was not the last in the row move to ne next cell in said row.
    //if it was the last location in the row, move to the first column of the next row
    if (column + 1 != L) {solve(row, column + 1);}
    else if (row + 1 != L) {solve(row + 1, 0);}
    else {show();}
}

//This method finds a valid number for a specific location on the sudoku grid\
public boolean solve(int row, int column) {
    if (row >= L) {return true;}
    //pass over any numbers that are not empty
    if (getSquare(row, column) != 0) {moveOn(row, column);}
    else {
        //attempt to find a valid number for the location
        for (int n = 1; n <= L; n++) {
            if (checkRow(row, n) && checkCol(column, n) && checkSquare(row, column, n)) {
                // If a number is allowed at a specific location set that location to the number
                setSquare(row, column, n);
                //Begin checking for a solution based on previous numbers changed           
                moveOn(row, column);
            }               
        }
        //If no number is allowed in this space backtrack to the last successful number 
        //changed and reset all locations that have been changed recursively
        setSquare(row, column, 0);          
    }
    //If the puzzle is unsolveable
    return false;
}

非常感谢任何可以帮助了解情况的人。 如果需要更多我的代码/信息,我很乐意提供

示例输入文件:http://pastebin.com/6mSKT3ES

编辑:删除完整代码

【问题讨论】:

    标签: java recursion backtracking sudoku solver


    【解决方案1】:

    solve 函数中只有一个return 语句,即

    return false;
    

    因为这是函数中的最后一条语句,并且无条件执行,solve 将,除非抛出异常,否则总是返回 false

    要获得一个实际告诉您是否找到解决方案的返回值,您需要使返回值取决于一个条件。此外,一旦你找到了解决方案,对于合适的谜题,继续搜索是没有意义的。

    所以你应该在搜索循环中添加一个条件return true;。为此,您需要知道何时找到了解决方案。您将递归包装在对moveOn 的中间调用中,因此最简单的更改是将返回值添加到moveOn

    public boolean moveOn(int row, int column) {
        //if the previous location was not the last in the row move to ne next cell in said row.
        //if it was the last location in the row, move to the first column of the next row
        if (column + 1 != L) {return solve(row, column + 1);}
        else if (row + 1 != L) {return solve(row + 1, 0);}
        else {show(); return true;}  // reached end of grid, solved
    }
    

    并在 `solve' 中使用它:

    public boolean solve(int row, int column) {
        //pass over any numbers that are not empty
        if (getSquare(row, column) != 0) {return moveOn(row, column);}
        else {
            //attempt to find a valid number for the location
            for (int n = 1; n <= L; n++) {
                if (checkRow(row, n) && checkCol(column, n) && checkSquare(row, column, n)) {
                    // If a number is allowed at a specific location set that location to the number
                    setSquare(row, column, n);
                    //Begin checking for a solution based on previous numbers changed           
                    if (moveOn(row, column)) {
                        return true;       // solved, yay!
                    }
                }               
            }
            //If no number is allowed in this space backtrack to the last successful number 
            //changed and reset all locations that have been changed recursively
            setSquare(row, column, 0);          
        }
        //If the puzzle is unsolveable
        return false;
    }
    

    【讨论】:

    • 我之前曾尝试过这种更改,并且存在编译错误,说明“函数 moveOn 必须返回布尔类型”即使返回语句在那里
    • 您是否也将return 添加到ifelse if 分支?我的函数确实在所有可能的代码路径中返回 boolean
    • 添加所有 3 个后,我又回到了原始问题。我添加了一个调试行System.out.println(Integer.toString(row)+Integer.toString(column)); 作为solve 函数的第一行,并注意到虽然它仍然调用show() 并显示板,但它在板显示后打印更多的调试行,然后仍然返回false。与我进行建议更改之前一样。
    • 这不应该发生。当然,我可能忽略了一些东西。我可以获取完整的代码来检查吗?
    • 谢谢。我也收到了if (getSquare(row, column) != 0) {moveOn(row, column);} 的回复。一旦找到解决方案,也需要立即停止它。
    【解决方案2】:
    This code works...
    
    import java.io.*;
    import java.util.Arrays;
    import java.util.Scanner;
    
    
    public class Sudoku {
    
        public static int suRows=9;
        public static int suColumns=9;
        public static int [][] suArray = new int[suRows][suColumns];
        public static int [] dummyRowArray = new int[suRows];
        public static int [] dummyColArray = new int[suColumns];
        public static int [][] dummy3x3Array = new int[3][3];
        public static int [] dummyArray = new int[9];
    
        //read the contents of the file into a 2 dimensional array
        public static void readSudoku() throws FileNotFoundException, IOException
        {  
            System.out.print("Please enter the full file name containing the Sudoku Puzzle (e.g:X:/sudoku_case1.txt):");
            Scanner scan = new Scanner (System.in);
            String filename = scan.nextLine();
            File file = new File( filename );
    
           if ( file.exists() )  
           {   
               Scanner inFile = new Scanner( file );
               for(int i=0; i<suRows; i++)
               {
                    for(int j=0; j<suColumns; j++)
                    {
                        if(inFile.hasNextInt())   suArray[i][j] = inFile.nextInt();
                    }
                }   
           inFile.close();
           }    
        }
    
        public static boolean inOrder(int [] a, int i, int j)
        {
            return a[i]<=a[j];
        }
    
        public static void swap(int [] a, int i, int j)
        {
            int tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }
    
    
        public static void exchangeSort(int [] a)
        {
            for(int i=0;i<a.length;i++)
            {
                for(int j=1;j<a.length-i;j++)
                {
                    if(!inOrder(a,j-1,j))    swap(a,j-1,j);
                }
            }
        }
    
        public static void displaySudoku(int [][] suArray)
        {
            for(int i=0; i<suArray.length;i++)
            {
                for(int j=0; j<suArray[i].length;j++)
                {
                    System.out.print(suArray[i][j]);
                    System.out.print(" ");
                }
                System.out.println();
            }    
        }    
    
        //Check if there are any more zeros
        public static boolean isComplete(int [][]suArray)
        {
            boolean result=true;
    
            //Check every element for 0
            for(int i=0; i<suArray[0].length; i++)
            {
                for(int j=0 ; j<suRows ; j++)
                {
                    if(suArray[i][j]==0) return false;
                }
            }
            System.out.println("There are no zeros in this Sudoku");
            return result;
        }    
    
    
        //Check for adjacent duplicates
        public static boolean isAdjacentDup(int [] a)
        {
            for(int i=1; i<a.length; i++)
            {
                if((a[i-1]!=0 || a[i]!=0))
                {
                         if(a[i-1]==a[i]) return true;
                }  
            }
            return false;    
        }
    
        //Check for 1 through 9
        public static boolean is1to9(int [] a)
        {
            int j=1;
            for(int i=0; i<a.length; i++)
            {
                if(a[i]==j) j++;
                else return false;
            }
            return true;    
        }
    
        public static boolean isDuplicate(int [][]suArray)
        {
            boolean result=false;
    
            //Check every row for duplicates
            for(int i=0; i<suArray[0].length; i++)
            {
                for(int j=0 ; j<suRows ; j++)
                {
                    dummyRowArray[j]=suArray[i][j];
                }
    
                //Sort dummyArray so that duplicates can be checked
                exchangeSort(dummyRowArray);
    
    
                //Now check Adjacent elements for duplicates
                if(isAdjacentDup(dummyRowArray)==true)
                {
                    System.out.println("Duplicates are found in row");
                    return true;
                }
    
            }
    
            displaySudoku(suArray);
    
            //Check every column for duplicates 
            for(int j=0; j<suArray[0].length; j++)
            {
                for(int i=0 ; i<suColumns ; i++)
                {
                    dummyColArray[i]=suArray[i][j];
                }
    
                //Sort dummyArray so that duplicates can be checked
                exchangeSort(dummyColArray);
    
    
                //Now check Adjacent elements for duplicates
                if(isAdjacentDup(dummyColArray)==true)
                {
                    System.out.println("Duplicates are found in columns");
                    return true;
                }
    
            }
    
            displaySudoku(suArray);
    
            System.out.println("3X3:");
    
            //Check every 3X3 matrix for duplicates
            // 1st block 
            if(is3x3Duplicate(suArray,0,3,0,3)==true)
            {
                System.out.println("1st Block has a duplicate");
                return true;
            }
            else System.out.println("1st Block has no duplicate");
            // 2nd block 
            if(is3x3Duplicate(suArray,0,3,3,6)==true)
            {
                System.out.println("2nd Block has a duplicate");
                return true;
            }
            // 3rd block 
            if(is3x3Duplicate(suArray,0,3,6,9)==true)
            {
                System.out.println("3rd Block has a duplicate");
                return true;
            } 
            // 4th block 
            if(is3x3Duplicate(suArray,3,6,0,3)==true)
            {
                System.out.println("4th Block has a duplicate");
                return true;
            } 
            // 5th block 
            if(is3x3Duplicate(suArray,3,6,3,6)==true)
            {
                System.out.println("5th Block has a duplicate");
                return true;
            } 
            // 6th block 
            if(is3x3Duplicate(suArray,3,6,6,9)==true)
            {
                System.out.println("6th Block has a duplicate");
                return true;
            } 
            // 7th block 
            if(is3x3Duplicate(suArray,6,9,0,3)==true)
            {
                System.out.println("7th Block has a duplicate");
                return true;
            } 
            // 8th block 
            if(is3x3Duplicate(suArray,6,9,3,6)==true)
            {
                System.out.println("8th Block has a duplicate");
                return true;
            } 
            // 9th block 
            if(is3x3Duplicate(suArray,6,9,6,9)==true)
            {
                System.out.println("9th Block has a duplicate");
                return true;
            } 
    
            return result;
        }
    
        //Check every3X3 grid for duplicates
        public static boolean is3x3Duplicate(int [][]suArray, int x1, int x2, int y1, int y2)
        {
            boolean result=false;
            int k=0, l=0;
    
            for(int i=x1; i<x2;i++)
            {   
                for(int j=y1;j<y2;j++)
                {
    
                    dummy3x3Array[k][l]=suArray[i][j];
                    l++;
                }
                l=0;
                k++;
            }
            displaySudoku(dummy3x3Array);   
    
            for(int i=0; i<dummy3x3Array.length; i++)
            {
                for(int j=0; j<dummy3x3Array.length; j++)
                {
                    dummyArray[(i*dummy3x3Array.length) + j] = dummy3x3Array[i][j];
                }
            }
    
            System.out.println(Arrays.toString(dummyArray));
    
            //Sort dummyArray so that duplicates can be checked
            exchangeSort(dummyArray);
    
    
    
            //Now check Adjacent elements for duplicates
            if(isAdjacentDup(dummyArray)==true)
            {
                System.out.println("Duplicates are found in blocks");
                return true;
            }
    
            return result;
        }
    
         //Check every3X3 grid for 1 trough 9
        public static boolean is3x3have1to9(int [][]suArray, int x1, int x2, int y1, int y2)
        {
            boolean result=false;
            int k=0, l=0;
    
            for(int i=x1; i<x2;i++)
            {   
    
                for(int j=y1;j<y2;j++)
                {
    
                    dummy3x3Array[k][l]=suArray[i][j];
                    l++;
                }
                l=0;
                k++;
            }
    
    
            for(int i=0; i<dummy3x3Array.length; i++)
            {
                for(int j=0; j<dummy3x3Array.length; j++)
                {
                    dummyArray[(i*dummy3x3Array.length) + j] = dummy3x3Array[i][j];
                }
            }
    
    
    
            //Sort dummyArray so that duplicates can be checked
            exchangeSort(dummyArray);
    
    
    
            //Now check Adjacent elements for duplicates
            if(is1to9(dummyArray)==false)
            {
                System.out.println("Block doe snot have 1 through 9");
                return false;
            }
    
            return result;
        }
    
    
    
        public static boolean isValidSudoku(int [][] suArray)
        {
          //  boolean result=true;
    
            //All nos should be between 0 and 9 
            for(int i=0; i<suArray.length; i++)
            {
                for(int j=0; j<suArray[i].length; j++)
                {
                        if(suArray[i][j]<0 || suArray[i][j]>9){
                            System.out.println("Nos in the puzzle are out of range");
                            return false;
                        }
                }
            }
    
            //Call teh isDuplicate function to check for duplicates in the rows
            if( isDuplicate(suArray)==true) return false;
    
            return true;
    
        }
    
        public static boolean isSolvedSudoku(int [][] suArray)
        {
             //Check every row for 1 to 9
            for(int i=0; i<suArray[0].length; i++)
            {
    
                for(int j=0 ; j<suRows ; j++)
                {
                    dummyRowArray[j]=suArray[i][j];
                }
    
    
                //Sort dummyArray so that duplicates can be checked
                exchangeSort(dummyRowArray);
    
    
    
                if(is1to9(dummyRowArray)==false)
                {
                    System.out.println("1 through 9 not present in rows");
                    return false;
                }
    
    
            } 
            //Check every column for 1 to 9
            for(int j=0; j<suArray[0].length; j++)
            {
    
                for(int i=0 ; i<suColumns ; i++)
                {
                    dummyColArray[i]=suArray[i][j];
                }
    
    
                //Sort dummyArray so that duplicates can be checked
                exchangeSort(dummyColArray);
    
    
    
                //Now check Adjacent elements for duplicates
                if(is1to9(dummyColArray)==false)
                {
                    System.out.println("1 through 9 not present in columns");
                    return false;
                }
    
            }
    
             //Check every 3X3 matrix for 1 through 9
            // 1st block 
            if(is3x3have1to9(suArray,0,3,0,3)==true)
            {
                System.out.println("1st Block does not contain 1 through 9");
                return false;
            }
            // 2nd block 
            if(is3x3have1to9(suArray,0,3,3,6)==true)
            {
                System.out.println("2nd Block does not contain 1 through 9");
                return false;
            }
            // 3rd block 
            if(is3x3have1to9(suArray,0,3,6,9)==true)
            {
                System.out.println("3rd Block does not contain 1 through 9");
                return false;
            } 
            // 4th block 
            if(is3x3have1to9(suArray,3,6,0,3)==true)
            {
                System.out.println("4th Block does not contain 1 through 9");
                return false;
            } 
            // 5th block 
            if(is3x3have1to9(suArray,3,6,3,6)==true)
            {
                System.out.println("5th Block does not contain 1 through 9");
                return false;
            } 
            // 6th block 
            if(is3x3have1to9(suArray,3,6,6,9)==true)
            {
                System.out.println("6th Block does not contain 1 through 9");
                return false;
            } 
            // 7th block 
            if(is3x3have1to9(suArray,6,9,0,3)==true)
            {
                System.out.println("7th Block does not contain 1 through 9");
                return false;
            } 
            // 8th block 
            if(is3x3have1to9(suArray,6,9,3,6)==true)
            {
                System.out.println("8th Block does not contain 1 through 9");
                return false;
            } 
            // 9th block 
            if(is3x3have1to9(suArray,6,9,6,9)==true)
            {
                System.out.println("9th Block does not contain 1 through 9");
                return false;
            } 
    
            return true;
        }
    
    
        public static boolean solveSudoku(int [][] s)
        {
            //Check if Valid
            if(isValidSudoku(suArray)==true) System.out.println("Sudoku is valid");
            else
            {
                System.out.println("Not valid!");
                return false;
            }
            //Check if Complete - No 0's in any place
            if(isComplete(suArray)==true)
            {
                System.out.println("Sudoku is Complete");
                return true;
            }
            else System.out.println("Sudoku is not Complete");
    
            //Check if solved - 1-9 present in every row, column and 3x3
            if(isSolvedSudoku(suArray)==true) System.out.println("Sudoku is Solved!");
            else System.out.println("Not Solved");   
    
            //Locate the first 0 in the Sudoko puzzle
            for(int i=0; i<suArray.length; i++)
            {
                for(int j=0 ; j<suArray[i].length ; j++)
                {
                    if(suArray[i][j]==0) 
                    {
                        System.out.println("0 found in location: " + i +"   " + j );
                        for(int k=1;k<10;k++)
                        {
                            suArray[i][j]=k;
                            System.out.println("New value assigned to Sudoku: " + k);
                            displaySudoku(suArray);
                            if(solveSudoku(suArray))// isValidSudoku(suArray))
                            {
                                displaySudoku(suArray);
                                System.out.println("New value assigned to Sudoku");
                                return true;
                            }
                        }    
    
                        suArray[i][j]=0; 
                        return false;  // remove this
                    }
                }
            }
    
            return true;
        }
    
    
    
        public static void main(String[] args) throws FileNotFoundException, IOException {
    
    
            readSudoku();
            displaySudoku(suArray);
    
            if( (isValidSudoku(suArray)!=true))
            {
                System.out.println("The given Sudoku Puzzle is not Valid!. Exiting....");
                System.exit(0);
            }
    
            do
            {
                if(isSolvedSudoku(suArray)==true)
                {
                    System.out.println("Sudoku is Completely Solved!");
    
                }
    
                if(solveSudoku(suArray)==true) 
                {
                    System.out.println("Sudoku is now solved");
    
                }
                else System.out.println("Not Complete");  
    
    
            }while(isSolvedSudoku(suArray)!=true);
    
            System.out.println("Sudoku is now completely solved:");
            displaySudoku(suArray);
    
    
        }
    }
    

    【讨论】:

      最近更新 更多