2012-03-31 39 views
7

Tôi đang cố gắng mã hóa một thuật toán tạo bảng Sudoku hợp pháp trong cả Java hoặc Javascript. Không làm việc, và tôi không hoàn toàn chắc chắn tại sao.Giải pháp đệ quy cho trình tạo Sudoku

Về cơ bản, vấn đề trong cả hai chương trình là x hoặc y đang tăng lên nhiều hơn mức cần thiết (bỏ qua hình vuông). Tôi không thể cho cuộc sống của tôi tìm ra cách điều này đang xảy ra. Tôi có thể cung cấp HTML hoàn thành giải pháp JS nếu cần.

Đoán tốt nhất của tôi là nó phải làm với cách tôi đã tạo một ngăn xếp bằng cách sử dụng đệ quy, nhưng theo như tôi có thể nói, nó nên hoạt động. Trong mã cũ của tôi có một vòng lặp không chính xác, tôi biết điều này. Tôi đã dán một phiên bản cũ, nó đã được sửa.

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

Đặt mã trong câu hỏi thay vì một pastebin. –

Trả lời

1

Java:

  1. Bạn nên khởi tạo biến board của bạn, bạn có thể muốn để khởi tạo nó trong một constructor:

    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. tôi tin rằng iterator vòng lặp của bạn trong hàm nextBoard nó là sai:

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

    Tôi nghĩ rằng bạn muốn lặp từ 0 đến 9.

  3. Trong chức năng nextBoard, bạn cũng cần phải kiểm tra các biến:

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

    Bạn nhận được một java.lang.ArrayIndexOutOfBoundsException, bạn nên khởi tạo nó từ 0 đến 8, nếu không bạn cố gắng truy cập vào hàng của bảng số 9 và bạn gặp lỗi thời gian chạy.

  4. Một vấn đề khác mà bạn cần giải quyết là x đang được đặt thành chín trong hàm nextBoard(). Gọi hàm nextBoard(int x, int y) "theo cách thủ công" với các tham số sau: nextBoard(7,3) và bạn sẽ hiểu tại sao x được đặt thành chín. Kiểm tra cụ thể các giá trị của biến số nextX.

Tôi tin rằng nó thực sự sẽ giúp bạn nếu bạn sử dụng một debugger để kiểm tra loại lỗi, here bạn có một hướng dẫn tốt đẹp với một lời giải thích video (trong trường hợp bạn đang sử dụng IDE Eclipse).

Hy vọng điều đó sẽ hữu ích.

+0

Hãy thử kiểm tra lỗi này và sau đó đăng câu hỏi cụ thể hơn. –

+0

Tôi đã sửa các lỗi này. Như tôi đã nói, đó là mã cũ. Nếu bạn muốn giải thích làm thế nào x và/hoặc y đang nhận được thiết lập đến chín, đó sẽ là tuyệt vời! – SomeKittens

+0

Perfect @SomeKittens. Tôi đã cập nhật câu hỏi của tôi bây giờ, tôi hy vọng nó sẽ giúp. –

1

Java:

iterator vòng lặp của bạn trong phạm vi nextBoard từ 1 đến 9. Tôi không nghĩ rằng bạn có nghĩa là. Cùng trong hàm legalMove .... khởi cornerX và cornerY để 0.

+0

Rất tiếc, có vẻ như tôi đã dán một phiên bản cũ của mã của mình. Tôi sẽ sửa nó. – SomeKittens

0

Trong các chỉ mục mảng Java là không dựa trên.Trong nextBoard bạn lặp qua 1..9 cho i và sử dụng nó làm chỉ mục thành toCheck sẽ bỏ qua phần tử đầu tiên tại chỉ mục 0 và đi qua cuối mảng. Điều này sẽ ném ArrayIndexOutOfBoundsException nếu dòng có chứa toCheck[i] được tiếp cận với i bằng 9.

+0

Tôi đã khắc phục điều đó, nhưng vấn đề vẫn tồn tại. Có vẻ như x và/hoặc y đang được thiết lập đến chín bằng cách nào đó, và tôi không biết tại sao. – SomeKittens

4

Trong đoạn mã Java: tôi sẽ dịch nó để 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 

Nhưng nếu bạn không thể đặt bất kỳ số lượng có khi nó kết thúc lên được bất hợp pháp (hay còn gọi là một bảng, nơi bạn có thể' t chèn bất kỳ số nào trong một hình vuông cụ thể)?

Bạn không giải quyết điều đó. Những gì bạn cần làm là thực hiện nó qua quay lui:

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

Tôi thấy những gì bạn đang làm ở đó và tôi hiểu. Tôi nghĩ rằng tôi đã xử lý nó bằng cách sử dụng một stack đệ quy. Nếu vuông P là hợp pháp tại 4, sau đó chuyển sang vuông Q, nơi không có gì là hợp pháp, sẽ không đệ quy di chuyển trở lại P và sau đó thử nó ở 5? – SomeKittens

+0

Nó sẽ không - bạn không có một phần nào trong mã không hoạt động ngược. Trung tâm của vấn đề là một quyết định: nếu nó hoạt động, tốt đẹp, nếu không, hãy thử tùy chọn tiếp theo. Bạn không có một điều khoản để xử lý "nếu dự đoán của tôi là hợp pháp, nhưng tôi không thể giải quyết nó từ đó?" - về cơ bản có nghĩa là bạn cần lưu bảng hiện tại, hãy thử với phán đoán pháp lý đầu tiên và nếu không có giải pháp, hãy coi nó như thể đoán sai – user1304831

+0

Tôi đã thực hiện các thay đổi bạn đề xuất và sự cố vẫn tiếp diễn. Tôi vẫn chưa hiểu rõ lý do tại sao, sau khi cuộc gọi đệ quy không thành công, chức năng này sẽ ngừng chạy. – SomeKittens

1

câu hỏi thú vị, tôi mới nhận ra một lỗi trong mã Java: không phải là cuộc gọi đến Collection.shuffle() vô dụng kể từ mảng toCheck sẽ vẫn unmodifed (unshuffled) sau cuộc gọi này? Dưới đây là sửa chữa nhanh chóng của tôi (và tôi chắc chắn rằng có những cách thông minh hơn để làm điều đó):

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

Ồ, một vụ nổ từ quá khứ. Bạn nói đúng, chúng tôi phát hiện ra rằng khi tôi đang trình bày trước lớp. Lúng túng. – SomeKittens

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

Vui lòng cập nhật câu trả lời trước của bạn, thay vì tạo câu trả lời hoàn toàn mới. – Jesse

Các vấn đề liên quan