2012-03-31 97 views
7

我試圖編寫一個在Java或Javascript中創建合法Sudoku板的算法。既不工作,也不完全確定爲什麼。Sudoku生成器的遞歸解決方案

從本質上講,這兩個程序的問題是,要麼x或y增加超過它應該(跳過正方形)。我不能爲了我的生活而弄清楚這是怎麼發生的。如果需要,我可以提供完成JS解決方案的HTML。

我最好的猜測是它與我如何使用遞歸創建堆棧有關,但據我所知,它應該應該工作。 在我的舊代碼中有一個不正確的循環,我意識到這一點。我粘貼了一箇舊版本,現在已經修復。

的Java:

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; 
} 

的Javascript:

//Recursive method that attempts to place every number in a square 
function driver() 
{ 
    board = new Array(10); 
    for(var i=0;i<9;i++) 
     board[i] = new Array(10); 
    nextBoard(0,0); 
    print(); 
} 

function nextBoard(x, y) 
{ 
    var nextX = x; 
    var nextY = y; 
    for(var i=1;i<10;i++) { 
     console.log(y + " " + x + " " + i); 
     document.getElementById(y + " " + x).innerHTML = i; 
     if(legalMove(x, y, i)) { 
      board[x][y] = i; 
      if(x === 8) { 
       if(y === 8) 
        return board;//We're done! Yay! 
       else { 
        nextX = 0; 
        nextY++; 
       } 
      } 
      else 
       nextX++; 
      nextBoard(nextX, nextY); 
     } 
    } 
    //This is needed for legalMove to work, otherwise [x][y] == 9 
    board[x][y] = undefined; 
} 

function legalMove(x, y, current) { 
    for(var i=0;i<9;i++) { 
     if(current === board[x][i]) 
      return false; 
    } 
    for(var i=0;i<9;i++) { 
     if(current === board[i][y]) 
      return false; 
    } 
    var cornerX = 0; 
    var 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(var i=cornerX;i<10 && i<cornerX+3;i++) 
     for(var j=cornerY;j<10 && j<cornerY+3;j++) 
      if(current === board[i][j]) 
       return false; 
    return true; 
} 

function print() { 
    for(var i=0;i<9;i++) 
     for(var j=0;j<9;j++) 
     { 
      document.getElementById(i + " " + j).innerHTML = board[i][j]; 
      console.log(board[i][j]);   
     } 
} 

var board; 
+4

將代碼放在這個問題,而不是一個引擎收錄的。 – 2012-03-31 20:20:54

回答

1

的Java:

  1. 你應該初始化變量board,你可能想在構造函數初始化:

    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]; 
        } 
    } 
    
  2. 我相信,在你的函數循環迭代nextBoard這是錯誤的:

    for(int i=1;i<10;i++){ ... }

    我認爲你想從0迭代到9

  3. 在功能nextBoard,你還需要檢查變量:

    int[] toCheck = {1,2,3,4,5,6,7,8,9};

    你得到一個java.lang.ArrayIndexOutOfBoundsException,你應該將其初始化爲0到8,否則嘗試訪問電路板行號9並且出現運行時錯誤。

  4. 另一個需要解決的問題是x在nextBoard()函數中被設置爲9。使用這些參數調用函數nextBoard(int x, int y)「手動」:nextBoard(7,3)並且您將理解爲什麼x被設置爲9。具體檢查變量nextX的值。

我相信它會真正幫助你,如果你使用debugger檢查這種錯誤,here你有一個很好的教程,視頻的解釋(如果您正在使用Eclipse IDE)。

希望它有幫助。

+0

嘗試檢查此錯誤,然後發佈更具體的問題。 – 2012-03-31 20:35:21

+0

我已經修復了這些錯誤。就像我說的,那是舊代碼。如果你想解釋x和/或y是如何設定爲9,那太棒了! – SomeKittens 2012-03-31 20:56:58

+0

完美@SomeKittens。我現在已經更新了我的問題,我希望它有幫助。 – 2012-03-31 21:15:40

1

的Java:

在nextBoard範圍你的循環迭代從1到9,我不認爲你意味着。同樣在功能legalMove ....初始化cornerX和cornerY 0

+0

哎呀,看起來像我粘貼了我的代碼的舊版本。我會解決這個問題。 – SomeKittens 2012-03-31 20:06:04

0

在Java數組索引是從零開始的。在nextBoard中,您循環使用1..9獲取i,並將其用作toCheck的索引,該索引將跳過索引0上的第一個元素並超過數組的末尾。如果包含toCheck[i]的行與i等於9,則這將拋出ArrayIndexOutOfBoundsException

+0

我修復了這個問題,但問題仍然存在。它看起來像x和/或y以某種方式被設置爲9,並且我不知道爲什麼。 – SomeKittens 2012-03-31 20:57:39

4

在Java代碼: 我將它翻譯成僞代碼:如果你不能把任何數量那裏它最終被非法(又名板

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 

但是,在那裏你可以」 t在特定的正方形中插入任何數字)?

你不解決這個問題。你需要做的是通過回溯實現:

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) 
+0

我明白你在那裏做什麼,我明白了。我以爲我已經通過使用遞歸堆棧來處理它。如果平方P在4是合法的,然後移到方Q,那裏什麼都不是合法的,那麼遞歸會不會回到P然後在5處嘗試? – SomeKittens 2012-03-31 20:31:17

+0

它不會 - 你沒有參與回溯的代碼。問題的核心是一個決定:如果它工作的很好,否則,請嘗試下一個選項。你沒有條款來處理「如果我的猜測是合法的,但我無法從那裏解決呢?」 - 這基本上意味着您需要保存當前的棋盤,用第一個合法的猜測進行嘗試,如果沒有解決方案,請將其視爲錯誤的猜測 – user1304831 2012-03-31 20:37:04

+0

我已經做出了您所建議的更改並且問題仍然存在。我仍然不完全明白爲什麼在遞歸調用失敗後,函數停止運行。 – SomeKittens 2012-03-31 20:58:49

1

有趣的問題,我只注意到在Java代碼中這一個錯誤:不調用Collection.shuffle()沒用,因爲toCheck陣列將保持這個電話之後沒有改變(不加掩飾)?這裏是我的速戰速決(我敢肯定有更巧妙的方法來做到這一點):

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); 
+1

哇,從過去是一個什麼樣的爆炸。你是對的,我們發現,當我在課堂前展示時。尷尬。 – SomeKittens 2013-02-24 19:43:01

0
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)); 
    } 
} 
+0

請更新您以前的答案,而不是創建一個全新的答案。 – Jesse 2013-04-29 00:43:12