rekursiver Aufruf (Sudoku und Guice)

freez

Top Contributor
Ich habe Guice mit einem Beispielprojekt testen wollen. Viele Hinweise aus diesem Forum sind dabei eingeflossen ... danke


Ich habe nun eine Frage zu meiner Methode [c]solveSudoku()[/c] ... ich bekomme sie nicht rekursiv gelöst ... die Anwendung beendet sich normal, ohne Exception, aber das Sudoku ist nicht gelöst.
Java:
@Override
	public void solveSudoku() {
		try {
			if(!solveNextField(1,1))
				System.out.println("konnte Spielfeld nicht lösen.");
		} catch (NumberNotAllowedException e) {
			e.printStackTrace();
		}
	}

	private boolean solveNextField(int row, int col) throws NumberNotAllowedException {
		System.out.println("solve row: " + row + "; col: " +col);
		if(spielfeld.getField(row, col) != null){
			if(row == 9 && col == 9)
				return true;
			
			int newcol = 0;
			int newrow = 0;
			if(col == 9){
				newcol = 1;
				newrow = row+1;
			} else {
				newcol = col+1;
				newrow = row;
			}
			return solveNextField(newcol,newrow);
		}
		
		
		for(int i = 1; i <=9; i++){
			System.out.println("versuche: " + i);
			boolean goOn;
			try {
				goOn = spielfeld.checkNumberAllowed(i, row, col);
				if(goOn)
					System.out.println("Nummer erlaubt: " + goOn);
				else
					System.out.println("Nummer NICHT erlaubt (try)");
			} catch (Exception e) {
				goOn = false;
				System.out.println("Nummer NICHT erlaubt (catch)");
			}
			

			if(goOn ){
				System.out.println("weiterschalten, da Nummer erlaubt ist");
				if(row == 9 && col == 9){
					spielfeld.setField(i, row, col);
					return true;
				}
				
				spielfeld.setField(i, row, col);
				
				
				int newcol = 0;
				int newrow = 0;
				if(col == 9){
					newcol = 1;
					newrow = row+1;
				} else {
					newcol = col+1;
					newrow = row;
				}
				

				return solveNextField(newcol,newrow);
			}
		}
		
		return false;
	}
 

Anhänge

  • sudoku.jar
    16,6 KB · Aufrufe: 6
S

SlaterB

Gast
wenn das jar hoffentlich Quellcode und eine main-Methode mit fertigen Test-Feld enthält ist das sicher eine schöne kleine Suchaufgabe,
ich habe noch nicht reingeschaut und frage vorher nach: ist das noch aktuell?

morgen dann vielleicht, falls es nicht gar zwischendurch wer anders macht, ob durch mein Erinnerungs-Posting oder Antwort darauf ;)
 

freez

Top Contributor
wenn das jar hoffentlich Quellcode und eine main-Methode mit fertigen Test-Feld enthält ist das sicher eine schöne kleine Suchaufgabe,

Ja, hätte ich auch eher drauf kommen können, dass die Info gut wäre:
Code:
java -classpath sudoku.jar;guice-3.0.jar;javax.inject.jar;aopalliance.jar freezly.test.googleGuice.sudoku.Main
Die guice3.0 jars nicht vergessen :) guice-3.0.zip - google-guice - Guice 3.0 - Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 5 and above, brought to you by Google. - Google Project Hosting

ich habe noch nicht reingeschaut und frage vorher nach: ist das noch aktuell?

Ja, ist es. Ich bin am WE nicht untätig gewesen und habe schon mal 2 Dinge raus gefunden: Kann das nächste Feld nicht gelöst werden, muss ich das aktuelle Feld wieder leeren, da sonst falsche Nummern stehen bleiben. Und es ist glaube ich eine gute Idee zuerst abzufragen, ob es das letzte Feld ist und diesen Fall gesondert abzuarbeiten. Dann sieht man eher, ob sich im letzten Feld noch ein weiteres
Code:
solveNextField()
versehentlich eingeschlichen hat ... beim letzten Feld darf das nicht passieren.
 
Zuletzt bearbeitet:

freez

Top Contributor
mach dir eine instanzvariable als boolean (solved o.ä), die du dann in zeile 14 setzt. dann gehst du den backtrack nur, wenn
Code:
!solved
. kannst auch hier mal reinschauen: http://www.java-forum.org/blogs/nrg/159-probieren-geht-ueber-studieren-backtracking.html

Danke für den Hinweis ... super Tutorial ... habe im Netz nach sowas gesucht und bin eher auf unpassende Seiten getroffen. Naja.

