Backtracking Problem

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo zusammen,

ich habe stunden im Debugmodus zugebracht komme aber nicht auf einen grünen Zweig. Ich immer noch ein Sudoku erstell. Zunächst betrachte ich nur Zeilen und Spalten. Mit einem 3 mal 3 Feld geht das Programm. Hier meine allgemeine Vorgehensweise:

1. Ich generiere 9 mal zufallszahlen zwischen 1 und 9 und speichere sie in random[81]

2. Von den 81 generierten Zahlen nehme ich die erste und führe folgende Aktionen durch:
-->suche eine freie Stelle im Spielfeld
-->setze die Zahl auf die erste freie stelle
-->prüfe ob die Zahl nach den Regeln dort stehen darf
-->wenn kein Regelverstoß vorliegt fahre ich mit der zweiten Zahl aus random[] fort
-->liegt ein Regelverstoß vor, setze ich die zuvor gesetzte Zahl eine Position weiter.

3. kann eine Zahl nicht weitergesetzt werden, gehe ich nochmals zurück
-->usw....

Ich hoffe es ist einigermaßen nachvollziehbar. Ich möchte mich noch einmal entschuldigen, für den unkommentierten code vom letzen mal.
Hier ist jetz ein verbessterter und kommentierter code.

Ich würde nicht nochmals fragen wenn ich wirklich nicht weiter kommen würde.

Euer JavaMaximum5000

Code:
import java.util.BitSet;
import java.util.Random;


public class Sudoku {

	public static void main(String[] args) {
		
		int random[] = new int[81]; //random is for the random numbers
		int pointer[] = new int[81]; //pointer knows which random number is already set
		int tmp[] = new int[1]; //includes the current random number to set
		int field[][] = new int[9][9]; //the final field
		boolean statussetrandomnumbertogame = false;
		boolean status = false;
		
		int transfer[] = new int[2];
		
		//create random numbers
		createnumbers(random);
		
		//status is false as long as the field is not complete
		while(status == false){
			status = checkpointer(pointer);
			transfer[0] = 0;
			transfer[1] = 0;
			
			//get the next number to the field
			nextnumber(random, pointer, tmp);
			
			//set the number to the field
			statussetrandomnumbertogame = setrandomnumbertogame(tmp, field, transfer,pointer);
			
			printpointer(pointer);
			printfield(field);
			
			//do backtracking as long as statussetrandomnumbertogame is false
			while(statussetrandomnumbertogame == false){
				backtracking(pointer,tmp,random,field, transfer);
				statussetrandomnumbertogame = true;
			}
		}
		
		//finish, print out the game
		printpointer(pointer);
		printfield(field);

	}
	
/*
This function spends the pointers.
1 = The Random Number at this position was set.
0 = The Random Number at this position was not set.
*/
	private static void printpointer(int[] pointer) {
		for(int i = 0; i < 81; i++){
			System.out.print(pointer[i]);
		}
		System.out.println();
	}
	
/*
This function prints the field out.
The quantity of the 0 numbers must be equal to the 0 numbers of the print pointer function.
*/
	private static void printfield(int[][] game) {
		for(int y = 0; y < 9; y++){
			for(int x = 0; x < 9; x++){
				System.out.print(game[y][x]+ " ");
			}
			System.out.println();
		}
		
	}
	
/*
The function checks every place in the array. If the number on every position
is on 1, the sudoku is set up.
*/
	private static boolean checkpointer(int[] pointer) {
		for(int i = 0; i < 80; i++){
			if(pointer[i] == 0){
				return false;
				
			}
		}
		return true;
	}
	
/*
If it is not possible to set the current number into the field, this function
takes the last set number and put it into the next free position. This function is 
recursive 
*/
	private static void backtracking(int[] pointer, int[] tmp, int[] random, int[][] game,int transfer[]) {
		boolean statussetrandomnumbertogame = false;
		int i = 0;
		boolean status = false;
		
		//get the last set number
		//I guess here is a special case missing
		while(status == false){
			if(pointer[i] == 0){
				if(i == 0){
					tmp[0] = random[i];
					status = true;
				}
				else{
					pointer[i-1] = 0;
					tmp[0] = random[i-1];
					status = true;
				}
			}
			i++;
		}
		
		//set the last set number into the next free position
		//I guess here is a special case missing
		for(int row = 8; row >= 0; row--){
			for(int column = 8; column >= 0; column--){
				if(game[row][column] == tmp[0]){
					game[row][column] = 0;
					if(column == 8 && row < 8){
						transfer[0] = row + 1;
						transfer[1] = 0;
						statussetrandomnumbertogame = setrandomnumbertogame(tmp, game, transfer,pointer);
						if(statussetrandomnumbertogame == false){
							//recursive call of the backtrack function
							backtracking(pointer,tmp,random,game, transfer); 
						}
						return;
						
						
					}
					if(column == 8 && row == 8){
						transfer[0] = 8;
						transfer[1] = 8;
						//recursive call of the backtrack function
						backtracking(pointer,tmp,random,game, transfer); 
						return;
					}
					
					else{
						transfer[0] = row;
						transfer[1] = column + 1;
						statussetrandomnumbertogame = setrandomnumbertogame(tmp, game, transfer,pointer);
						if(statussetrandomnumbertogame == false){
							//recursive call of the backtrack function
							backtracking(pointer,tmp,random,game, transfer); 
						}
						return;
					}
				}
			}
		}
		
	}
	
/*
sets the next number to the field
If there is no way in setting up the number, the function returns false
and the backtrack function is called
*/
	private static boolean setrandomnumbertogame(int[] tmp, int[][] game, int transfer[], int[] pointer) {
		boolean status = true;
		for(int row = transfer[0]; row < 9; row++){
			for(int column = transfer[1]; column < 9; column++){
				if(game[row][column] == 0){
					game[row][column] = tmp[0];
					status = checknumber(game, row, column);
					if(status == true){
						for(int i = 0; i < 81; i++){
							if(pointer[i] == 0){
								pointer[i] = 1;
								return true;
							}
						}
						
					}
					else{
						game[row][column] = 0;
					}
				}
			}
		}
		return false;
	}
	
/*
checks the number on a breach of the rules  
*/
	private static boolean checknumber(int[][] game, int row, int column) {
		boolean statusrow = false;
		boolean statuscolumn = false;
		
		statusrow = checkrow(game, row, column);
		statuscolumn = checkcolumn(game, row, column);
		
		if(statusrow == true && statuscolumn == true){
			return true;
		}
		return false;
	}
	
/*
checks the columns on a breach of the rules	
*/
	private static boolean checkcolumn(int[][] game, int row, int column) {
		for(int y = 0; y < 9; y++){
			if(row == y){
				
			}
			else if(game[row][column] == game[y][column]){
				return false;
			}
		}
		
		return true;
		
	}
	
/*
checks the rows on a breach of the rules	 
*/
	private static boolean checkrow(int[][] game, int row, int column) {
		for(int x = 0; x < 9; x++){
			if(column == x){
				
			}
			else if(game[row][column] == game[row][x]){
				return false;
			}
		}
		
		return true;
	}
	
/*
Creates 9 times random numbers from 1 to 9
*/
	private static void createnumbers(int random[]) {
		Random randomnumber = new Random();
		for(int y = 0; y < 81; y = y + 9){
			BitSet generatednumber = new BitSet();
			for(int x = 0; x < 9; x++){
				int number = 1 + Math.abs(randomnumber.nextInt()) % 9;
				if(! generatednumber.get(number)){
					generatednumber.set(number);
					random[y+x] = number;	
				}
				else x--;
			}
		}
	}
	/*
	  
	 */
	private static void nextnumber(int[] random, int[] pointer, int[] tmp) {
		for(int i = 0; i < 81; i++){
			if(pointer[i] == 0){
				tmp[0] = random[i];
				return;
			}
		}
		
	}
}
 
