Sudoku in C++ - Finde den Fehler einfach nicht

Diablokiller999

Enthusiast
Thread Starter
Mitglied seit
09.01.2004
Beiträge
2.054
Hi Leute!
Ich wollte für ein Studienfach ein einfaches Sudoku objektorientiert schreiben.
Nun habe ich aber das Problem, dass das Programm in einer Endlosschleife weiterläuft bzw. es abschmiert, wenn ich eine Funktion rekursiv aufrufe. Momentan soll erstmal das Spielfeld initialisiert und ausgegeben werden.
Hoffe die Kommentare sind gut gesetzt und verständlich. Finde das Problem einfach nicht, aber ein paar eingefügte cout's haben mir gezeigt, das es sich immer bei unterschiedlichen Feldern im Array aufhängt, deshalb tippe ich auf die rand-Funktion. Hab' das Programm schon 3mal neu geschrieben und selbst strukturiert kommt der selbe Fehler :confused:

Code:
#include <iostream>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

//Klasse fürs Spielfeld
class spielfeld{
public:     void init();
            int zufallszahl(int x, int y);
            int checkreihe(int zahl,int x);
            int checkspalte(int zahl, int y);
            int checkquadrat(int quadrat,int zahl);
            int getquadrat(int x, int y);
            void show();

private:    int feld[9][9];
};

//Initialisiert das Feld
void spielfeld::init(){
int x,y;
    for (x=0;x<9;x++)
        {
            for(y=0;y<9;y++){
                        feld[x][y]=zufallszahl(x,y);
            }
        }
//Löscht beliebige Zahlen aus dem Sudoku
    for(int del=0;del<35;del++){
        x=rand()%9+1;
        y=rand()%9+1;
        feld[x][y]=NULL;
    }

}

//Erzeugt eine Zufallszahl für Feld X-Y
int spielfeld::zufallszahl(int x, int y){
 /*REKURSIONSTEST

    //Zufallszahl zwischen 1 und neun generieren
    int zahl = rand()%9+1;
    //Schauen in welchem Quadrat das Feld liegt.
    int quadrat = getquadrat(x,y);

    if(checkquadrat(quadrat,zahl) == 0 && checkspalte(x,zahl)==0 && checkreihe(y,zahl) ==0 ) return zahl;
    else return zufallszahl(x,y);
    */

int zahl,quadrat;
//Holt die Information in welchem Quadrat des Sudoku's sich die Zahl befindet
quadrat=getquadrat(x,y);

//Macht die Schleife so lang, bis eine Zahl heraus kommt die weder in
//Reihe, Spalte noch Quadrat vorkommt, diese wird dann zurück gegeben
//Alle Funktionen müssen 0 zurückgeben!
do
{
    zahl=rand()%9+1;
}while((checkquadrat(quadrat,zahl))+(checkreihe(zahl,x))+(checkspalte(zahl,y))!=0);
return zahl;
}

//Schaut in welchem Quadrat sich die Koordinate befindet
int spielfeld::getquadrat(int x, int y){
    if(x >= 0 && x<=2 && y>= 0 && y<=2) return 0;
    if(x >= 0 && x<=2 && y>= 3 && y<=5) return 3;
    if(x >= 0 && x<=2 && y>= 6 && y<=8) return 6;

    if(x >= 3 && x<=5 && y>= 0 && y<=2) return 1;
    if(x >= 3 && x<=5 && y>= 3 && y<=5) return 4;
    if(x >= 3 && x<=5 && y>= 6 && y<=8) return 7;

    if(x >= 6 && x<=8 && y>= 0 && y<=2) return 2;
    if(x >= 6 && x<=8 && y>= 3 && y<=5) return 5;
    if(x >= 6 && x<=8 && y>= 6 && y<=8) return 8;
}

//Prüfet das Quadrat auf die gleiche Zahl
int spielfeld::checkquadrat(int quadrat,int zahl){
    int xstart,ystart;
    switch(quadrat) {
        case 0: xstart = 0; ystart = 0; break;
        case 1: xstart = 3; ystart = 0; break;
        case 2: xstart = 6; ystart = 0; break;
        case 3: xstart = 0; ystart = 3; break;
        case 4: xstart = 3; ystart = 3; break;
        case 5: xstart = 6; ystart = 3; break;
        case 6: xstart = 0; ystart = 6; break;
        case 7: xstart = 3; ystart = 6; break;
        case 8: xstart = 6; ystart = 6; break;
    }
    
    //Wenn Zahl existiert, wird der Wert 1
    for (int x = xstart; x <= (xstart + 2) ; x++) {
        for (int y = ystart ; y <= (ystart + 2) ; y++) {
            if (zahl == feld[x][y]) return 1;
        }
    }
    return 0;
}

//Prüft Reihe auf gleiche Zahl
int spielfeld::checkreihe(int zahl,int x){
    for(int y=0;y<9;y++)
    {
        if(feld[x][y]==zahl)
        return 1;
    }
return 0;
}

//Prüft Spalte auf gleiche Zahl
int spielfeld::checkspalte(int zahl,int y){
    for(int x=0;x<9;x++)
    {
        if(feld[x][y]==zahl)
        return 1;
    }
return 0;
}

//Gibt das Spielfeld aus
void spielfeld::show(){
for(int x=0;x<9;x++){
    for(int y=0;y<9;y++){
     cout<<feld[x][y];
    }
cout<<endl;

}

}

int main()
{   //Random-Initialisierung
    srand(time(NULL));
    spielfeld cSpielfeld;

    cSpielfeld.init();
    cSpielfeld.show();




    getchar();
    return 0;
}