zu deinem Tipp: Dein Vorschlag geht einen etwas anderen Weg, als ich es mir das gedacht habe. Ich wollte im Feld 9/9 das erfolgreich gelöste Soduku erkennen und durch alle rekursiven Aufrufe den Erfolg zurück geben (durch den Rückgabewert). Sollte es nämlich an irgendeiner Stelle keine Lösung geben, wird ein false zurück gegeben, und das Feld davor versucht dann die restlichen Nummern.
Das aktuelle Feld soll somit anhand der eigenen Versuche eine Nummer zu setzen und des Erfolgs / Misserfolg des nächsten Feldes einen Erfolg erkennen. Somit weiß der erste Aufruf der Methode, ob das komplette Sudoku gelöst wurde, oder nicht.
 
S

SlaterB

Gast
das mit Guice ist doch nicht dein Ernst, oder?
für so ein Miniprogramm so kompliziert auf Libraries setzen?
auch Interface/ Impl mag ja an sich ne tolle Sache sein, hier für ein Miniprogramm ist das aber unnötig störend,

ich habe deinen Programmcode etwas zusammengefasst unten gepostet,
falls immer noch aktuell und ich da weitermachen soll, bitte vorher noch bisschen aktiv werden:

- ich habe alles guicige herausgenommen, wenn ein Field erzeugt werden soll passiert das jetzt 'normal' mit new Field(),
nicht so komisch newInstance von wer weißt wo,
allerdings läuft jetzt nicht mehr so viel, vielleicht meine Schuld beim Kürzen,

in der main-Methode von SpielfeldImpl steht nicht viel mehr als das Befüllen eines Feldes, wo wird denn solveSudoku() usw. aufgerufen?
selbst der Anfang läuft bei mir nicht besonders, egal ob ich die Füll-Schleife aus der main-Methode verwende
oder SpielConsole.generateFields() (doppelter Code?), immer kommt es zur NullPointerException,
das Hauptarray fields in Spielfeld ist null, wann soll das wer setzen?

- bisher wird mit Random gefüllt, die Wahl des Sodukos ist von 1x1 bis 9x9 variabel,
hast du nicht ein konkretes Beispiel mit ganz konkreter Problemsituation?
mit new Random(zahl als seed) kann man übrigens einen reproduzierbaren Zufallsverlauf erschaffen,
ansonsten vielleicht auch manuell ein Feld befüllen, so viele Werte sind es am Anfang ja nicht, oder?


edit: Code mit weiteren Änderungen von Folgeposts:
Java:
public class Test
{

    public static void main(String... args)
        throws NumberNotAllowedException
    {
        SpielConsole c = new SpielConsole();
        c.generateFields(30);
        c.showSpielfeld();
        c.solveSudoku();
        c.showSpielfeld();

    }

}


class Field
{
    int number;

    public int getNumber()
    {
        return number;
    }

    public void setNumber(int number)
        throws NumberNotAllowedException
    {
        if (number < 1 || number > 9) throw new NumberNotAllowedException("Nur Zahlen von 1-9 erlaubt (Wert:" + number + ")");
        this.number = number;
    }

}


class Spielfeld
{
    Field[][] fields = new Field[9][9];

    public Field getField(int row, int col)
        throws NumberNotAllowedException
    {

        if (row < 1 || row > 9) throw new NumberNotAllowedException("row ist Ausserhalb Bereich von 1-9 (Wert:" + row + ")");

        if (col < 1 || col > 9) throw new NumberNotAllowedException("column ist Ausserhalb Bereich von 1-9 (Wert:" + col + ")");

        return fields[row - 1][col - 1];
    }

    public Field[][] getSquare(int rowSqare, int colSquare)
        throws NumberNotAllowedException
    {

        if (rowSqare < 1 || rowSqare > 3)
            throw new NumberNotAllowedException("row ist Ausserhalb Bereich von 1-3 (Wert:" + rowSqare + ")");

        if (colSquare < 1 || colSquare > 3)
            throw new NumberNotAllowedException("column ist Ausserhalb Bereich von 1-3 (Wert:" + colSquare + ")");


        Field[][] square = new Field[3][3];
        for (int i = 0; i < square.length; i++)
        {
            int rowFromField = rowSqare * 3 - 3 + i;
            for (int j = 0; j < square[i].length; j++)
            {
                int colFromField = colSquare * 3 - 3 + j;
                square[i][j] = fields[rowFromField][colFromField];
            }
        }

        return square;
    }

