Sudoku Löser in C
-
Hallo,
im Rahmen meines Studiums sollen wir im Fach Informatik ein Programm in C entwerfen, welches ein beliebig vorgegebenes Sudoku löst.
Folgende Aufgabenstellung wurde uns gegeben:- das Programm soll einfache Prozeduren für die Lösung benutzen
- zusätzlich soll das programm für die iterative Lösungssuche rekursive Prozeduren einsetzen
- der Quellcode der einzelnen Funktionen soll aus nicht mehr als 45 Anweisungen bestehen
- die Aufteilung des programms in Funktionen hat nach den prinzipien "strong cohesion" und "loose coupling" zu erfolgen
- der aktuelle Lösungszustand ist als "struct"-Variable zu speichernBis jetzt habe ich folgendes Programm noch ohne Strukturen geschrieben, welches die Möglichkeiten pro Feld heraussucht und nach dem Ausschlussverfahren (Möglichkeiten pro Zeile, Spalte und 3er-Block) schon einzelne Zahlen ermittelt. Der dritte Index von Sudoku steht an der Nullten Stelle für eine Variable oder feste Variable - ist als Kommentar im Programm erklärt. Der dritte Index von 1 bis 9 steht für die Möglichkeiten an zahlen in diesem Feld. ist also bei [3], [4], [5] die Werte 1, 0, 1 , so heißt das, dass eine 3 oder 5 in diesem Feld, dass du die ersten beide Indexe bestimmt wird, stehen muss.
Eventuell schlechte Einrückungen kommen vom Compiler LCCWin32, welchen wir nutzen...meine Frage ist jetzt: Wie mach ich weiter? Ich weiß nicht, wie ich das systematische Probieren umsetzen soll.. was habt ihr für Vorschläge?
#include <stdio.h> int main(void) { int zeile,spalte,element, laufvar,laufvar2,laufvar3, block_s,block_z, anz_ausgeschl; char vorgabe[9][9] = { '0', '7', '0', '6', '0', '0', '0', '8', '0', '6', '0', '0', '5', '0', '0', '0', '0', '0', '0', '0', '9', '0', '0', '4', '0', '5', '0', '1', '2', '0', '0', '0', '0', '9', '6', '0', '0', '0', '0', '0', '2', '0', '4', '0', '0', '0', '0', '6', '0', '0', '0', '0', '0', '0', '0', '0', '0', '4', '3', '0', '1', '0', '7', '2', '0', '5', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '8', '0', '0' }; char sudoku[9][9][10]; // Überprüfen auf feste und variable Eingaben // 0. Element = 1 --> Wert variabel // 0. Element = 0 --> Wert fest for (zeile = 0; zeile < 9; zeile++) for (spalte = 0; spalte < 9; spalte++) { for (element = 0; element <= 9; element++) sudoku[zeile][spalte][element]='0'; switch (vorgabe[zeile][spalte]) { case '0' : { for (laufvar = 0; laufvar <= 9; laufvar++) sudoku[zeile][spalte][laufvar]='1'; break; }; default : { for (laufvar = 1; laufvar <=9; laufvar++) sudoku[zeile][spalte][laufvar] = '.'; break; }; }; switch (vorgabe[zeile][spalte]) { case '1' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][1]='1'; break; }; case '2' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][2]='1'; break; }; case '3' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][3]='1'; break; }; case '4' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][4]='1'; break; }; case '5' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][5]='1'; break; }; case '6' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][6]='1'; break; }; case '7' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][7]='1'; break; }; case '8' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][8]='1'; break; }; case '9' : { sudoku[zeile][spalte][0]='0'; sudoku[zeile][spalte][9]='1'; break; }; }; }; // Vorgegebene Zahlen als Möglichkeiten aus // Zeile, Spalte und Block entfernen for (zeile = 0; zeile < 9; zeile++) for (spalte = 0; spalte < 9; spalte++) if (sudoku[zeile][spalte][0] == '1') // Wenn variabel ... // Loeschen der Festwertzahl als Mgl. aus Zeile { for (laufvar = 0; laufvar < 9; laufvar++) if (sudoku[laufvar][spalte][0] == '0') // Wenn fest for (laufvar2 = 1; laufvar2 <= 9; laufvar2++) if (sudoku[laufvar][spalte][laufvar2] == '1') sudoku[zeile][spalte][laufvar2] = '.'; // Loeschen der Festwertzahl als Mgl. aus Spalte for (laufvar = 0; laufvar < 9; laufvar++) if (sudoku[zeile][laufvar][0] == '0') // Wenn fest for (laufvar2 = 1; laufvar2 <= 9; laufvar2++) if (sudoku[zeile][laufvar][laufvar2] == '1') sudoku[zeile][spalte][laufvar2] = '.'; // Loeschen der Festwertzahl als Mgl. aus Block // Bestimmen des aktuellen Blocks if (zeile < 3) block_z = 3; else if ( (zeile >= 3) && (zeile < 6) ) block_z = 6; else if (zeile >= 6) block_z = 9; if (spalte < 3) block_s = 3; else if ( (spalte >= 3) && (spalte < 6) ) block_s = 6; else if (spalte >= 6) block_s = 9; for (laufvar = block_z-3; laufvar < block_z; laufvar++) for (laufvar2 = block_s-3; laufvar2 < block_s; laufvar2++) if (sudoku[laufvar][laufvar2][0] == '0') for (laufvar3 = 1; laufvar3 <= 9; laufvar3++) if (sudoku[laufvar][laufvar2][laufvar3] == '1') sudoku[zeile][spalte][laufvar3] = '.'; }; // Wenn alle Ziffern bis auf eine ausgeschlossen sind, dann ist diese // als Festwertzahl zuzuordnen for (zeile = 0; zeile < 9; zeile ++) for (spalte = 0; spalte < 9; spalte++) if (sudoku[zeile][spalte][0] == '1') // Wenn variabel ... { anz_ausgeschl = 0; for (element = 1; element <= 9; element++) if (sudoku[zeile][spalte][element] == '.') anz_ausgeschl++; if (anz_ausgeschl == 8) sudoku[zeile][spalte][0] = '0'; } // Ausgabe printf("Eingegebene Matrix:\n"); for (zeile = 0; zeile < 9; zeile ++) { printf("\n"); for (spalte = 0; spalte < 9; spalte++) { printf(" %c", vorgabe[zeile][spalte] ); }; }; printf("\n\n"); printf("Moeglichkeiten Matrix:\n"); for (zeile = 0; zeile <9; zeile++) { printf("\n"); if ( (zeile == 3) || (zeile == 6) ) printf("\n"); for (spalte = 0; spalte <9; spalte++) { if ( (spalte == 3) || (spalte == 6) ) printf(" "); printf(" "); for (element = 0; element <=9; element++) printf("%c", sudoku[zeile][spalte][element]); }; }; // systematisches Probieren return(0); }
-
Habe das Programm mit Strukturen geschrieben..
Weiterhin bleibt aber die Frage: Wie soll ich nach dem Aussortieren der Möglichkeiten der Zahlen für die einzelnen Felder durch überprüfen, ob Zahlen im Block, der gleichen Zeile und der gleichen Spalte bereits vorhanden sind, weiter fortfahren?
Eigentlich steht ja jetzt nur systematisches Probieren an, aber wie kann man das bewerkstelligen?#include <stdio.h> struct dt_sudoku { char vorgabe[9][9]; char moeglichk[9][9][10]; }; typedef struct dt_sudoku sud; // Eingabe void eingabe(sud *sdk) { int zeile, spalte; char eing[9][9] = { '0', '7', '0', '6', '0', '0', '0', '8', '0', '6', '0', '0', '5', '0', '0', '0', '0', '0', '0', '0', '9', '0', '0', '4', '0', '5', '0', '1', '2', '0', '0', '0', '0', '9', '6', '0', '0', '0', '0', '0', '2', '0', '4', '0', '0', '0', '0', '6', '0', '0', '0', '0', '0', '0', '0', '0', '0', '4', '3', '0', '1', '0', '7', '2', '0', '5', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '8', '0', '0' }; // Eingabe wird an sdk übergeben, um raus aus Funktion for (zeile = 0; zeile < 9; zeile++) for (spalte = 0; spalte < 9; spalte++) // Pfeil-Operator sdk->vorgabe[zeile][spalte] = eing[zeile][spalte]; // oder als Punkt-Operator //(*sdk).vorgabe[zeile][spalte] = eing[zeile][spalte]; return; }; // Festwertzahlen in der Eingabe bestimmen void festwertzahlen_bestimmen(sud *sdk) { int zeile, spalte, element, laufvar; // Überprüfen auf feste und variable Eingaben // 0. Element = 1 --> Wert variabel // 0. Element = 0 --> Wert fest for (zeile = 0; zeile < 9; zeile++) for (spalte = 0; spalte < 9; spalte++) { for (element = 0; element <= 9; element++) (*sdk).moeglichk[zeile][spalte][element]='0'; switch ((*sdk).vorgabe[zeile][spalte]) { case '0' : { for (laufvar = 0; laufvar <= 9; laufvar++) (*sdk).moeglichk[zeile][spalte][laufvar]='1'; break; }; default : { for (laufvar = 1; laufvar <=9; laufvar++) (*sdk).moeglichk[zeile][spalte][laufvar] = '.'; break; }; }; switch ((*sdk).vorgabe[zeile][spalte]) { case '1' : { (*sdk).moeglichk[zeile][spalte][1]='1'; break; }; case '2' : { (*sdk).moeglichk[zeile][spalte][2]='1'; break; }; case '3' : { (*sdk).moeglichk[zeile][spalte][3]='1'; break; }; case '4' : { (*sdk).moeglichk[zeile][spalte][4]='1'; break; }; case '5' : { (*sdk).moeglichk[zeile][spalte][5]='1'; break; }; case '6' : { (*sdk).moeglichk[zeile][spalte][6]='1'; break; }; case '7' : { (*sdk).moeglichk[zeile][spalte][7]='1'; break; }; case '8' : { (*sdk).moeglichk[zeile][spalte][8]='1'; break; }; case '9' : { (*sdk).moeglichk[zeile][spalte][9]='1'; break; }; }; // Zusatz zu zweiter Switch-Anweisung, bei Zahl in Eingabe // 0. Element = fest if ((*sdk).vorgabe[zeile][spalte] != '0') (*sdk).moeglichk[zeile][spalte][0]='0'; }; return; }; // Vorgegebene Zahlen als Möglichkeiten aus // Zeile, Spalte und Block entfernen void moeglichkeiten_bestimmen(sud *sdk) { int zeile,spalte, laufvar,laufvar2,laufvar3, block_s,block_z; for (zeile = 0; zeile < 9; zeile++) for (spalte = 0; spalte < 9; spalte++) if ((*sdk).moeglichk[zeile][spalte][0] == '1') // Wenn variabel ... // Loeschen der Festwertzahl als Mgl. aus Zeile { for (laufvar = 0; laufvar < 9; laufvar++) if ((*sdk).moeglichk[laufvar][spalte][0] == '0') // Wenn fest for (laufvar2 = 1; laufvar2 <= 9; laufvar2++) if ((*sdk).moeglichk[laufvar][spalte][laufvar2] == '1') (*sdk).moeglichk[zeile][spalte][laufvar2] = '.'; // Loeschen der Festwertzahl als Mgl. aus Spalte for (laufvar = 0; laufvar < 9; laufvar++) if ((*sdk).moeglichk[zeile][laufvar][0] == '0') // Wenn fest for (laufvar2 = 1; laufvar2 <= 9; laufvar2++) if ((*sdk).moeglichk[zeile][laufvar][laufvar2] == '1') (*sdk).moeglichk[zeile][spalte][laufvar2] = '.'; // Loeschen der Festwertzahl als Mgl. aus Block // Bestimmen des aktuellen Blocks if (zeile < 3) block_z = 3; else if ( (zeile >= 3) && (zeile < 6) ) block_z = 6; else if (zeile >= 6) block_z = 9; if (spalte < 3) block_s = 3; else if ( (spalte >= 3) && (spalte < 6) ) block_s = 6; else if (spalte >= 6) block_s = 9; for (laufvar = block_z-3; laufvar < block_z; laufvar++) for (laufvar2 = block_s-3; laufvar2 < block_s; laufvar2++) if ((*sdk).moeglichk[laufvar][laufvar2][0] == '0') for (laufvar3 = 1; laufvar3 <= 9; laufvar3++) if ((*sdk).moeglichk[laufvar][laufvar2][laufvar3] == '1') (*sdk).moeglichk[zeile][spalte][laufvar3] = '.'; }; return; }; void zuordnung_festwertzahlen(sud *sdk) { int zeile, spalte, element, anz_ausgeschl; // Wenn alle Ziffern bis auf eine ausgeschlossen sind, dann ist diese // als Festwertzahl zuzuordnen for (zeile = 0; zeile < 9; zeile ++) for (spalte = 0; spalte < 9; spalte++) if ((*sdk).moeglichk[zeile][spalte][0] == '1') // Wenn variabel ... { anz_ausgeschl = 0; for (element = 1; element <= 9; element++) if ((*sdk).moeglichk[zeile][spalte][element] == '.') anz_ausgeschl++; if (anz_ausgeschl == 8) (*sdk).moeglichk[zeile][spalte][0] = '0'; }; }; // Ausgabe void ausgabe(sud *sdk) { int zeile, spalte, element; printf("Eingegebene Matrix:\n"); for (zeile = 0; zeile < 9; zeile ++) { printf("\n"); for (spalte = 0; spalte < 9; spalte++) { printf(" %c", (*sdk).vorgabe[zeile][spalte] ); }; }; printf("\n\n"); printf("Moeglichkeiten Matrix:\n"); for (zeile = 0; zeile <9; zeile++) { printf("\n"); if ( (zeile == 3) || (zeile == 6) ) printf("\n"); for (spalte = 0; spalte <9; spalte++) { if ( (spalte == 3) || (spalte == 6) ) printf(" "); printf(" "); for (element = 0; element <=9; element++) printf("%c", (*sdk).moeglichk[zeile][spalte][element]); }; }; printf("\n"); return; }; // Hauptprogramm int main(void) { sud sdk; eingabe(&sdk); festwertzahlen_bestimmen(&sdk); moeglichkeiten_bestimmen(&sdk); zuordnung_festwertzahlen(&sdk); ausgabe(&sdk); // systematisches Probieren return(0);
-
10 Bits passen immer in ein int, deshalb wäre die kanonische Deklaration:
int moeglichk[9][9]; /* Wenn alle Elemente in moeglichk auf 0 gesetzt sind, setzt man die Bits etwa so: */ moeglichk[a][b] &= (1 << i); /* Und liest sie etwa so aus:*/ ist_5_noch_moeglich = moeglichk[a][b] & (1 << 4)
Statt (*pt).elem schreibt man eleganter pt->elem.
In Zeile 47 und 57 hast du zwei gleiche switches, den unteren mit einer menge redundatem Code daran. Das verdirbt einem leider das Verständnis.
Lass die leeren Anweisungen weg z.B. Zeile 51, 55, 56.
Ohne zu zählen, wette ich, dass deine funktion moeglichkeiten_bestimmen mehr als 45 Anweisungen hat...
Wenn man probieren muss gibt es zwei Fälle: im ersten hat man die Lösung erraten, im zweiten wird man einen Widerspruch erhalten, d.h. die Möglichkeiten werden irgendwo für keine Ziffer mehr bestehen.
-
Hallo,
was meisnt du mit leeren Anweisungen? Kann doch nicht einfach die schließenden Klammern weglassen? Denn eine Vorgabe für den Stil unserer Programme ist die "freie Sicht"... Das heißt, dass öffnende und schließende Klammer vertikal untereinander stehen sollen, um die Einrückungen zu sehen.
Deinen Code verstehe ich leider nicht so ganz. Kannst du mir das nochmal erläutern?
-
Ein Semikolon ';' schließt eine einzige Anweisung ab, ein Block wird
durch die Klammer '}' geschlossen.
Von Verzweigungen hängen einzelne Anweisungen oder Blöcke ab.
Also bedeutetwhile(cond) do();
das gleiche wie
while(cond) { do(); }
Daher bedeutet
while(cond) { do(); };
das gleiche wie
while(cond) do(); ; /* <----- leere Anweisung */
Denn eine Vorgabe für den Stil unserer Programme ist die
"freie Sicht"...Damit hast du's dann aber recht schwer mit sowas:
case '0' : { for (laufvar = 0; laufvar <= 9; laufvar++)
weil du immer die schliessende Klammer mit Leerzeichen in
die freie Sicht rücken must...Es ist viel schönerer Stil, zusammengehörige Boolsche Variablen in
einigen Bits zu speichern, als dafür chars zu verwenden.
Eine int-Variable bietet dir auf deinem System
sizeof(int) Bytes = 8 * sizeof(int) Bits Speicherplatz.
C stellt bitweise Operatoren zur Verfügung (~ & ^ | << >>).
Die sollte man halt schon kennen. Dann drei Makros und fertig:/* 1111111111 binär ist hexadezimal 0x03ff */ #define ALLEM (0x03ff) /* um herauszufinden, ob ZIFFER moeglich ist */ #define MOEGL(INTEGER, ZIFFER) \ ((INTEGER & (1 << (ZIFFER - 1))) ? 1 : 0) /* um ZIFFER moeglich zu machen */ #define SETZEM(INTEGER, ZIFFER) \ (INTEGER | (1 << (ZIFFER - 1))) /* um ZIFFER unmoeglich zu machen */ #define LOESCHEM(INTEGER, ZIFFER) \ (INTEGER & ~(1 << (ZIFFER - 1))) /* dann könnte ich das so machen */ unsigned int i = ALLEM; printf("%d\n", MOEGL(i, 5)); /* ist 5 moeglich? */ i = LOESCHEM(i, 5); printf("%d\n", MOEGL(i, 5)); /* ist 5 moeglich? */ i = SETZEM(i, 5); printf("%d\n", MOEGL(i, 5)); /* ist 5 moeglich? */ /* Und ich hätte 810 chars (810 bytes) getauscht gegen 81 ints (für gewöhnlich 324 bytes) aber short würde ja auch reichen */
Du darfst eben nicht verwirrst sein, weil wir Integers benutzen, um Bits zu
setzen. Für uns sollen die Stellen der Binärzahl ja bedeuten, ob die der
Stelle zugeordnete Ziffer noch möglich ist. Z.B. die Binärzahl(führende Nullstellen) 10 1000 0010
soll für uns bedeuten, dass nur mehr die Ziffern 10 (zehnte Stelle),
8 (achte Stelle) und 2 (zweite Stelle) möglich sind.
Es darf dich nicht betrüben, dass diese Zahl für printf was anderes bedeutet,
nämlich512 + 128 + 2 = 642
Alle Möglichkeiten bestehen also bei
(führende Nullstellen) 11 1111 1111 = 0x03ff = 1023
Bei den Makros gehe ich davon aus, dass ZIFFER der Zahlenwert der Ziffer ist,
also 5 für '5', nicht ihr ASCII Wert 53. Wenn du die Ziffer als ASCII Wert hast,
rechnest du um mit Ziffer = ASCII_Wert - '0'.Erklär mir bitte trotzdem, warum du in den Zeilen 47 und 57 den gleichen
switch hast und warum du beim zweiten überhaupt einen switch verwendest!Die Zeilen 57 bis 85 kann mann stark verkürzen:
if (sdk->vorgabe[zeile][spalte] > '0' && sdk->vorgabe[zeile][spalte] <= '9') sdk->moeglichk[zeile][spalte][sdk->vorgabe[zeile][spalte] - '0'] = '1';
Die beiden Zeilen haben den gleichen Effekt wie deine 29.
- der aktuelle Lösungszustand ist als "struct"-Variable zu speichern
Du kannst deinem Lehrer ruhig sagen, dass das eine didaktische Nullaussage ist,
weil in einer Struktur wiederum alles sein kann. Du hättest das
Array moeglichk auch allein (sogar global) definieren können,
die Struktur hast du ja wirklich nur aus Autoritätsglauben.
Das Array vorgabe hast du ja ohnehin nur als Eingabe,
die im wirklichen Leben wahrscheinlich nicht in dieser Form vom Terminal kommen wird.
Du wirst ja dann die Eingabedaten (die dein Programm ja irgendwann nicht mehr
aus dem Quelltext beziehen soll) gleich umrechnen und in moeglichk
speichern, also vorgabe gar nicht brauchen.
Deshalb hat vorgabe in der Struktur eigentlich nichts zu suchen;
es hat auch nichts mit dem aktuellen Lösungszustand zu tun.So. Nach einigen Edits habe ich mich nun länger mit deiner Hausübung befasst. Ich weise dich darauf hin, dass sie hier keiner für dich machen wird, aber wir dir gerne bei Problemen weiterhelfen. Bis dahin solltest du deinen Code kürzen, damit ihn die anderen schneller verstehen als ich. Da ist noch das unwichtigste, ob du mit chars oder Integer-Bits arbeitest.
-
Vielen vielen dank für diese ausführliche Antwort. Hast dich ja richtig ins Zeug gelegt. Werde deine Tipps und Hinweise morgen umsetzen und melde mich dann wieder. Habe jetzt auch einen Algorithmus herausgefunden um die restlichen Felder des Sudoku zu lösen.
Das mit der freien Sicht gefällt mir leider auch nicht so, aber leider prüft unser Prof in Form von Testaten jede Woche den aktuellen Wissens- und Verständnisstand ab und verlangt dabei von uns seine Stilvorgaben einzuhalten (damit ers wohl einfacher hat). Diese Testate dienen dazu, dass man erst zur Prüfung zugelassen wird... aber will darauf nicht weiter eingehen.
Das mit der leeren Anwerisung hab ich jetzt verstanden. Wusste zuerst nicht was du meisnt. Besten dank.
Das mit den Zeilen kürzen ist mir so gar nicht in den Sinn gekommen. Anfängerfehler ebenAber super, dass du das gesehen hast. Nur aus Fehlern lernt man ja ...
Der Vorschlag mit der Speicherung der Möglichkeiten je Feld als Binärzahl ist wirklich gut, werde aber wahrscheinlich dennoch die Speicherung als char beibehalten, da das Programm nicht effizient sein muss und unser Prof sonst im Testat nur dumme Frage stellt(wir müssen das Programm vorstellen, erklären und auf Fragen zum Quelltext antworten können und falls er Veränderungen am Quelltext vornehmen möchte deren Auswirkungen auf das Programm erklären. Falls man dabei nen Fehler macht dann hat man schon halbes Fehltestat und bei mehreren fehlern ist das ein komplettes Fehltestat und man kann es wiederholen. Bei 3 Fehltestaten wird man nicht zur Prüäfung zugelassen. Deswegen halte ich mich da strikt an seine Dummen Regeln. Ist zwar blöd aber nur so kann ich Info bestehen).
Werde aber für mich persönlich nach dem Testat das Programm mit Speicherung als Binärzahlen umschreiben. Finde das wirklich gut die Idee
Zu der Eingabe: Das habe ich bisher so gelöst, damit ich nicht bei jeder Ausführung des Programms die Matrix eingeben muss. Das Array vorgabe wird bei fertigem Programm entfernt und eine Eingabesequenz geschrieben, die die Eingabe direkt im Feld moeglichk speichert...
Jiss
-
Stil ist Schall und Rauch.
Vielen vielen dank für diese ausführliche Antwort. Hast dich ja richtig ins Zeug gelegt.
Ich will ja auch sehen, was am Ende rauskommt.
Werde aber für mich persönlich nach dem Testat das Programm mit Speicherung als Binärzahlen umschreiben. Finde das wirklich gut die Idee
Weil sie so gut ist, ist sie älter als ich.
-
Werde aber für mich persönlich nach dem Testat das Programm mit Speicherung als Binärzahlen umschreiben. Finde das wirklich gut die Idee
Noch einmal bedacht: das ist eigentlich nicht nötig, weil ich's schon getan habe.
Siehe:/* so machst du's: */ typedef struct dt_sudoku { char moeglichk[9][9][10]; /* der Rest ist egal */ } sud; /* so mach ich's: */ typedef struct dt_sudoku { /* short ist besser als int, hat auch immer mind. 2 Bytes */ short moeglichk[9][9]; } sud; /* egal, wie man's macht, man muss nur die drei Makros anpassen ;) Wenn ich recht verstanden habe, dann bedeutet '0' bei dir: unmöglich und '1': möglich. moeglichk hat in der tiefsten Ebene 10 Elemente, also eines zu viel. Afaik ist das nullte bei dir egal. Also: */ #define MOEGL(POINTER, ZIFFER) \ (((POINTER)[ZIFFER]) == '1' ? 1 : 0) /* um ZIFFER moeglich zu machen */ #define SETZEM(POINTER, ZIFFER) \ ((POINTER)[ZIFFER] = '1') /* um ZIFFER unmoeglich zu machen */ #define LOESCHEM(POINTER, ZIFFER) \ ((POINTER)[ZIFFER] = '0') /* weil die Sache mit ALLEM in der Zuweisung an ein Array nicht geht, mache ich noch ein Makro, um alle M. zu setzen */ #define SETZEALLEM(POINTER) \ { for (int i = 0; i < 10; i++) { (SETZEM(POINTER, i)); } } /* in meinem Fall (mit ints) muss SETZEALLEM lauten: */ #define SETZEALLEM(INTEGER) \ ((INTEGER) = 0x0377)
Nun ist es egal, ob du moeglichk deklarierst als int[][] oder char[][][], wenn du nur mehr die jeweiligen Makros verwendest. Wenn dein Professor fragt, warum du die Makros hast, sagst du einfach: weil's so klarer ist. Und wenn er nicht herschaut, änderst du die Deklaration von moeglichk und nimmst die anderen Makros. Sonst müsste man nichts am Code ändern, wenn du die Makros konsequent verwendet. Ein Aufruf sieht immer so aus:
MOEGL(sdk->moeglichk[1][2], 5) /* sieht nach, ob im Feld (1,2) noch 5 möglich ist */
Wenn du's dann zum Laufen gebracht hast, wär's schön, wenn du mir eine Kopie geben könntest. (Ich brauche nämlich auch einen Sudoku-Löser, den ich verstehe, nur nicht so dringed wie du
)