:autsch:

Oh jeh stimmt. Also meine Frage ist ob meine Vorgehensweise überhaupt richtig ist und objemand eine Idee hat warum das Programm in eine Endlosschleife gerät. Wie gesagt ich habe Stunden (kein Witz) beim Debuggen verbracht. Komme aber nicht drauf.
Ich vermute dass ich in der Backtracking Funktion irgendeinen Fall nicht abgefangen habe, komme jedoch nicht drauf.
Mit einem 3 mal 3 Spiel funktioniert es.
 

Marco13

Top Contributor
(Das hab ich mir schon gedacht, aber wollte sicherheitshalber nochmal nachfragen :wink: )

Bist du sicher, dass es in eine Endlosschleife gerät? Wie lange hast du es denn laufen lassen, bis du zu dieser Erkenntnis gekommen bist? Ich habe das Programm nicht komplett nachvollzogen, aber wenn es "straightforward" programmiert ist, schlägt da jetzt halt die Schwäche des Backtracking zu: Es ist probiert alles Kobinationen stupide durch, und ist deswegen scheiß langsam. Genaugenommen hat es exponentielle Laufzeit.

Wenn es bei 3x3=9 Feldern zum Beispiel nach 2^9 = 512 Millisekunden fertig ist, dann kann es durchaus sein, dass es bei 9x9=81 Feldern eben 2^81 Millisekunden braucht, also etwa 76000000000000 Jahre.

Es muß also nicht unbedingt in einer Endlosschleife stecken, nur weil es mal ein paar Billionen Jahre braucht, um fertig zu werden.

Wenn es schneller gehen soll, mußt du dir halt was überlegen..........
 
Schon mal meinen Dank,

aber den Backtracking Algorithmus bei einem 9x9 Feld anzuwenden ist doch Standart. Steht auch auf vielen Seiten.
Was meinst du ich sollte mir was überlegen
 

sparrow

Top Contributor
Anonymous hat gesagt.:
1. Ich generiere 9 mal zufallszahlen zwischen 1 und 9 und speichere sie in random[81]

