• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

[C] Sudoku - Löser

No3x

Mitglied
Hallo, ich bin grad dabei einen Sudoku-Löser [C] zu schreiben, leider harkt es an der Stelle an der geprüft werden soll ob die Zahl in der Zeile schon vorhanden ist.

Das Problem liegt hauptsächlich bei Zeile 74-86.

PasteBin.de
Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

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

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


int zufallszahl;
int counter = 0;
int counter_ergebnis[9][2];
int i, j, k = 0;
int ergebnis = 0;
int counter_ergebnis_check = 0;
int runs = 0;

void print_matrix () {
    
    for (i = 0; i != 9; ++i)
    {
        for (j = 0; j != 9; ++j){ 
            
            printf("%d\t", sudokuMatrix[i][j]);
            
        }
        printf("\n\n");
    } 
} 

int new_zufallszahl() {
    srand(time(NULL));
    return rand()%9+1;
}
int main (int argc, const char * argv[]) {
    
    srand(time(NULL));
    print_matrix();
    while (ergebnis != 1 | runs != 2) {
        
        //1. Zufällige Zahlen einsetzen
        for (i = 0; i < 9; ++i)
        {//Zeile
            for (j = 0; j < 9; ++j) 
            {//Spalte 
                printf("Weiter mit beliebiger Taste\n");    
                int c = getchar();
                //Prüfen ob zu bearbeitende Zahl keine Ausgangszahl ist
                if(sudokuMatrix_compare[i][j] == 0) {
                    
                    printf("Target: sudokuMatrix[%d][%d], da Inhalt = %d oder unpassende Zahl\n", i, j, sudokuMatrix[i][j]);
                    
                    //Zufallszahl erzeugen
                    zufallszahl = new_zufallszahl();
                    for (k = 0; k < 9; ++k) 
                    {//Alle Spalten der Zeile prüfen, ob Zufallszahl schon in dieser Zeile vergeben ist
                        if (sudokuMatrix[i][k] == zufallszahl) {
                            printf("Zufallszahl %d in sudokuMatrix[%d][%d] schon vorhanden!\n", zufallszahl, i, j);
                            zufallszahl = new_zufallszahl();
                        } else {
                            //Aktuelle Stelle mit generierter Zufallszahl belegen
                            sudokuMatrix[i][j] = zufallszahl;
                            printf("sudokuMatrix[%d][%d] ist nun geandert zu %d\n", i, j, zufallszahl);
                            srand(time(NULL));
                            zufallszahl = new_zufallszahl();
                            
                        }
                        print_matrix();
                    }
                    
                } else {
                    printf("no Target: sudokuMatrix[%d][%d], da Inhalt = vorgegebene Zahl %d\n", i, j, sudokuMatrix[i][j]);
                }
    
            }
            printf("\n\n");
            //Aktuelle Lösung ausgeben
            print_matrix();
        } 
        
        //2. Prüfen ob die Summe jeder Zeile 45 ergibt
        
        for (i = 0; i != 9; i++)
        {
            int counter = 0;
            
            for (j = 0; j != 9; ++j) {
                counter += sudokuMatrix[i][j];
                
            }
            if (counter != 45) {
                counter_ergebnis[i][j] = 0;
                printf("Brute Force in %d(+1). Zeile fehlgeschlagen\n", i);
            } else if (counter == 45) {
                counter_ergebnis[i][j] = 1;
                printf("Brute Force in %d(+1). Zeile erfolgreich\n", i);
            }
            
            printf("Die Summe der Spalten der Zeile %d(+1) ergab %d\n\n", i, counter);
        }
        
        //3. Ergebnis
        counter_ergebnis_check = 0;
        for (i = 0; i != 9; ++i)
        {
            for (j = 0; j != 9; j++)
            {    
                printf("%d", counter_ergebnis[i][j]);
                if(counter_ergebnis[i][j] == 1) {
                    counter_ergebnis_check++;
                }    
            }    
            printf("\n\n");
        }
        if (counter_ergebnis_check == 9) {
            printf("Erfolgreich geloest.\n");
            print_matrix();
            ergebnis = 1;
        } else {
            printf("Counter bei %d\n", counter_ergebnis_check);
        }
        runs++;
    }
}
Ist mit Xcode geschrieben.

Kann mir jemand einen Tipp geben, wie ich am besten die Zeile prüfen kann, bevor die Zufallszahl eingesetzt wird?