    public void setField(int number, int row, int col)
        throws NumberNotAllowedException
    {
        if (row < 1 || row > 9) throw new NumberNotAllowedException("row ist Ausserhalb Bereich von 1-9 (Wert:" + row + ")");

        if (col < 1 || col > 9) throw new NumberNotAllowedException("column ist Ausserhalb Bereich von 1-9 (Wert:" + col + ")");

        if (number < 1 || number > 9)
            throw new NumberNotAllowedException("number ist Ausserhalb Bereich von 1-9 (Wert:" + number + ")");

        if (fields[row - 1][col - 1] != null)
            throw new NumberNotAllowedException("Feld bereits belegt (" + col + "/" + row + ") Wert:"
                                                + fields[row - 1][col - 1].getNumber());

        Field field = new Field();
        field.setNumber(number);
        fields[row - 1][col - 1] = field;

    }

    public boolean checkNumberAllowed(int number, int row, int col)
        throws NumberNotAllowedException
    {
        if (row < 1 || row > 9) throw new NumberNotAllowedException("row ist Ausserhalb Bereich von 1-9 (Wert:" + row + ")");

        if (col < 1 || col > 9) throw new NumberNotAllowedException("column ist Ausserhalb Bereich von 1-9 (Wert:" + col + ")");

        if (number < 1 || number > 9)
            throw new NumberNotAllowedException("number ist Ausserhalb Bereich von 1-9 (Wert:" + number + ")");

        if (fields[row - 1][col - 1] != null)
            throw new NumberNotAllowedException("Feld bereits belegt (" + col + "/" + row + ") Wert:"
                                                + fields[row - 1][col - 1].getNumber());


        // Horizontale und vertikale prüfen
        for (int i = 0; i < 9; i++)
        {

            // horizontale (Zeile) prüfen
            if (fields[row - 1][i] != null) if (fields[row - 1][i].getNumber() == number) return false;

            // vertikale (Spalte) prüfen
            if (fields[i][col - 1] != null) if (fields[i][col - 1].getNumber() == number) return false;

        }


        // Das Quadrat prüfen
        Field[][] square = this.getSquare((row - 1) / 3 + 1, (col - 1) / 3 + 1);
        for (int i = 0; i < square.length; i++)
            for (int j = 0; j < square[i].length; j++)
                if (square[i][j] != null) if (square[i][j].getNumber() == number) return false;

        // Alles Klar, ist erlaubt
        return true;
    }


}


class SpielConsole
{
    Spielfeld spielfeld = new Spielfeld();


    public void showSquare(int rowsquare, int colsquare)
        throws NumberNotAllowedException
    {
        Field[][] square = spielfeld.getSquare(rowsquare, colsquare);
        for (int i = 0; i < square.length; i++)
        {
            System.out.println();
            for (int j = 0; j < square[i].length; j++)
                System.out.print(square[i][j].getNumber() + "\t");
        }
    }

    public Spielfeld getSpielfeld()
    {
        return spielfeld;
    }

    public void showSpielfeld()
    {
        try
        {
            for (int i = 1; i <= 9; i++)
            {
                System.out.println();
                if (i % 3 == 1)
                    System.out.println("-------------------------");
                System.out.print("|");
                for (int j = 1; j <= 9; j++)
                {
                    String trenner;
                    if (j % 3 == 0)
                        trenner = " |";
                    else
                        trenner = "";
                    Field field = spielfeld.getField(i, j);
                    if (field == null)
                        System.out.print("  " + trenner);
                    else
                        System.out.print(" " + field.getNumber() + trenner);
                }
            }
            System.out.println();
            System.out.println("-------------------------");
        }
        catch (NumberNotAllowedException e)
        {
            e.printStackTrace();
        }
    }

    public Field getField(int row, int col)
        throws NumberNotAllowedException
    {
        return spielfeld.getField(row, col);
    }

    public void generateFields(int count)
        throws NumberNotAllowedException
    {
        if (count > (9 * 9)) throw new NumberNotAllowedException("count muss zwischen 1 und 81 liegen: count=" + count);
        Random rand = new Random();

        for (int i = 0; i < count; i++)
        {
            boolean success = false;
            int row = 0;
            int col = 0;
            int number = 0;
            while (!success)
            {
                row = rand.nextInt(8) + 1;
                col = rand.nextInt(8) + 1;
                number = rand.nextInt(8) + 1;

                try
                {
                    success = spielfeld.checkNumberAllowed(number, row, col);
                }
                catch (NumberNotAllowedException e)
                {
                    success = false;
                }
            }

            spielfeld.setField(number, row, col);
        }

    }

    public void solveSudoku()
    {
        try
        {
            if (!solveNextField(1, 1)) System.out.println("konnte Spielfeld nicht lösen.");
        }
        catch (NumberNotAllowedException e)
        {
            e.printStackTrace();
        }
    }