Wieso Zufallszahlen?
Ich bin mir ziemlich sicher welche 81 Zahlen in das Feld müssen, die sind doch nicht zufällig.


Gruß
Sparrow
 

Marco13

Top Contributor
Es kommt auch darauf an, wie früh man "backtracken" kann, wenn man feststellt, dass das Ziel nichtmehr erfüllbar ist. Soweit ich weiß dürfen ja auch in jedem 3x3-TEIL-Block des 9x9-Feldes nur die Zahlen von 1 bis 9 stehen.

Ich habe zwar keine zeit, dein Programm nachzuvollziehen, zu debuggen, den Fehler zu finden, und zu beheben, aber grundsätzlich:
4 5 3 1 6 2 8 9 7
8 6 7 4 3 1 5 2 9
6 4 5 8 1 3 9 7 2
1 9 2 5 4 0 3 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
hier ist ja vermutlich schon was schief gegangen - in der letzten bearbeiteten Zeile steht ...4 0 3 ... und diese 0 sollte da nicht sein.

Das mit den 81 Zufallszahlen hab ich nicht ganz kapiert, aber du solltest dir auf jeden Fall (!) einmal ein solches Array erstellen, und deine Debug-Tests dann immer mit dem gleichen Array machen. Dann kannst du nämlich (in dem Beispiel oben) einfach eine Bedinung einbauen, die Abfragt, ob dieses ...4 0 3... dort steht, und DANN kannst du genauer nachsehen, wo die 0 herkommt.
 
Ich fülle zuerst mein Array random mit den Zufallszahlen, damit ich immer die gleichen Zahlen benutze.

mit 4 0 3 das muss schon so sein, es wird ja immer die Zahl weitergesetzt. An der 0 hat dann eine andere Zahl platz.
Gerade habe ich es nochmals mit einem 5 x 5 Feld (Zahlen 1 bis 5) getestet. In 3 von 10 Durchläufen ist das Ergebnis sofort da und das Programm fertig abgelaufen. In den anden Fällen gerät es in eine Endlosschleife.

Es muss irgendeinen Fall geben wo es hakt. Dieser muss wiederum äußerst selten vorkommen.
Bei einem 3x3 Feld wurde er noch nie festgestellt.
Bei einem 4x4 Feld wurde der Fehler selten festgestellt(bei 10 Fällen 2 mal).
Bei einem 5x5 Feld siehe oben.
Höher wurde nicht getestet(9x9 geht niemals).

Mit allen Ausgaben stellt man recht schnell fest, dass sich das Programm in einer Endlosschleife befindet.
Nur warum habe ich noch nicht festgestellt.

MfG JavaMaximum5000
 

Ariol

Top Contributor
ich kann dir sagen wo das Problem liegt, aber wie man es los wird weiss ich gerade nicht.

Sieh dir mal diese Ausgabe an:

1 6 8 4 5 2 7 3 9
3 2 4 9 6 1 5 8 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0

Die nächste Zahl die eingesetzt werden soll ist die 7. Die kann man aber nicht einfügen, weil diese bereits im rechten oberen Viertel vorhanden ist.
Deshalb hängt das Programm in einer Endlosschleife fest.

Ich hab eine Idee, wie mans lösen kann... ich meld mich dann wieder
 
ja schon, die Blockprüfung ist auch noch nicht implementiert (ganz oben erwähnt).

Hier nochmal der Code für 5 x 5. Geht halt nicht immer.

Code:
import java.util.BitSet;
import java.util.Random;


public class Sudoku {