btw:Bisher prüfe ich nur die Zeilen ob sie 45 ergeben, später dann auch die Spalten. Außerdem möchte ich es später ohne Brute-Force, mit mehr Logik, erledigen.
 
Hi,

du kannst doch ne Schleife über die Anzahl der Spalten in jeder Zeile laufen lassen und dabei vergleichen, oder?
 
Ist mein Ansatz nicht so wie du meinst? Du kannst es ja mal so bearbeiten, wie du es meinst. Ich schreibe hier, weil ich momentan nicht weiterkomme.
 
Was genau funktioniert da denn nicht? (Hab hier leider keinen C Compiler)

Ich würde vor dem einsetzen prüfen, ob das Feld überhaupt frei ist. Denn immer wenn die eingetragene Zahl != zufallszahl ist, wird diese dort eingetragen.
 
Er bleibt immer bei der ersten einsetzbaren Zahl hängen oder er füllt die ganze Zeile mit Zahlen, die sich aber wiederholen.

Die Prüfung ob die Zahl keine Ausgangszahl ist hab ich drin Zeile 69.
Code:
if(sudokuMatrix_compare[i][j] == 0)
PasteBin.de
Hier ein bisschen geändert, er soll nun alle Spalten der Zeile durchgehen, falls er die Zufallszahl schon findet wird die Variable zufallszahlbelegt größer als 0 und somit nicht mehr eingesetzt.

Hier mal das Ergebnis von zwei Durchläufen
Code:
1    3    0    0    0    0    0    0    0    

0    0    0    1    9    5    0    0    0    

0    9    8    0    0    0    0    6    0    

8    0    0    0    6    0    0    0    0    

4    0    0    0    0    3    0    0    1    

0    0    0    0    2    0    0    0    0    

0    6    0    0    0    0    2    8    0    

0    0    0    4    1    9    0    0    5    

0    0    0    0    0    0    0    7    0    

Weiter mit beliebiger Taste

no Target: sudokuMatrix[0][0], da Inhalt = vorgegebene Zahl 1
Weiter mit beliebiger Taste

no Target: sudokuMatrix[0][1], da Inhalt = vorgegebene Zahl 3
Weiter mit beliebiger Taste

Target: sudokuMatrix[0][2], da Inhalt = 0 oder unpassende Zahl
sudokuMatrix[0][2] ist nun geandert zu 5
1    3    5    0    0    0    0    0    0    

0    0    0    1    9    5    0    0    0    

0    9    8    0    0    0    0    6    0    

8    0    0    0    6    0    0    0    0    

4    0    0    0    0    3    0    0    1    

0    0    0    0    2    0    0    0    0    

0    6    0    0    0    0    2    8    0    

0    0    0    4    1    9    0    0    5    

0    0    0    0    0    0    0    7    0    



1    3    5    0    0    0    0    0    0    

0    0    0    1    9    5    0    0    0    

0    9    8    0    0    0    0    6    0    

8    0    0    0    6    0    0    0    0    

4    0    0    0    0    3    0    0    1    

0    0    0    0    2    0    0    0    0    

0    6    0    0    0    0    2    8    0    

0    0    0    4    1    9    0    0    5    

0    0    0    0    0    0    0    7    0    