    private boolean solveNextField(int row, int col)
        throws NumberNotAllowedException
    {
        System.out.println("solve row: " + row + "; col: " + col);
        if (spielfeld.getField(row, col) != null)
        {
            if (row == 9 && col == 9) return true;

            int newcol = 0;
            int newrow = 0;
            if (col == 9)
            {
                newcol = 1;
                newrow = row + 1;
            }
            else
            {
                newcol = col + 1;
                newrow = row;
            }
            return solveNextField(newcol, newrow);
        }


        for (int i = 1; i <= 9; i++)
        {
            System.out.println("versuche: " + i);
            boolean goOn;
            try
            {
                goOn = spielfeld.checkNumberAllowed(i, row, col);
                if (goOn)
                    System.out.println("Nummer erlaubt: " + goOn);
                else
                    System.out.println("Nummer NICHT erlaubt (try)");
            }
            catch (Exception e)
            {
                goOn = false;
                System.out.println("Nummer NICHT erlaubt (catch)");
            }


            if (goOn)
            {
                System.out.println("weiterschalten, da Nummer erlaubt ist");
                if (row == 9 && col == 9)
                {
                    spielfeld.setField(i, row, col);
                    return true;
                }

                spielfeld.setField(i, row, col);


                int newcol = 0;
                int newrow = 0;
                if (col == 9)
                {
                    newcol = 1;
                    newrow = row + 1;
                }
                else
                {
                    newcol = col + 1;
                    newrow = row;
                }


                return solveNextField(newcol, newrow);
            }
        }

        return false;
    }

}


class NumberNotAllowedException
    extends Exception
{

    /**
     * 
     */
    private static final long serialVersionUID = 3186762137729838344L;

    public NumberNotAllowedException()
    {
    }

    public NumberNotAllowedException(String arg0)
    {
        super(arg0);
    }

    public NumberNotAllowedException(Throwable arg0)
    {
        super(arg0);
    }

    public NumberNotAllowedException(String arg0, Throwable arg1)
    {
        super(arg0, arg1);
    }

}
 
Zuletzt bearbeitet von einem Moderator:

freez

Top Contributor
das mit Guice ist doch nicht dein Ernst, oder?

Und ob das mein Ernst ist! Das ist doch der ganze Sinn der Übung. Ich habe eine Programmieraufgabe gesucht um mich Guice zu nähern. Hier im Forum habe ich bereits viele Hinweise bekommen und irgendwie muss man doch die ganzen Hinweise zu Guice in der Praxis mal umsetzen. Von daher wäre es nicht ganz so schlimm, wenn die Methode nicht funktioniert ... den Erfolg habe ich bereits dadurch, dass ich dieses Beispiel bis jetzt gut mit Guice umgesetzt habe. Aber mich wurmt es, dass ich den rekursiven Aufruf nicht hinbekommen habe.
Siehe auch http://www.java-forum.org/allgemeine-java-themen/122290-guice-singleton.html

in der main-Methode von SpielfeldImpl steht nicht viel mehr als das Befüllen eines Feldes, wo wird denn solveSudoku() usw. aufgerufen?
selbst der Anfang läuft bei mir nicht besonders, egal ob ich die Füll-Schleife aus der main-Methode verwende
oder SpielConsole.generateFields() (doppelter Code?), immer kommt es zur NullPointerException,
das Hauptarray fields in Spielfeld ist null, wann soll das wer setzen?

Das hier ist die richtige Einstiegsklasse (SpielfeldImpl.main ist nur ein Test gewesen):
[c]freezly.test.googleGuice.sudoku.Main[/c]

Und damit gibt es keine Exceptions, aber auch keine Lösung.

bisher wird mit Random gefüllt, die Wahl des Sodukos ist von 1x1 bis 9x9 variabel,
hast du nicht ein konkretes Beispiel mit ganz konkreter Problemsituation?

Nein, das Sudoku ist fix auf 9x9. Es können mit generateFields per Zufallsgenerator eine vorgegebene Anzahl von Felder befüllt werden. Die restlichen Felder sollen per Backtracking gelöst werden.

Das Problem tritt bei jedem zufällig generierten Sudoku auf (keine Exceptions, keine Lösung).
 
S

SlaterB

Gast
da habe ich zuviel gelöscht, stimmt, wobei ich mich noch weiter frage, wie da automatisch ein 9x9er Array erzeugt wird?
egal, wenn es bei dir geht, mag es sein,