	public static void main(String[] args) {
		
		int random[] = new int[25]; //random is for the random numbers
		int pointer[] = new int[25]; //pointer knows which random number is already set
		int tmp[] = new int[1]; //includes the current random number to set
		int field[][] = new int[5][5]; //the final field
		boolean statussetrandomnumbertogame = false;
		boolean status = false;
		
		int transfer[] = new int[2];
		
		//create random numbers
		createnumbers(random);
		
		//status is false as long as the field is not complete
		while(status == false){
			status = checkpointer(pointer);
			transfer[0] = 0;
			transfer[1] = 0;
			
			//get the next number to the field
			nextnumber(random, pointer, tmp);
			
			//set the number to the field
			statussetrandomnumbertogame = setrandomnumbertogame(tmp, field, transfer,pointer);
			
			printpointer(pointer);
			printfield(field);
			printpointer(random);
			//do backtracking as long as statussetrandomnumbertogame is false
			while(statussetrandomnumbertogame == false){
				backtracking(pointer,tmp,random,field, transfer);
				statussetrandomnumbertogame = true;
			}
		}
		
		//finish, print out the game
		printpointer(pointer);
		printfield(field);
		printpointer(random);

	}
	
/*
This function spends the pointers.
1 = The Random Number at this position was set.
0 = The Random Number at this position was not set.
*/
	private static void printpointer(int[] pointer) {
		for(int i = 0; i < 25; i++){
			System.out.print(pointer[i]);
		}
		System.out.println();
	}
	
/*
This function prints the field out.
The quantity of the 0 numbers must be equal to the 0 numbers of the print pointer function.
*/
	private static void printfield(int[][] game) {
		for(int y = 0; y < 5; y++){
			for(int x = 0; x < 5; x++){
				System.out.print(game[y][x]+ " ");
			}
			System.out.println();
		}
		
	}
	
/*
The function checks every place in the array. If the number on every position
is on 1, the sudoku is set up.
*/
	private static boolean checkpointer(int[] pointer) {
		for(int i = 0; i < 24; i++){
			if(pointer[i] == 0){
				return false;
				
			}
		}
		return true;
	}
	
/*
If it is not possible to set the current number into the field, this function
takes the last set number and put it into the next free position. This function is 
recursive 
*/
	private static void backtracking(int[] pointer, int[] tmp, int[] random, int[][] game,int transfer[]) {
		boolean statussetrandomnumbertogame = false;
		int i = 0;
		boolean status = false;
		
		//get the last set number
		//I guess here is a special case missing
		while(status == false){
			if(pointer[i] == 0){
				if(i == 0){
					tmp[0] = random[i];
					status = true;
				}
				else{
					pointer[i-1] = 0;
					tmp[0] = random[i-1];
					status = true;
				}
			}
			i++;
		}
		
		//set the last set number into the next free position
		//I guess here is a special case missing
		for(int row = 4; row >= 0; row--){
			for(int column = 4; column >= 0; column--){
				if(game[row][column] == tmp[0]){
					game[row][column] = 0;
					if(column == 4 && row < 4){
						transfer[0] = row + 1;
						transfer[1] = 0;
						statussetrandomnumbertogame = setrandomnumbertogame(tmp, game, transfer,pointer);
						if(statussetrandomnumbertogame == false){
							//recursive call of the backtrack function
							backtracking(pointer,tmp,random,game, transfer); 
						}
						return;
						
						
					}
					if(column == 4 && row == 4){
						transfer[0] = 4;
						transfer[1] = 4;
						//recursive call of the backtrack function
						backtracking(pointer,tmp,random,game, transfer); 
						return;
						
					}
					
					else{
						transfer[0] = row;
						transfer[1] = column + 1;
						statussetrandomnumbertogame = setrandomnumbertogame(tmp, game, transfer,pointer);
						if(statussetrandomnumbertogame == false){
							//recursive call of the backtrack function
							backtracking(pointer,tmp,random,game, transfer); 
						}
						return;
					}
				}
			}
		}
		
	}
	
/*
sets the next number to the field
If there is no way in setting up the number, the function returns false
and the backtrack function is called
*/
	private static boolean setrandomnumbertogame(int[] tmp, int[][] game, int transfer[], int[] pointer) {
		boolean status = true;
		for(int row = transfer[0]; row < 5; row++){
			for(int column = transfer[1]; column < 5; column++){
				if(game[row][column] == 0){
					game[row][column] = tmp[0];
					status = checknumber(game, row, column);
					if(status == true){
						for(int i = 0; i < 25; i++){
							if(pointer[i] == 0){
								pointer[i] = 1;
								return true;
							}
						}
						
					}
					else{
						game[row][column] = 0;
					}
				}
			}
		}
		return false;
	}
	
/*
checks the number on a breach of the rules  
*/
	private static boolean checknumber(int[][] game, int row, int column) {
		boolean statusrow = false;
		boolean statuscolumn = false;
		
		statusrow = checkrow(game, row, column);
		statuscolumn = checkcolumn(game, row, column);
		
		if(statusrow == true && statuscolumn == true){
			return true;
		}
		return false;
	}
	
/*
checks the columns on a breach of the rules	
*/
	private static boolean checkcolumn(int[][] game, int row, int column) {
		for(int y = 0; y < 5; y++){
			if(row == y){
				
			}
			else if(game[row][column] == game[y][column]){
				return false;
			}
		}
		
		return true;
		
	}
	
/*
checks the rows on a breach of the rules	 
*/
	private static boolean checkrow(int[][] game, int row, int column) {
		for(int x = 0; x < 5; x++){
			if(column == x){
				
			}
			else if(game[row][column] == game[row][x]){
				return false;
			}
		}
		
		return true;
	}
	
/*
Creates 9 times random numbers from 1 to 9
*/
	private static void createnumbers(int random[]) {
		Random randomnumber = new Random();
		for(int y = 0; y < 25; y = y + 5){
			BitSet generatednumber = new BitSet();
			for(int x = 0; x < 5; x++){
				int number = 1 + Math.abs(randomnumber.nextInt()) % 5;
				if(! generatednumber.get(number)){
					generatednumber.set(number);
					random[y+x] = number;	
				}
				else x--;
			}
		}
	}
	/*
	  
	 */
	private static void nextnumber(int[] random, int[] pointer, int[] tmp) {
		for(int i = 0; i < 25; i++){
			if(pointer[i] == 0){
				tmp[0] = random[i];
				return;
			}
		}
		
	}
}
 