Würde mich ja gern mit nem Debugger hinsetzen und das ganze mal durchchecken, aber ich habe keine Ahnung wie man debuggt. Hat da evtl. jemand ein gutes Tutorial für an der Hand?:fresse2:
 
Zuletzt bearbeitet:
Wenn Du diese Anzeige nicht sehen willst, registriere Dich und/oder logge Dich ein.
Wenn ich das richtig sehe versuchst du da ein Sudoku mit zufallszahlen zu befüllen. Das kann nicht funktionieren.

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

Jetzt gibt es für X keine Lösung. Das ist dann eine Endlosschleife. Trotzdem ist bis dahin alles richtig gelaufen. Genau dieses Problem wirst du mit Zufallszahlen aber sehr oft bekommen.
 
Wieso sollte es nicht funktionieren?
1 2 3 4 5 6 7 8 9
2
3
4
5
6
7
8
9

Abgesehen davon das im Sudoku ja in der 3x3er konstellation auch keine gleiche Zahl vorkommen kann. Versteh das Problem noch nicht >.>
 
1 2 3 4 5 6 7 8 9
2
3
4
5
6
7
8
9

Dein Vorschlag wäre also X=1. Mein Beispiuel sähe dann so aus:

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

Das klappt ganz sicher nicht.

Abgesehen davon das im Sudoku ja in der 3x3er konstellation auch keine gleiche Zahl vorkommen kann.

Ja mein Fehler. Das hab ich in dem Beispiel nicht beachtet. Kannst die Zahlen ja etwas umstellen damit auch diese Regel erfüllt ist. Am Problem ändert das ja nichts. Nehmen wir für alles weitere einfach folgendes Beispiel:

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

Das Problem ist einfach, dass du die 2 Reihen mit Zufallszahlen so füllen kannst, dass die generierung einer weiteren Zufallszahl in einer endlosschleife endet weil es einfach keine Zahl gibt die dort reinpassen würde. Du hast dann ein nicht lösbarer Sudoku generiert bzw die Generierung endet in einer Endlosschleife.
 
Zuletzt bearbeitet:
Also ist mein Algorythmus falsch.Mit Glück wirds klappen, in den meisten Fällen also nicht...
Gut, dann werd' ich mir wohl einen neuen ausdenken müssen, THX :)
 
Zuletzt bearbeitet:
Sieht danach aus. Du könntest bei der Rekursion einfach einen zähler mitlaufen lassen und die Generierung bei 100 Versuchen abbrechen und dir das bis dahin generierte Feld anzeigen lassen. Das dürfte dann zweifelsfrei zeigen ob ich mit meiner Vermutung richtig liege.
 
Ok das debuggen kannst du dir sparen. Mir ist ein besseres Beispiel eingefallen was dein aktueller Quellcode hinbekommt.

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

Bis zur Zahl X hat der Quellcode alles richtig gemacht. Für X gibt es keine Lösung. Das ist dann eine wunderbare Endlosschleife. Das ganze bereits in der 2. Reihe.
Nun ist die Warscheinlichkeit in der 2. Reihe bereits einen Solchen Fall zu generieren relativ gering. Genauergesagt darf 8 mal nicht zufällig die Zahl gezogen werden, die in der Reihe darüber an der letzten Stelle steht. Wenn bei den 8 Zufallszahlen diese Zahl dabei ist, geht die Reihe auch auf. Betrachten wir doch aber mal die 5 Reihe. Da sieht die Rechnung schon deutlich anders aus. Die darüber liegenden Reihen haben in der letzten Spalte bereits 4 Zahlen die in der 5. Reihe alle und ich betone wirklich alle in den ersten 8 Stellen vorhanden sein müssen. Wenn auch nur eine der Zahlen für die letzte Spalte übrig bleibt, ist das wieder eine Endlosschleife.
Die Sache mit den 3X3 Quadranten ist ein zusätzliches nettes Endlosschleifenrisiko.

Es sieht also so aus als würde es mehr potentielle Endlosschleifen als richtige Lösungen geben. Es würde mich nicht mal wundern wenn das Gesammtrisiko für eine Endlosschleife bei über 99% liegt.

Dein Lösungsansatz mit der Endlosschleife ist trotzdem nicht verkehrt. Bau einfach einen Zähler ein. Wenn du nach 100 Zufallszahlen keinen Treffer hast, einfach das komplette Spielfeld verwerfen und nochmal Versuchen. Der Computer schafft problemlos tausende Spielfelder in der Sekunde. Da sollte sich innerhalb von sagen wir mal einer Minute doch ein gültiges Spielfeld generieren lassen.
 
Zuletzt bearbeitet:
Hi,
ein netter Ansatz ist auch hier zu finden:
SUDOKU ALgorithmus

Dort wird vorgeschlagen, erst einen Lösungsalgorhythmus zu machen.
Dann wird ein Feld mit einer Zufallszahl belegt und der Lösungsalg. drauf losgelassen. Somit erhält man (theoretisch) ein neues, lösbares Sudoku.

Ansonsten finden sich bei google natürlich viele (effizientere) Lösungen und Algorhythmen. Aber ich denk hier steht ja selbt entwerfen und lernen im Vordergrund ;)
Mfg.
 
Zuletzt bearbeitet:
Hardwareluxx setzt keine externen Werbe- und Tracking-Cookies ein. Auf unserer Webseite finden Sie nur noch Cookies nach berechtigtem Interesse (Art. 6 Abs. 1 Satz 1 lit. f DSGVO) oder eigene funktionelle Cookies. Durch die Nutzung unserer Webseite erklären Sie sich damit einverstanden, dass wir diese Cookies setzen. Mehr Informationen und Möglichkeiten zur Einstellung unserer Cookies finden Sie in unserer Datenschutzerklärung.


Zurück
Oben Unten refresh