ich bekomme nun (mit optimierter Feld-Ausgabe ;) ) ein Log wie
Code:
-------------------------
|       |     2 | 5 4   |
|   1 3 |     6 |       |
| 5 8 2 |   3   |   6   |
-------------------------
| 1     | 2 8 7 |   3   |
|   3   | 4     | 6     |
|   4   | 3     | 2 5   |
-------------------------
| 8 6   |   4   | 7 2   |
|       |   5   | 4     |
|       |       |       |
-------------------------
solve row: 1; col: 1
versuche: 1
Nummer NICHT erlaubt (try)
versuche: 2
Nummer NICHT erlaubt (try)
versuche: 3
Nummer NICHT erlaubt (try)
versuche: 4
Nummer NICHT erlaubt (try)
versuche: 5
Nummer NICHT erlaubt (try)
versuche: 6
Nummer erlaubt: true
weiterschalten, da Nummer erlaubt ist
solve row: 2; col: 1
versuche: 1
Nummer NICHT erlaubt (try)
versuche: 2
Nummer NICHT erlaubt (try)
versuche: 3
Nummer NICHT erlaubt (try)
versuche: 4
Nummer erlaubt: true
weiterschalten, da Nummer erlaubt ist
solve row: 2; col: 2
solve row: 3; col: 2
solve row: 3; col: 3
solve row: 4; col: 3
....
wie soll ich mir sicher sein ob die Ausgangssituation überhaupt lösbar ist?
kannst du nicht ein bestimmtes Feld vorgeben, die Schritte, die zur Lösung nötig sind usw.

oder anders gefragt: woran exakt erkennst du selber dass dein Programm einen Fehler macht,
kann nicht einfach das Random-Sudoku unlösbar sein? oder muss es immer lösbar sein?
 

freez

Top Contributor
oder anders gefragt: woran exakt erkennst du selber dass dein Programm einen Fehler macht, kann nicht einfach das Random-Sudoku unlösbar sein? oder muss es immer lösbar sein?

Hm, das ist ein interessanter Einwand. An sowas habe ich nun gar nicht gedacht. Ich bin/war der Meinung, dass man jedes sauber vorbefüllte Sudoku lösen kann ... allerdings weiß ich nicht, wie ich darauf komme.

Aber anders gesagt, müsste ein leeres Sudoku (generateFields(0)) auf jeden Fall lösbar sein ... oder? Sobald ich daheim bin, werde ich das noch mal prüfen und ggfs. ein gelöstes Sudoku als Grundlage nehmen und mal 60 Felder löschen ... dass muss dann aber lösbar sein. Ich habe mir auch schon Ideen von euch mitgenommen und werde die Methode heute Abend noch mal angehen. Je nachdem bekommt ihr heute abend eine Lösung, oder weitere Probleme zu hören ;)
 

Landei

Top Contributor
Hm, das ist ein interessanter Einwand. An sowas habe ich nun gar nicht gedacht. Ich bin/war der Meinung, dass man jedes sauber vorbefüllte Sudoku lösen kann ... allerdings weiß ich nicht, wie ich darauf komme.

Es ist eigentlich klar, dass dem nicht so ist: Nimm ein Sudoku aus der Zeitung und löse es. Die Lösung ist eindeutig. Wenn du das Ausgangssudoku nimmst und irgendwo eine Zahl hinzufügst, die zwar den Regeln nach "erlaubt" ist, aber nicht mit derjenigen in der korrekten Lösung übereinstimmt, hast du ein unlösbares Sudoku.
 

freez

Top Contributor
Naja, es kommt da bestimmt nur darauf an, wie viele Felder vorgegeben sind. Je weniger vorgegeben sind, um so mehr Lösungen wird es geben.
 

timbeau

Gesperrter Benutzer
Natürlich gibt es sehr viele Sudokus mit Lösungsmengen > 1.


--1 --- ---
--- --- ---
--- --- ---
--- --- ---
--- --- ---
--- --- ---
--- --- ---
--- --- ---
--- --- ---

ist z.B. eins mit sehr vielen Lösungen. ;)

Aber es stimmt schon, dass du nicht auf gut Glück Zahlen ins Sudoku setzen kannst. Da müsstest du dir einen Sudokuersteller basteln. Kannst ja auch vollständige Sudokus erschaffen und da Zahlen rauslöschen.

Edith: Mein 1. Sudoku-Solver, leider QuellCode verloren, da nur schlecht zum nachschauen, aber vielleicht hat ja jmd. einen guten Decompiler ;)
 

Anhänge

  • sudoku-solver.jar
    143 KB · Aufrufe: 1
Zuletzt bearbeitet:

freez