NTB

Bekanntes Mitglied
ich kann dir nicht zu der Lösung verhelfen, aber ein kleiner Tipp:
Bevor Du für jede Feldgröße den ganzen Code änderst, könntest Du die Feldgröße doch als Variable einmalig angeben.
 

Ariol

Top Contributor
Ich hab das ganze selbst mal ein bisschen übersichtlicher geschrieben, vielleicht hilft es ja weiter.

Ich bin noch an meiner Idee dran

Code:
public class Sudoku {

	
	public static int[][] field = new int[9][9]; 
	
	public static void fillField()
	{
		for(int i = 0; i < field.length; i++)
		{
			for(int j = 0; j < field[i].length; j++)
			{
				int number = ((int)(Math.random()*10));
				
				int fromRow = Math.round(i/3)*3;
				int fromColumn = Math.round(j/3)*3;
					
				while(  existsInRow(i, number) || 
						existsInColumn(j, number) ||
						existsInQuater(fromRow, fromRow + 2, fromColumn, fromColumn + 2, number))
				{
					number = ((int)(Math.random()*10));
				}
				
				field[i][j] = number;
				printField();
				
			}
		}
	}
	
	public static boolean existsInRow(int row, int value)
	{
		for(int i = 0; i < 9; i++)
		{
			if(field[row][i] == value)return true;
		}
		return false;
	}
	
	public static boolean existsInColumn(int column, int value)
	{
		for(int i = 0; i < 9; i++)
		{
			if(field[i][column] == value)return true;
		}
		return false;
	}
	
	public static boolean existsInQuater(int fromRow, int toRow, int fromColumn, int toColumn, int value)
	{
		for(int i = fromRow; i <= toRow; i++)
		{
			for(int j = fromColumn; j <= toColumn; j++)
			{
				if(field[i][j] == value)return true;
			}
		}
		return false;
	}
	
	public static void printField()
	{
		for(int i = 0; i < field.length; i++)
		{
			for(int j = 0; j < field[i].length; j++)
			{
				System.out.print(" " + field[i][j] + " ");
			}
			System.out.println();
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		fillField();
		printField();
	}

}
 
J

JavaMaximum50000

Gast
Vielen dank für deine Arbeit werde es mir später nocheinmal ansehen.
JavaMaximum5000
 

Marco13

Top Contributor
@Ariel: Das ist Lottodoku :lol:

@JavaMaximum50000: Nochmal: Du solltest zuallererst den Zufall am Anfang rausnehemen. Lass dir meinetrwegen EINMAL zufällig einen Array so füllen, wie du das da willst, aber verwende danach immer wieder den gleichen - sonst ist das vollkommen un-debug-bar.

Und mit "etwas einfallen lassen" meinte ich, dass das Backtracking in diesem Fall eben unter Umständen extrem lange dauert. Du meintest
aber den Backtracking Algorithmus bei einem 9x9 Feld anzuwenden ist doch Standart. Steht auch auf vielen Seiten.
Bezog sich das auf Sudoku, oder z.B. auf sowas wie das N-Queens-Problem? Dort ist das sicher Standard, aber bei Sudoku in dieser Form NICHT (d.h. nicht ohne dass man gezielt bestimmte Sachen ausnutzt, um es schneller zu machen).


Ein Beispiel: Wenn man ein 5x5-Sudoku hat, und das nicht mit zufälligen Zahlen füllt, sondern mit fortlaufenden (oder wenn die Zufälligen Zahlen zufällig fortlaufend sind :wink: ) dann füllt er das Feld bis hierhin:

1 2 3 4 5
2 1 4 3 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

Dann will er die zweite 5 loswerden, und setzt sie auf

1 2 3 4 5
2 1 4 3 0
5 0 0 0 0
0 0 0 0 0
0 0 0 0 0

aber das letzt Feld in der 2. zeile ist noch 0 - und das bleibt es auch. Für immer. Es gibt keine Zahl mehr, die dort stehen kann. Aber er füllt munter weiter, und Probiert etliche Millionen Kombinationen durch. Er "weiß" einfach nicht, dass er ganz am Anfang schon einen Fehler gemacht hat, der alles kaputt macht. Bis er durch das Backtracking wieder zu diesem Punkt zurückkommt, und von

1 2 3 4 5
2 1 4 0 3
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

aus weiterarbeitet, kann es EXTREM lange dauern.

Hier wäre es besser das Backtracking nicht über die Feldpositionen laufen zu lassen, sondern über die Zahlen. Also nicht zu Fragen: "Wo kann ich die aktuelle Zahl hinsezen?" sondern "Welche Zahl kann ich aufs nächste Feld setzen?". Dann würde man im o.g. Beispiel sehr schnell sehen, dass es dort keine Möglichkeit mehr gibt, und das Backtracking würde früher "greifen".

Als Beispiel, hier mal beide Methoden im Vergleich: solveB läuft ruck-zuck durch, während solveA sich im Backtracking verhakt.

Code:
class Sudoku
{
    public static void main(String args[])
    {
        Sudoku sudoku = new Sudoku(5);
        sudoku.solveB();
        sudoku.solveA();
    }


