2012-03-31 12 views
7

Sto provando a codificare un algoritmo che crea una scheda Sudoku legale in Java o Javascript. Né funzionano, e non sono del tutto sicuro del perché.Soluzione ricorsiva al generatore di sudoku

In sostanza, il problema in entrambi i programmi è che xey viene incrementato più del dovuto (saltando il quadrato). Non posso per la vita di me capire come sta succedendo. Posso fornire l'HTML che completa la soluzione JS, se necessario.

La mia ipotesi migliore è che ha a che fare con il modo che ho creato uno stack utilizzando la ricorsione, ma per quanto ne so, è dovrebbe lavoro. Nel mio vecchio codice c'era un ciclo errato, ne sono consapevole. Ho incollato una vecchia versione, ora è riparata.

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

inserisce il codice in questione, invece di un pastebin. –

risposta

1

Java:

  1. Si dovrebbe inizializzare la variabile board, si consiglia di inizializzare in un costruttore:

    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. credo che il vostro iteratore ciclo nella funzione nextBoard è sbagliato:

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

    Penso che si desidera iterare da 0 a 9.

  3. Nella funzione nextBoard, è inoltre necessario controllare la variabile:

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

    Si ottiene un java.lang.ArrayIndexOutOfBoundsException, si dovrebbe inizializzarlo da 0 a 8, altrimenti si tenta di accedere alla riga numero 9 della scheda e si ottiene un errore di runtime.

  4. Un altro problema che è necessario risolvere è che x è impostato su nove nella funzione nextBoard(). Chiama la funzione nextBoard(int x, int y) "manualmente" con questi parametri: nextBoard(7,3) e capirai perché x è impostato su nove. Controllare specificamente i valori della variabile nextX.

Credo che sarà davvero aiutare se si utilizza un debugger di controllare questo tipo di errori, here si ha un bel tutorial con una spiegazione video (nel caso in cui si sta usando l'IDE Eclipse).

Spero che aiuti.

+0

Prova a verificare questi errori e quindi pubblica una domanda più specifica. –

+0

Ho già corretto questi errori. Come ho detto, quello era il vecchio codice. Se vuoi spiegare come x e/o y si stanno impostando su nove, sarebbe fantastico! – SomeKittens

+0

Perfect @SomeKittens. Ho aggiornato la mia domanda ora, spero che aiuti. –

1

Java:

tuo iteratore ciclo nella gamma nextBoard da 1 a 9. Non credo che volevi dire questo. Lo stesso nella funzione legalMove .... inizializzare cornerX e Cornery a 0.

+0

Whoops, sembra che abbia incollato una vecchia versione del mio codice. Lo aggiusterò. – SomeKittens

0

Gli indici di array Java sono a base zero.In nextBoard si esegue il ciclo su 1..9 per i e lo si utilizza come indice in toCheck, che salterà il primo elemento all'indice 0 e passerà oltre la fine dell'array. Ciò genererà ArrayIndexOutOfBoundsException se la riga contenente toCheck[i] viene raggiunta con i uguale a 9.

+0

L'ho risolto, ma il problema esiste ancora. Sembra che x e/o y siano impostati su nove in qualche modo, e non so perché. – SomeKittens

4

Nel codice Java: sarò tradurre al psuedocodarlo:

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 

Ma cosa succede se non si può mettere un qualsiasi numero lì come si finisce per essere illegale (aka una scheda in cui si puo' t inserire un numero in un quadrato specifico)?

Non si rivolgono a questo. Quello che dovete fare è implementare tramite backtracking:

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

Vedo cosa stai facendo lì, e capisco. Pensavo di averlo già gestito usando una pila ricorsiva. Se il quadrato P era legale a 4, allora passava al punto Q, dove nulla era legale, la ricorsione non sarebbe tornata a P e poi provata a 5? – SomeKittens

+0

Non sarebbe - non hai parte nel codice che fa il backtracking. Il cuore del problema è una decisione: se ha funzionato, bello, altrimenti, prova la prossima opzione. Non hai una clausola per gestire "e se la mia ipotesi fosse legale, ma non posso risolverlo da lì?" - che in pratica significa che è necessario salvare la scheda corrente, provarla con la prima ipotesi legale, e se non c'è soluzione, trattarla come se fosse un'ipotesi errata – user1304831

+0

Ho apportato le modifiche suggerite e il problema persiste. Ancora non capisco perché, dopo una chiamata ricorsiva fallita, la funzione smetta di funzionare. – SomeKittens

1

interessante domanda, ho appena notato questo bug nel codice Java: non è la chiamata a Collection.shuffle() inutile in quanto la matrice tocheck rimarrà non modificato (non mescolato) dopo questa chiamata? Qui è la mia soluzione rapida (e sono sicuro che ci sono modi più intelligenti per farlo):

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

Wow, che esplosione del passato. Hai ragione, l'abbiamo scoperto mentre mi presentavo davanti alla classe. Imbarazzante. – 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

Si prega di aggiornare la risposta precedente, piuttosto che creare una risposta completamente nuova. – Jesse

Problemi correlati