2012-03-31 10 views
7

Ich versuche, einen Algorithmus zu programmieren, der eine legale Sudoku-Karte in Java oder Javascript erstellt. Keine Arbeit, und ich bin mir nicht ganz sicher warum.Rekursive Lösung für Sudoku-Generator

Im Wesentlichen besteht das Problem in beiden Programmen darin, dass entweder x oder y mehr inkrementiert wird, als es sein sollte (das Quadrat überspringend). Ich kann nicht für das Leben von mir herausfinden, wie dies geschieht. Ich kann den HTML-Code bereitstellen, der die JS-Lösung bei Bedarf vervollständigt.

Meine beste Vermutung ist es hat damit zu tun, wie ich einen Stapel mit Rekursion erstellt habe, aber soweit ich das beurteilen kann, sollte arbeiten. In meinem alten Code gab es eine falsche for-Schleife, ich bin mir dessen bewusst. Ich habe eine alte Version eingefügt, jetzt ist es behoben.

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

Setzen Sie den Code in der Frage statt einem Pastebin. –

Antwort

1

Java:

  1. Sie sollten Ihre board Variable initialisieren, können Sie es in einem Konstruktor initialisieren möchten:

    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. ich glaube, dass Ihre Schleife Iterator in der Funktion nextBoard es ist falsch:

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

    Ich denke, dass Sie von 0 bis 9.

  3. In der Funktion nextBoard iterieren möchten, müssen Sie auch die Variable überprüfen:

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

    Sie eine java.lang.ArrayIndexOutOfBoundsException erhalten, sollten Sie initialisiere es von 0 bis 8, sonst versuchst du auf die board row number 9 zuzugreifen und bekommst einen Laufzeitfehler.

  4. Ein weiteres Problem, das Sie lösen müssen, ist, dass x in der Funktion nextBoard() auf neun gesetzt wird. Rufen Sie die Funktion nextBoard(int x, int y) "manuell" mit diesen Parametern auf: nextBoard(7,3) und Sie werden verstehen, warum x auf neun gesetzt wird. Überprüfen Sie speziell die Werte der Variablen nextX.

Ich glaube es wird Ihnen wirklich helfen, wenn Sie eine debugger verwenden diese Art von Fehler zu überprüfen, here Sie haben ein schönes Tutorial mit einem Video Erklärung (falls Ihr die Eclipse-IDE verwenden).

Ich hoffe, es hilft.

+0

Versuchen Sie, diese Fehler zu überprüfen und stellen Sie dann eine spezifischere Frage. –

+0

Ich habe diese Fehler bereits behoben. Wie ich schon sagte, das war alter Code. Wenn du erklären möchtest, wie x und/oder y auf neun gesetzt werden, wäre das großartig! – SomeKittens

+0

Perfekt @SomeKittens. Ich habe meine Frage jetzt aktualisiert, ich hoffe, es hilft. –

1

Java:

Ihre Schleife Iterator in nextBoard Bereich von 1 bis 9. Ich glaube nicht, dass Sie das bedeutete. Gleiche in der Funktion legalMove .... initialisieren cornerX und Cornery auf 0

+0

Whoops, sieht so aus, als hätte ich eine alte Version meines Codes eingefügt. Ich werde das reparieren. – SomeKittens

0

In Java sind Array-Indizes nullbasiert.In nextBoard Sie Schleife über 1..9 für i und verwenden Sie es als Index in toCheck, die das erste Element bei Index 0 überspringt und über das Ende des Arrays gehen. Dadurch wird ArrayIndexOutOfBoundsException ausgelöst, wenn die Zeile toCheck[i] mit i gleich 9 erreicht wird.

+0

Ich habe das behoben, aber das Problem besteht immer noch. Es sieht so aus, als ob x und/oder y irgendwie auf neun gesetzt werden, und ich weiß nicht warum. – SomeKittens

4

Im Java-Code: Ich werde es psuedocode übersetzen:

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 

Aber was, wenn Sie nicht da eine beliebige Anzahl setzen kann, wie es (auch bekannt als ein Forum zu sein illegal landet wo man‘ t eine beliebige Zahl in ein bestimmtes Quadrat einfügen)?

Sie adressieren das nicht. Was Sie tun müssen, ist zu implementieren es über Rückzieher:

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

Ich sehe was du da machst, und ich verstehe. Ich dachte, ich hätte es bereits mit einem rekursiven Stack behandelt. Wenn Quadrat P bei 4 legal wäre, dann weiter zu Quadrat Q, wo nichts legal wäre, würde die Rekursion nicht zurück zu P gehen und es dann bei 5 versuchen? – SomeKittens

+0

Es würde nicht - Sie haben keinen Teil in dem Code, der Backtracking tut. Das Herz des Problems ist eine Entscheidung: Wenn es funktioniert, schön, ansonsten, versuchen Sie die nächste Option. Sie haben keine Klausel, um mit "Was ist, wenn meine Vermutung legal war, aber ich kann es von dort nicht lösen?" - was im Grunde bedeutet, dass Sie das aktuelle Board speichern müssen, versuchen Sie es mit der ersten rechtlichen Vermutung, und wenn es keine Lösung gibt, behandeln Sie es als ob es eine falsche Schätzung wäre – user1304831

+0

Ich habe die von Ihnen vorgeschlagenen Änderungen vorgenommen und das Problem besteht fort. Ich verstehe immer noch nicht ganz, warum nach einem fehlgeschlagenen rekursiven Aufruf die Funktion nicht mehr ausgeführt wird. – SomeKittens

1

interessante Frage, ich habe gerade bemerkt dies ein Fehler in der Java-Code: ist nicht der Aufruf an Collection.shuffle() nutzlos, da die toCheck Array bleiben unmodifiziert (nicht gemischt) nach diesem Aufruf? Hier ist meine schnelle Lösung (und ich bin sicher, es gibt mehr clevere Möglichkeiten, es zu tun):

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, was für eine Explosion aus der Vergangenheit. Du hast recht, wir haben das entdeckt, als ich mich vor der Klasse vorstellte. Peinlich. – 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

Bitte aktualisieren Sie Ihre vorherige Antwort, anstatt eine neue Antwort zu erstellen. – Jesse