    private int size = 0;
    private int entries[][];

    private boolean used[];

    public Sudoku(int size)
    {
        this.size = size;
        entries = new int[size][size];
        used = new boolean[size];
    }

    public String toString()
    {
        StringBuffer sb = new StringBuffer();
        for (int i=0; i<size; i++)
        {
            for (int j=0; j<size; j++)
            {
                sb.append(entries[i][j]).append(" ");
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    private void clear()
    {
        for (int i=0; i<size; i++)
        {
            for (int j=0; j<size; j++)
            {
                entries[i][j] = 0;
            }
        }
    }

    public void solveA()
    {
        clear();
        solveA(0);
    }

    public void solveB()
    {
        clear();
        solveB(0);
    }

    private boolean solveA(int entryNumber)
    {
        System.out.println(entryNumber);
        if (entryNumber == size * size)
        {
            System.out.println("Finished");
            System.out.println(this);
            return true;
        }
        int entryValue = entryNumber % size + 1;
        for (int i=0; i<size; i++)
        {
            for (int j=0; j<size; j++)
            {
                if (entries[i][j] == 0)
                {
                    System.out.println("Setting "+entryValue+" on "+i+" "+j+" on \n"+this);
                    entries[i][j] = entryValue;
                    if (!fieldValid())
                    {
                        System.out.println("Field becomes invalid");
                    }
                    else
                    {
                        if (solveA(entryNumber+1))
                        {
                            return true;
                        }
                    }
                    entries[i][j] = 0;
                }
            }
        }
        return false;
    }


    private boolean solveB(int entryNumber)
    {
        System.out.println(entryNumber);
        if (entryNumber == size * size)
        {
            System.out.println("Finished");
            System.out.println(this);
            return true;
        }
        int row = entryNumber / size;
        int col = entryNumber % size;
        for (int i=0; i<size; i++)
        {
            int entryValue = i + 1;
            entries[row][col] = entryValue;
            System.out.println("Setting "+entryValue+" on "+row+" "+col+" on \n"+this);
            if (!fieldValid())
            {
                System.out.println("Field becomes invalid");
            }
            else
            {
                  if (solveB(entryNumber+1))
                {
                    return true;
                }
            }
            entries[row][col] = 0;
        }
        return false;
    }


    private boolean rowValid(int row)
    {
        for (int i=0; i<size; i++)
        {
            used[i] = false;
        }
        for (int i=0; i<size; i++)
        {
            int entry = entries[row][i] - 1;
            if (entry > -1)
            {
                if (used[entry])
                {
                    return false;
                }
                used[entry] = true;
            }
        }
        return true;
    }

    private boolean columnValid(int col)
    {
        for (int i=0; i<size; i++)
        {
            used[i] = false;
        }
        for (int i=0; i<size; i++)
        {
            int entry = entries[i][col] - 1;
            if (entry > -1)
            {
                if (used[entry])
                {
                    return false;
                }
                used[entry] = true;
            }
        }
        return true;
    }

    private boolean fieldValid()
    {
        for (int i=0; i<size; i++)
        {
            if (!rowValid(i))
            {
                return false;
            }
            if (!columnValid(i))
            {
                return false;
            }
        }
        return true;
    }


}
 

Ariol

Top Contributor
Code:
public class Sudoku {

	
	public static int[][] field = new int[9][9]; 
	
	public static void fillField()
	{
		for(int i = 0; i < 9; i++)
		{
			while(!fillQuater(i,i+1,0,9));
		}
	}
	
	public static boolean fillQuater(int fromRow, int toRow, int fromColumn, int toColumn)
	{
		for(int i = fromRow; i < toRow; i++)
		{
			for(int j = fromColumn; j < toColumn; j++)
			{
				int number = ((int)(Math.random()*10));
				
				int fromRowCheck = Math.round(i/3)*3;
				int fromColumnCheck = Math.round(j/3)*3;
				
				int count = 0;
				
				while(  existsInRow(i, number) || 
						existsInColumn(j, number) ||
						existsInQuater(fromRowCheck, fromRowCheck + 2, fromColumnCheck, fromColumnCheck + 2, number))
				{
					number = ((int)(Math.random()*10));
					count++;
					
					//Ging nicht -> zurücksetzen zum nochmal versuchen
					if(count >= 20) 
					{
						for(int k = fromRow; k < toRow; k++)
						{
							for(int l = fromColumn; l < toColumn; l++)
							{
								field[k][l] = 0;
							}
						}
						return false;
					}
				}
				field[i][j] = number;
				printField();
			}
		}

		return true;
	}
	
	public static boolean existsInRow(int row, int value)
	{
		for(int i = 0; i < 9; i++)
		{
			if(field[row][i] == value)return true;
		}
		return false;
	}
	
	public static boolean existsInColumn(int column, int value)
	{
		for(int i = 0; i < 9; i++)
		{
			if(field[i][column] == value)return true;
		}
		return false;
	}
	
	public static boolean existsInQuater(int fromRow, int toRow, int fromColumn, int toColumn, int value)
	{
		for(int i = fromRow; i <= toRow; i++)
		{
			for(int j = fromColumn; j <= toColumn; j++)
			{
				if(field[i][j] == value)return true;
			}
		}
		return false;
	}
	
	public static void printField()
	{
		System.out.println("--------------------------");
		for(int i = 0; i < field.length; i++)
		{
			for(int j = 0; j < field[i].length; j++)
			{
				System.out.print(" " + field[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println("--------------------------");
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		fillField();
		printField();

	}

}

Funktioniert
 
@Ariol
@Marco13

Vielen Dank für eure Hilfe und Mühen. Ich werde mir das alles nochmals genauestens anschauen.

1 2 3 4 5
2 1 4 3 0
5 0 0 0 0
0 0 0 0 0
0 0 0 0 0

aber das letzt Feld in der 2. zeile ist noch 0 - und das bleibt es auch. Für immer. Es gibt keine Zahl mehr, die dort stehen kann. Aber er füllt munter weiter, und Probiert etliche Millionen Kombinationen durch. Er "weiß" einfach nicht, dass er ganz am Anfang schon einen Fehler gemacht hat, der alles kaputt macht. Bis er durch das Backtracking wieder zu diesem Punkt zurückkommt, und von

1 2 3 4 5
2 1 4 0 3
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

aus weiterarbeitet, kann es EXTREM lange dauern.

genau so hatte ich mir das gedacht, ich konnte mir einfach nicht vorstellen dass es so lange dauern würde.
Werde mich nochmals hineindenken.

Gruss,

JavaMaximum5000
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Max246Sch Backtracking Problem Box Filler Allgemeine Java-Themen 6
A Sudoku mittels Backtracking Problem Allgemeine Java-Themen 6
K Sudoku-Solver - Backtracking Allgemeine Java-Themen 2
T Methoden Backtracking Allgemeine Java-Themen 2
J Laufzeitberechnung - Sudoku Backtracking Allgemeine Java-Themen 7
J Damenproblem mit Backtracking Allgemeine Java-Themen 33
B Magisches Quadrat per Backtracking Allgemeine Java-Themen 4
krgewb Problem mit Umlauten und Eszett bei InputStream Allgemeine Java-Themen 3
NightVision402 VisualVM Startskript Problem Allgemeine Java-Themen 3
javaBoon86 Email Server Connection Problem Allgemeine Java-Themen 1
F Problem mit PDFBOX Library Allgemeine Java-Themen 1
A Java modul Problem Allgemeine Java-Themen 4
D Read JSON File Problem Allgemeine Java-Themen 9
urmelausdemeis Exception in thread "main" java.lang.Error: Unresolved compilation problem: Allgemeine Java-Themen 7
J Problem mit JasperReports Allgemeine Java-Themen 8
M log4j Problem mit jlink Allgemeine Java-Themen 19
8u3631984 Problem beim Mocken von Record Klassen Allgemeine Java-Themen 4
torresbig Website login Problem - Jsoup, wie bisher, klappt nicht! Allgemeine Java-Themen 31
P Selenium . getText Problem Allgemeine Java-Themen 9
A Jar zu Exe Problem Allgemeine Java-Themen 13
sserio Variablen Liste erstellt und ein Problem mit dem Index Allgemeine Java-Themen 6
S Folgendes Problem bei einem Programm Allgemeine Java-Themen 1
stormyark Problem beim Klassen erstellen Allgemeine Java-Themen 1
A Thread.sleep Problem Allgemeine Java-Themen 2
A Problem bei der Nachbarschafttest Allgemeine Java-Themen 11
Splayfer Problem: no main manifest attribute Allgemeine Java-Themen 3
G javamail Problem beim Empfangen von Nachrichten Allgemeine Java-Themen 3
Splayfer JDA Problem mit MessageCounter Allgemeine Java-Themen 0
Splayfer Problem mit BufferedWriter Allgemeine Java-Themen 3
F Streams als Alternative für dieses Problem ? Allgemeine Java-Themen 15
N Maven Problem mit Datenbanktreiber (H2 Embedded) Allgemeine Java-Themen 12
T Problem beim Umwandeln in eine Jar-Datei Allgemeine Java-Themen 3
B Einfach Elemente zweier Arraylisten kreuz und quer vergleichen, min und max Problem? Allgemeine Java-Themen 16
C ArrayList Problem Allgemeine Java-Themen 3
kev34 nim-Spiel problem Allgemeine Java-Themen 1
D Firebase retrieve data Problem, Child Element wird nicht angesprochen Allgemeine Java-Themen 0
G Welches Problem besteht bei den Typparametern? Allgemeine Java-Themen 5
temi Problem mit Aufrufreihenfolge bei Vererbung Allgemeine Java-Themen 3
Sumo_ow "ArrayIndexOutofBoundsException: 2" Array Problem Allgemeine Java-Themen 6
T PIM basierend auf netbeans via AnyDesk Problem Allgemeine Java-Themen 3
xGh0st2014 Problem mit Java Array Allgemeine Java-Themen 1
Kirby.exe Verständnis Problem bei Rucksack Problem Allgemeine Java-Themen 6
B Eclipse-Lombok-Problem Allgemeine Java-Themen 19
I Input/Output ObjectOutputStream - Problem Allgemeine Java-Themen 7
1 Multiple Choice Knapsack- Problem Allgemeine Java-Themen 2
kodela Problem mit strukturiertem Array Allgemeine Java-Themen 18
E Problem mit Gridlayout und Button Allgemeine Java-Themen 2
A Array Problem Allgemeine Java-Themen 8
bueseb84 Problem Allgemeine Java-Themen 0
S Problem mit Arrays Allgemeine Java-Themen 1
D Nullpointer Exception Problem Allgemeine Java-Themen 5
B Problem mit meinen Klassen Allgemeine Java-Themen 6
A HashMap Methode "get()"-Problem Allgemeine Java-Themen 28
J Problem beim Umstellen auf Java jdk 13 Allgemeine Java-Themen 3
J Problem bei Install java 13 Allgemeine Java-Themen 3
X Profitable Reise Problem Allgemeine Java-Themen 32
A Problem beim öffnen von Java-Installern Allgemeine Java-Themen 1
Dann07 Problem mit JavaMail API Allgemeine Java-Themen 26
J Problem beim Generischen Klassen und Interfaces Allgemeine Java-Themen 2
L Klassen Algorithmus für das folgende Problem entwickeln? Allgemeine Java-Themen 30
J Clear-Problem Allgemeine Java-Themen 10
B Problem zu einem Java Projekt Allgemeine Java-Themen 6
S JFileChooser Problem Allgemeine Java-Themen 4
M Traveling Salesman - MST Heuristik Problem Allgemeine Java-Themen 4
J Traveling Salesman Problem Allgemeine Java-Themen 14
E Java Editor Problem mit 2er Exceptions Allgemeine Java-Themen 12
C code oder Bibliotheken für 2-Center Problem Allgemeine Java-Themen 4
M Salesman Problem - Bruteforce Algorithmus Allgemeine Java-Themen 23
S Methoden Problem mit NullPointerException Allgemeine Java-Themen 9
Javafan02 Problem mit if-clause Allgemeine Java-Themen 17
J Lombok Problem mit Konstruktoren bei Verberbung Allgemeine Java-Themen 1
kodela Event Handling Problem mit der Alt-Taste Allgemeine Java-Themen 16
W Threads Problem Allgemeine Java-Themen 15
D (Verständnis-)Problem mit Unterklasse Allgemeine Java-Themen 4
S Problem mit Generic bei unmodifiableCollection Allgemeine Java-Themen 4
S jserialcomm Problem Allgemeine Java-Themen 1
Flynn Thread-Problem... Allgemeine Java-Themen 2
J Generische Interface - Problem Allgemeine Java-Themen 3
G Problem beim GUI Allgemeine Java-Themen 9
L Applet Problem "security: Trusted libraries list file not found" ? Allgemeine Java-Themen 7
A OOP Problem beim Berechnen der größten Fläche eines Ringes Allgemeine Java-Themen 19
T Problem mit externen Datenbankzugriff über SSH Tunnel Allgemeine Java-Themen 4
F Problem beim Einlesen einer Textdatei Allgemeine Java-Themen 12
S Java OpenOffice Problem mit Windows-Benutzerwechsel Allgemeine Java-Themen 19
K Threads RAM Problem Allgemeine Java-Themen 20
P Operatoren Problem mit Zähler in recursiver Schleife Allgemeine Java-Themen 2
C Int Problem Allgemeine Java-Themen 8
C J2V8 NodeJs Java Bride Problem und Frage!?!? Allgemeine Java-Themen 1
J Problem bei Hashmap Key-Abfrage Allgemeine Java-Themen 4
C Webseiten Programm problem Allgemeine Java-Themen 5
M LocalDate Problem Allgemeine Java-Themen 4
J "Problem Objektorientierung" Allgemeine Java-Themen 20
geekex Problem Meldung! Was tun?! Allgemeine Java-Themen 19
T Klassen Override Problem Allgemeine Java-Themen 7
L Unbekanntes Problem Allgemeine Java-Themen 1
FrittenFritze Problem mit einer JComboBox, Event temporär deaktivieren Allgemeine Java-Themen 11
Blender3D Java Swing Programm Windows 10 Autostart Problem Allgemeine Java-Themen 2
F HTTPS Zertifikat Problem Allgemeine Java-Themen 3
M OpenCV KNearest Problem Allgemeine Java-Themen 0
Tommy Nightmare Project Euler: Problem 22 Allgemeine Java-Themen 2

Ähnliche Java Themen


Oben