Brute Force in 0(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 0(+1) ergab 9

Brute Force in 1(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 1(+1) ergab 15

Brute Force in 2(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 2(+1) ergab 23

Brute Force in 3(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 3(+1) ergab 14

Brute Force in 4(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 4(+1) ergab 8

Brute Force in 5(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 5(+1) ergab 2

Brute Force in 6(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 6(+1) ergab 16

Brute Force in 7(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 7(+1) ergab 19

Brute Force in 8(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 8(+1) ergab 7

000000000

000000000

000000000

000000000

000000000

000000005

000000675

000075500

008350000

Counter bei 0
Weiter mit beliebiger Taste

no Target: sudokuMatrix[0][0], da Inhalt = vorgegebene Zahl 1
Weiter mit beliebiger Taste

no Target: sudokuMatrix[0][1], da Inhalt = vorgegebene Zahl 3
Weiter mit beliebiger Taste

Target: sudokuMatrix[0][2], da Inhalt = 5 oder unpassende Zahl
sudokuMatrix[0][2] ist nun geandert zu 7
1    3    7    0    0    0    0    0    0    

0    0    0    1    9    5    0    0    0    

0    9    8    0    0    0    0    6    0    

8    0    0    0    6    0    0    0    0    

4    0    0    0    0    3    0    0    1    

0    0    0    0    2    0    0    0    0    

0    6    0    0    0    0    2    8    0    

0    0    0    4    1    9    0    0    5    

0    0    0    0    0    0    0    7    0    



1    3    7    0    0    0    0    0    0    

0    0    0    1    9    5    0    0    0    

0    9    8    0    0    0    0    6    0    

8    0    0    0    6    0    0    0    0    

4    0    0    0    0    3    0    0    1    

0    0    0    0    2    0    0    0    0    

0    6    0    0    0    0    2    8    0    

0    0    0    4    1    9    0    0    5    

0    0    0    0    0    0    0    7    0    

Brute Force in 0(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 0(+1) ergab 11

Brute Force in 1(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 1(+1) ergab 15

Brute Force in 2(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 2(+1) ergab 23

Brute Force in 3(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 3(+1) ergab 14

Brute Force in 4(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 4(+1) ergab 8

Brute Force in 5(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 5(+1) ergab 2

Brute Force in 6(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 6(+1) ergab 16

Brute Force in 7(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 7(+1) ergab 19

Brute Force in 8(+1). Zeile fehlgeschlagen
Die Summe der Spalten der Zeile 8(+1) ergab 7

000000000

000000000

000000000

000000000

000000000

000000005

000000677

000075700

008370000

Counter bei 0
Weiter mit beliebiger Taste
 
Also das Ganze Programm sieht mir ziemlich verworren aus. Wie genau soll dien Algorithmus aussehen? Ich habe da jetzt folgende herangehensweise gesehen:

1. Erzeuge eine Zufallszahl
2. Suche ein leeres Feld
3. Prüfe ob in der zugehörigen Zeile die vorher gewählte Zufallszahl schon vorhanden ist
3.1. Falls nein, setzt du die Zahl in das Feld ein
3.2. Falls ja, überspringst du sowohl dieses Feld als auch das nächste [Zeile 93]?!


Also dieser Algorithmus ist relativ ungeeignet um ein Sudoku zu lösen - du bräuchtest schon sehr, sehr, sehr viel Glück ein Sudoku nur mithilfe von Zufallszahlen zu lösen.


Ein etwas verbesserter Ansatz wäre es zum Beispiel, das Sudoku nur mithilfe von Logik zu lösen. Dazu legst du ein Array an, welches für jedes einzelne Feld speichert, welche Zahlen in diesem Feld noch nicht ausgeschlossen sind. Dann gehst du durch alle Felder durch:
Wenn das aktuelle Feld nicht leer ist, dann streiche in der Zeile, Spalte und in der Box diese Zahl aus den möglichen Zahlen raus.
Wenn das das erste mal durchgeführt ist, gehst du erneut durch alle Felder. Jedes Feld, welches dann nur noch eine Möglichkeit zur Belegung der Zahl hat, wird mit dieser Zahl belegt - danach wird diese Zahl in der Spalte, Zeile und Box ausgelöscht.

Das ganze lässt sich solange wiederholen, bis das Sudoku nicht mehr durch logisches Denken weiter ausfüllbar ist.


Bei der vorgegeben Matrix bringt diese herangehensweise jedoch kaum etwas, man kann damit höchstens drei Felder ausfüllen:
Code:
135      
   195   
 98    6 
8   6    
4    3  1
    2    
 6   [B]7[/B]28 
   419[B]63[/B]5
       7

In solch einen Fall muss man kompliziertere Methoden einführen. Ein vergleichsweise einfacher Ansatz wäre Backtracking. Hier müsste man 55 Felder backtracken, das klingt viel, muss es aber nicht sein. Wenn man das Array mit möglichen Zahlen aus dem logischen Ansatz nimmt, so haben alle Felder relativ wenige Möglichkeiten [die meisten 2-5].
Ich habe noch nie versucht soetwas zu implementieren, soetwas kann mitunter relativ kompliziert sein.


Wenn das allerdings immernoch zu viel Zeit in anspruch nimmt, muss man sich erst weiter mit der Theorie hinter Sudokus befassen -> Sudoku
 
Ich glaub ich lass es erstmal mit dem Sudoku und bleib bei der Arbeit mit Arrays, was eigentlich der Grund für den Versuch war.

3.2. Falls ja, überspringst du sowohl dieses Feld als auch das nächste [Zeile 93]?!
das war nur zum testen und aus Verzweiflung ob das etwas bringt.

Sieht jemand den Fehler warum die Zeilen nicht richtig ausgefüllt werden?
 
Sieht jemand den Fehler warum die Zeilen nicht richtig ausgefüllt werden?

Nunja, dein Progrmamablauf sieht folgendes vor:
1. Prüfe ob Feld (i, j) leer ist
1.1. Wenn es leer ist, dann erstelle eine Zufallszahl
1.1.1. Ist die Zufallszahl nicht in der Zeile vorhanden, so ersetze das Feld (i, j) durch diese Zahl
1.1.2. Ist die Zufallszahl vorhanden, wird einfach nichts gemacht. Der Zähler wird dann durch die Schleife bedingt erhöht und man betrachtet das nächste Feld.


Hier eine Verbesserungsmöglichkeit, um wenigstens die Zeilen füllen zu können:
1. Gehe durch eine Zeile durch, füge in ein Array alle Zahlen ein, welche nicht in der Zeile vorhanden sind
2. Mische dieses Array
3. Gehe erneut durch die Zeile, fülle in das erste leere Feld den ersten Eintrag des Arrays, in das zweite den zweiten Eintrag etc.


Machst du das alles jetzt nur als Übung um C zu lernen? Dann ist soetwas vermutlich eher weniger geeignet ;)
 
Danke für deinen Vorschlag, aber warum funktioniert es im Moment nicht? Ich such den Fehler ja jetzt dort und will ihn erkennen und nicht einfach drumherum arbeiten.
Joar ich lern derzeit C und nun sind Arrays dran. Habe vorher einiges mit PHP gemacht und kenne somit die grundlegenden Sachen, die sich ja innerhalb verschiedener Programmiersprachen nicht groß ändern. Der größte Nachteil im Vergleich zu PHP ist, dass man sich um die Datentypen kümmern muss. ^^
 
Der Fehler sollte sein, dass du j++ statt j-- in Zeile 93 aufrufst.



An die Datentypen gewöhnt man sich schnell, mittlerweile fällt es mir schwer ohne Datentypen zu programmieren. Der Vorteil liegt jedoch ganz klar darin, dass man ordentlicher und gründlicher arbeitet ;)
 
Ok, du hast verschiedene Fehler begangen:


1. Das srand(...) gehört nicht in die funktion new_zufallszahl rein. Damit wird der Zufallszahlengenerator immer wieder initialisiert - weil das Programm schnell genug läuft auch immer wieder mit der gleichen Zeit. Das Ergebnis ist, dass du immer einmal initialisiert und dann eine Zufallszahl erzeugt wird. Diese ist jedoch immer die Selbe.
Lösung: srand(...) dort rausnehmen und nur in der main() beibehalten

2. Lauffvariablen in Schleifen sollten nie global sein [mir fällt auch kein Beispiel ein wo es notwendig wäre]. Du hast sie global gemacht, damit geschieht folgendes: Die Schleifen in der main laufen durch, dazu gehört auch die innere. Nach dieser wird print_matrix() aufgerufen - dieses setzt jedoch i und j auf 0 zurück. Damit wird die äußere Schleife in der main niemals über den Wert 0 hinauskommen.
Lösung: Gloable Deklarationen von i, j und k entfernen. Stattdessen folgendes bei jeder Schleife:
Code:
int i;
for(i = 0; […])
Natürlich musst du dabei noch den Variablennamen anpassen. Wenn zwei Schleifen innerhalb des gleichen Blocks sind und gleiche Laufvariablen haben, so gibst du das "int i;" nur bei der ersten an.

3. Die Abbruchbedingung der while-Schleife ist falsch, du willst die Schleife solange durchgehen lassen, bis die Matrix gelöst wurde oder eine bestimmte Anzahl von durchgängen gemacht wurde:
Code:
while ((ergebnis != 1) && (runs != 100)) {

4. Zeile 69, hier musst du sudoku_matrix statt der _compare-Version nehmen.

5. Das counter_ergebnis Am Ende ergibt überhaupt keinen Sinn, das solltest du nochmal ganz überarbeiten.



Ich habs auf meinem Rechner soweit zum laufen gebracht [bis auf die Überprüfung ganz am Ende, da war ich zu faul zu], das sollten alle Fehler sein die ich korrigieren musste.
 
Vielen Dank Commodore!

Ich habe heut die Fehler, die du mir aufgezeigt hast, behoben. Funktioniert nun. Ich werde allerhöchstens nur horizontal und vertikal auf Richtigkeit prüfen können.
 
Zurück
Oben