Smagjus
Vice Admiral
- Registriert
- Feb. 2011
- Beiträge
- 6.146
Hallo zusammen!
Ich habe ein extrem merkwürdiges Problem. Mein Programm soll eigentlich via Backtracking welches ich rekursiv realisiert habe, zusammen mit der Klasse Random zufällige Sudokus erstellen. Jetzt kommt das aber: Es funktioniert nur, wenn ich eine Debugausgabe einbaue und das kann ich mir mit gesundem Menschenverstand nicht erklären.
Der Code ist nicht schön, deswegen versuche ich das Prinzip erst einmal zu erklären:
Das Problem ist, dass dies nur funktioniert, wenn ich Debug Ausgabe über die Konsole einbaue. Ohne diese Ausgaben, scheint sich das Feld bis zur Ebene 70 recht fehlerfrei aufzubauen, fängt dann aber an sukzessive bis zurück auf Ebene 16 zu kollabieren. Baue ich die Debugausgabe ein, dauert das Erstellen wesentlich länger, dafür ist es aber erfolgreich und benötigt weniger Iterationen als der fehlerhafte Aufbau. Genau das kann doch eigentlich gar nicht sein oder? Das einzige Element in meinem Programm, das meines Wissens mit der Zeit in Relation steht, ist Random, womit ich die zufälligen Werte erstelle. Aber theoretisch gesehen, müsste das Programm auch mit einem schlechten Randomseed terminieren oder etwa nicht?
Ich habe ein extrem merkwürdiges Problem. Mein Programm soll eigentlich via Backtracking welches ich rekursiv realisiert habe, zusammen mit der Klasse Random zufällige Sudokus erstellen. Jetzt kommt das aber: Es funktioniert nur, wenn ich eine Debugausgabe einbaue und das kann ich mir mit gesundem Menschenverstand nicht erklären.
Der Code ist nicht schön, deswegen versuche ich das Prinzip erst einmal zu erklären:
- Ich habe ein eindimensionales Array, welches mein Feld darstellt. Index 0 ist oben links, Index 8 ist oben rechts und Index 80 ist unten rechts auf meinem quadratischen Sudoku Feld.
- Die Methode FillValues bekommt den Startindex 0 und einen Zufallswert zwischen 1 und 9. Dieser wird ins Array eingetragen.
- Danach prüfe ich mit der Methode IsLegal, ob der Teil des Array, der bereits befüllt ist, den Sudoku Regeln entspricht. Ist das nicht der Fall, werden für den aktuellen Index nacheinander alle anderen möglichen Werte zwischen 1 und 9 probiert.
- Funktioniert das nicht, gehe eine Ebene weiter nach oben(=Index - 1) und probiere wieder alle Werte.
- Bin ich erfolgreich, gehe ich eine Ebene weiter nach unten(=Index + 1) und mache mit verändertem Index bei Schritt 2 weiter.
- Abbruchbedingung ist ein Index von 81.
Das Problem ist, dass dies nur funktioniert, wenn ich Debug Ausgabe über die Konsole einbaue. Ohne diese Ausgaben, scheint sich das Feld bis zur Ebene 70 recht fehlerfrei aufzubauen, fängt dann aber an sukzessive bis zurück auf Ebene 16 zu kollabieren. Baue ich die Debugausgabe ein, dauert das Erstellen wesentlich länger, dafür ist es aber erfolgreich und benötigt weniger Iterationen als der fehlerhafte Aufbau. Genau das kann doch eigentlich gar nicht sein oder? Das einzige Element in meinem Programm, das meines Wissens mit der Zeit in Relation steht, ist Random, womit ich die zufälligen Werte erstelle. Aber theoretisch gesehen, müsste das Programm auch mit einem schlechten Randomseed terminieren oder etwa nicht?
Code:
private Boolean FillValues(int index, int value) {
if (index >= 81)
return true;
Solution[index] = (byte)value; TestValue++;
if (IsLegal(Solution, index) && FillValues(index + 1, new Random().Next(1, 10)))
return true;
else
{
Boolean isLegalOption = false;
int i = 0;
int newValue =((value % 9) + 1);
do
{
Solution[index] = newValue; TestValue++;
isLegalOption = IsLegal(Solution, index);
i++;
newValue = ((value + i) % 9) + 1;
}
while (newValue != value && !isLegalOption);
if (isLegalOption)
return FillValues(index + 1, new Random().Next(1, 10));
else
return false;
}
}
Code:
public Boolean IsLegal(int[] solution, int upperIndexLimit) {
Boolean[] values;
int temp = -1;
for (int i = 0; i < 9; i++)
{
values = new Boolean[10];
for (int j = 0; j < 9; j++) //hoizontal
{
temp = solution[i * 9 + j];
if (temp != 0 && (i * 9 + j) <= upperIndexLimit)
{
if (values[temp])
{
Print(solution, upperIndexLimit); //DEBUGAUSGABE, fällt sie weg, funktioniert das Programm nicht mehr
return false;
}
else
values[temp] = true;
}
}
//---------------------------------------------------------------------------------
values = new Boolean[10];
for (int k = 0; k < 9; k++) //vertical
{
temp = solution[k * 9 + i];
if (temp != 0 && (k * 9 + i) <= upperIndexLimit)
{
if (values[temp])
{
Print(solution,upperIndexLimit); //DEBUGAUSGABE, fällt sie weg, funktioniert das Programm nicht mehr
return false;
}
else
values[temp] = true;
}
}
//---------------------------------------------------------------------------------
values = new Boolean[10];
for (int l = 0; l < 9; l++) //blockwise
{
temp = solution[i * 3 + (i / 3) * 18 + (l / 3) * 9 + (l % 3)];
if (temp != 0 && (i * 3 + (i / 3) * 18 + (l / 3) * 9 + (l % 3)) <= upperIndexLimit)
{
if (values[temp])
{
Print(solution, upperIndexLimit); //DEBUGAUSGABE, fällt sie weg, funktioniert das Programm nicht mehr
return false;
}
else
values[temp] = true;
}
}
}
return true;
}
Code:
private void Print(int[] solution, int upperIndex) {
for (int i = 0; i < 81; i++)
{
if (i % 9 == 0)
Console.WriteLine();
Console.Write(solution[i] + " ");
}
Console.WriteLine();
Console.WriteLine("UpperIndex = {0}",upperIndex);
}