Top Contributor
So, habe nun nach euren Tipps eine Lösung.
1. das letzte Feld gesondert behandeln ... dort darf kein weiterer rekursiver Aufruf stattfinden.
2. wenn ein Feld ein false vom nächsten Feld bekommt, dann muss das Feld geleert und die restlichen Nummern geprüft werden
3. bei mehr wie 25 zufällig vorbelegten Feldern wird die Chance deutlich geringer, dass es eine Lösung gibt ... um ein sauberes Sudoku zu generieren würde sich anbieten z.B. 10 Felder vorzugeben, eine Lösung per Backtracking zu finden und dann so viele Felder zu löschen, damit die gewünschte Anzahl übrig bleibt.

so, hier die Methode:
Java:
private boolean solveNextField(int row, int col) throws NumberNotAllowedException {
		NextField nextField = new NextField(row, col);
//		System.out.println("Versuche row="+row+"; col="+col);
		
		
		if(row == 9 && col == 9){
			
//			Behandle letztes Feld
			if(!spielfeld.fieldEmpty(row, col))
				return true;
			else{
				for(int number = 1; number <= 9; number++){
					if(spielfeld.checkNumberAllowed(number, row, col)){
						spielfeld.setField(number, row, col);
						return true;
					}
				}
				return false;
			}
		}else{
//			Behandle beliebiges Feld
			if(!spielfeld.fieldEmpty(row, col)){
//				Feld bereits vorbelegt ... nächstes Feld probieren
				boolean retVal = solveNextField(nextField.getNewRow(), nextField.getNewCol());
				return retVal;
			} else{
//				jede Nummer durchprobieren
				for(int number = 1; number <= 9; number++){
					if(spielfeld.checkNumberAllowed(number, row, col)){
//						Wenn Nummer gesetzt werden darf, dann Nummer setzen und nächstes Feld probieren
						spielfeld.setField(number, row, col);
						boolean retVal = solveNextField(nextField.getNewRow(), nextField.getNewCol());
						
//						Wenn nächstes Feld nicht gesetzt werden konnte, dann Feld entfernen und nächste Nummer probieren 
//						... sonst true zurück geben
						if(retVal == false)
							spielfeld.removeField(row, col);
						else
							return true;
					}
				}
				
//				Keine Nummer konnte gesetzt werden ... false zurück geben
//				System.out.println("Fehlschlag: row="+row+"; col="+col);
				return false;
			}
		}

	}	
	
	private class NextField{
		int newRow = 0;
		int newCol = 0;
		
		public int getNewRow() {
			return newRow;
		}
		
		public int getNewCol() {
			return newCol;
		}
		
		public NextField(int currentRow, int currentCol){
			if(currentCol == 9){
				newCol = 1;
				newRow = currentRow+1;
			} else {
				newCol = currentCol+1;
				newRow = currentRow;
			}
		}
	}

PS: puh, das hat Nerven gekostet
 

RySa

Bekanntes Mitglied
Also nochmal kurz zu der ganzen Sache mit dem "lösbaren Sudoku". Auch wenn du das Feld ganz befüllst und sagen wir mal nur 12 Zahlen stehen lässt, heißt es nicht, dass es für ein Mensch "lösbar" sein wird. Wenn du ein Sudoku löst, musst du dir (also solltest zumindest, wenn du es richtig löst) 100% sicher sein, dass die Zahl dahin kommt, bevor du die reinschreibst, sonnst gehst du nach dem Prinzip "naja, vielleicht wird es ja passen". Sobald du feststellst, dass in das Feld >1 Zahl passt, sollst du an einer anderen Stelle nach der "sicheren Zahl" suchen. Und jetzt noch kurz ein Beispiel:
123 --- ---
456 --- ---
789 --- 123
--- --- ---
--- --- ---
--- --- ---
--- --- ---
--- --- ---
--- --- ---

Hier hast du auch 12 Zahlen vorgegeben, und auch wenn das generierte Feld zu lösen ist, ist es für den Menschen nicht zu lösen ohne einfach mal Blind welche Zahlen eingeben die passen könnten, und dann hoffen dass es die richtige war. Ich weiß, dass das Beispiel ein wenig überzogen ist, und dass du die Zahlen nicht so stehen lassen würdest, ich wollte es aber so deutlich machen.

Also nochmal: Nur weil es möglich ist, das Feld zu lösen, heißt es nicht, dass es für den Menschen "zu lösen" ist. Es sei dem als Schwierigkeitsgrad "Try Your Luck" oder "Impossible Hard OMG What Is That".

Gruß :)
 

freez

Top Contributor
Nur weil es möglich ist, das Feld zu lösen, heißt es nicht, dass es für den Menschen "zu lösen" ist.

Ja, das ist mir durchaus bewusst. Ich löse gern Sudokus. Es gibt die Easy Variante, wo es immer genau einen Weg zum Ziel gibt. Es gibt aber auch die schwierigeren, wo es doch mal passieren kann, dass man an einer Stelle raten und sich die möglichen Zahlen für ein Feld merken/aufschreiben muss. Erst im späteren Verlauf ist es dann möglich zu entscheiden, welche Zahl es sein muss. Das geht natürlich nur bis zu einer bestimmten Komplexität, weil es dann, wie du schon sagtest für einen Menschen unlösbar ist.

Hm, da fällt mir was auf ... so könnte doch auch ein Computer das Sudoku lösen, oder? Gibt es dafür bereits einen Algorithmus?
 

Landei

Top Contributor
Sicher ginge das auch, aber brutales Durchprobier-Backtracking ist viel einfacher zu implementieren, und immer noch schnell genug.
 

RySa

Bekanntes Mitglied
Gucke vielleicht in den Codeschnipseln/Projekten nach, da sollte sogar auf der ersten Seite ein Sudoku Spiel sein, das auch das schon gelöste Sudoku anzeigt falls der Benutzer es sehen will. Sofern ich mich noch erinnern kann, hat es ganz gut und vor allem schnell geklappt. Die Sourcen dazu wurden da glaube ich auch veröffentlicht, du könntest aber auch vielleicht den Themenstarter mal um Hilfe bitten, was das lösen angeht.

EDIT:

Sehe hier: http://www.java-forum.org/codeschnipsel-u-projekte/114833-sudoku-generator.html
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
G Rekursiver Aufruf von Waagengewichten Allgemeine Java-Themen 2
Cromewell Tail-Rekursiver Counting Sort Allgemeine Java-Themen 20
D Rekursiver Datentyp Allgemeine Java-Themen 2
G ziffern zählen mit rekursiver methode Allgemeine Java-Themen 2
D WSDL-Aufruf funktioniert nicht mehr nach Umstieg auf Maven Allgemeine Java-Themen 4
T JNA, Aufruf der Funktionen einer dll Allgemeine Java-Themen 5
T Der Aufruf von CMD-Programm Allgemeine Java-Themen 30
Alex_99 Programm stürzt beim Aufruf der Funktion ab? Text ausgeben Allgemeine Java-Themen 45
I Hibernate Envers - Aufruf der Methode zum Speichern selbst ausführen oder managen? Allgemeine Java-Themen 0
berserkerdq2 Wie mache ich den rekursiven Aufruf in IJVM Allgemeine Java-Themen 3
J Reflection Aufruf: .class durch .dll ersetzen Allgemeine Java-Themen 4
R JDK installieren OpenJDK-Aufruf sehr langsam Allgemeine Java-Themen 4
B Aufruf der Methode ergibt eine Exception Allgemeine Java-Themen 13
H Aufruf eines Web Service anhand übergebenen Parameter Allgemeine Java-Themen 2
P CMD Aufruf mit Admin-Rechte Allgemeine Java-Themen 2
cool_brivk24 Klassen Klassen Aufruf Fehlgeschlagen Allgemeine Java-Themen 14
D HTTP Aufruf einer Methode aus einem Servlet heraus Allgemeine Java-Themen 0
F Methoden Arraylist weiterverwenden nach methoden Aufruf Allgemeine Java-Themen 2
J Genson - zirkulärer Aufruf Allgemeine Java-Themen 1
C file.delete() funktioniert bei zweiten aufruf nicht mehr Allgemeine Java-Themen 3
B Kodierung von String -> URL aufruf Allgemeine Java-Themen 2
H Klassennamen zum Aufruf eines statischen Feldes aus Variable holen Allgemeine Java-Themen 4
M datei aufruf prüfen Allgemeine Java-Themen 9
D JNI DLL Aufruf Allgemeine Java-Themen 32
M datei aufruf datum auslesen Allgemeine Java-Themen 5
A Java Verhalten bei parallelem Aufruf derselben Methode?? Allgemeine Java-Themen 2
F Parameter im Link /jar-Aufruf Allgemeine Java-Themen 12
Z Socket Aufruf einer Klasse in einer anderen Klasse Allgemeine Java-Themen 6
A JNI: Unerklärlicher Crash beim Aufruf von CallVoidMethod Allgemeine Java-Themen 9
S Variablen bei Aufruf zurücksetzen Allgemeine Java-Themen 4
J yield() Aufruf in einer synchronized-Methode Allgemeine Java-Themen 13
R JAR aus Batchdatei Aufruf Allgemeine Java-Themen 4
Kr0e Sichtbarkeitsregeln nach Executor-Aufruf Allgemeine Java-Themen 5
B Cipher.getInstance Aufruf sehr langsam Allgemeine Java-Themen 2
M Aufruf von Unix-Shell in Java Allgemeine Java-Themen 5
G Aufruf einer Methode in IStatus exex Allgemeine Java-Themen 4
E Seltsamer aufruf von java.util.Date.toString() Allgemeine Java-Themen 3
C Netbeans - Aufruf-Reihenfolge Allgemeine Java-Themen 5
Nicer Problem mit Link aufruf Allgemeine Java-Themen 6
M Cobol-Aufruf aus Java Allgemeine Java-Themen 6
C Aufruf einer Methode einer anderen Klasse Allgemeine Java-Themen 14
T Lib/Framework zum Automatischen Aufruf von Methoden Allgemeine Java-Themen 2
R Ableiten - Methoden aufruf bei abgeleiteten Klassen Allgemeine Java-Themen 4
G DAOFactorry aufruf Allgemeine Java-Themen 10
G Aufruf einer Methode wenn Klasse noch nicht existiert Allgemeine Java-Themen 3
V Aufruf von Klasse mit Runnable versteh ich nicht Allgemeine Java-Themen 8
S Übergabe / Aufruf einer beliebigen Methode in einer anderen Allgemeine Java-Themen 9
R toString() methode überschreiben mit rekursivem aufruf. Allgemeine Java-Themen 8
N Main-Klasse wird beim Aufruf des JARs nicht gefunden Allgemeine Java-Themen 8
D Problem bei Aufruf einer Funktion Allgemeine Java-Themen 3
B Null Pointer Exception bei Canvas-objekt-Aufruf Allgemeine Java-Themen 12
S Aufruf in Konsole mit beliebig vielen Argumenten? Allgemeine Java-Themen 18
reibi Aufruf eines private Konstruktors Allgemeine Java-Themen 7
M Rekrusiver Aufruf ? Allgemeine Java-Themen 6
D aufruf beim kopieren Allgemeine Java-Themen 11
J einfachster Servlet-Aufruf klappt nicht Allgemeine Java-Themen 3
J Konstruktor-Aufruf nur aus einem bestimmten Package erlauben Allgemeine Java-Themen 5
S problem mit externen aufruf Allgemeine Java-Themen 4
M [Windows] Aufruf von Java mit Sonderzeichen im Classpath Allgemeine Java-Themen 5
D VM crash nach Aufruf von GetFieldID und GetMethodID in JNI Allgemeine Java-Themen 31
G PDF AUfruf Allgemeine Java-Themen 6
S Aufruf meines Programms Allgemeine Java-Themen 2
U zweifacher Aufruf animiertes gif Allgemeine Java-Themen 7
G Konstruktor-Aufruf nun mit oder ohne Typ? Allgemeine Java-Themen 9
T CMD nach aufruf von javaw Programmname wieder schließen Allgemeine Java-Themen 3
Z Problem beim Aufruf eines Listener? Allgemeine Java-Themen 4
A Problem beim Aufruf von javac Allgemeine Java-Themen 7
W Aufruf von JavaBeans Allgemeine Java-Themen 3
J Sudoku generieren Schwierigkeitsgrad Allgemeine Java-Themen 3
J Sudoku Kommandozeile Allgemeine Java-Themen 13
J Sudoku Löser Allgemeine Java-Themen 10
B Sudoku-Block-Prüfung Allgemeine Java-Themen 1
B Sudoku-Überprüfer Allgemeine Java-Themen 1
K Sudoku-Solver - Backtracking Allgemeine Java-Themen 2
F Sudoku-Löser Allgemeine Java-Themen 6
E Threads Sudoku Threads Allgemeine Java-Themen 8
J Laufzeitberechnung - Sudoku Backtracking Allgemeine Java-Themen 7
A Sudoku mittels Backtracking Problem Allgemeine Java-Themen 6
J Swing Sudoku GUI - Problem mit MaskFormatter Allgemeine Java-Themen 4
truesoul Sudoku programmieren Allgemeine Java-Themen 23
C Sudoku und KeyListener Allgemeine Java-Themen 2
M Problem bei Sudoku Allgemeine Java-Themen 21
V Strings aus externen Dateien Einlesen (Sudoku) Allgemeine Java-Themen 25
B sudoku backtrackingproblem Allgemeine Java-Themen 2
S Algorithmus für Sudoku Allgemeine Java-Themen 17

Ähnliche Java Themen


Oben