Guten Abend.
Bei meinem Sudoku möchte ich, dass das Programm, nachdem es die logischen Algorithmen zu NakedSingles und HiddenSingles angewendet hat, den Rest (existiert etwa ab Schwierigkeitsgrad Schwer verschiedener Anbieter) durch Systematisches Probieren löst.
Dazu ermittelt er erstmal alle leere Zellen und speichert diese in dem globalen dynmischen Array
LeereZellen: Array of Pos (Pos ist ein Record, der zwei Integerwerte x und y hat)
Da die Zahl der leeren Zellen je nach Situation von 0-81 (komplett gelöst-komplett leer) beträgt, nutze ich ein dynamisches Array.
Delphi-Quellcode:
procedure TForm4.LeereZellenBestimmen;
var Spalte,Zeile,i:integer;
begin
i:=-1;
For Spalte:=0 to 8 do
For Zeile:=0 to 8 do
If StringGrid1.cells[Spalte,Zeile]=' '
then
begin
inc(i);
SetLength(LeereZellen,i+1);
LeereZellen[i].x:=Spalte;
LeereZellen[i].y:=Zeile;
end;
end;
Dieses Array soll er dann rekursiv abarbeiten mit der Prozedur RestRaten, der Parameter Zelle ist dabei der Index des Arrays LeereZellen
Delphi-Quellcode:
procedure TForm4.RestRaten(Zelle:integer);
var i,Spalte,Zeile,Zahl:integer;
Sudoku:string;
Passt:boolean;
begin
Spalte:=LeereZellen[Zelle].x ;
Zeile:=LeereZellen[Zelle].y; //zur einfacheren Bearbeitung
For Zahl:=1 to 10 do //wenn Zahl=10, dann ist 1..9 kein Element der FeldMenge,
If Zahl in FeldMenge[Spalte,Zeile]
then
begin
Sudoku:=SudokuInListeSpeichern;
Sudoku[Zeile*9+Spalte+1]:=inttostr(Zahl)[1];
SudokuAusListeLaden(Sudoku); //Zahl reinschreiben und FeldMengen neu berechnen
If Zelle=high(LeereZellen) then exit; //wenn Zelle=high(LeereZellen) sind alle leeren Zellen regelkonform besetzt-->Sudoku gelöst
RestRaten(Zelle+1); //nächste leere Zelle bearbeiten
end;
If Zahl=10
then
begin
Sudoku:=SudokuInListeSpeichern;
Sudoku[LeereZellen[Zelle-1].x*9+LeereZellen[Zelle-1].y+1]:=' '; //Inhalt der vorherigen leeren Zelle löschen
SudokuAusListeLaden(Sudoku);
end;
end;
Der komplette Lösungsalgorithmus nutzt zuerst solange die logischen Prozeduren NakedSingles und HiddenSingles, bis sich nichts mehr ändert. Dann wird LeereZellenBestimmen aufgerufen, dann RestRaten(0).
Das ganze ist
eigentlich so gedacht, dass er bei RestRaten folgendes macht:
Füge in die erste leere Zelle die niedrigste regelkonforme Zahl ein und ändere die FeldMengen entsprechend.Dann füge die niedrigste regelkonforme Zahl in die zweite leere Zelle ein und ändere die FeldMengen entsprechend....etc.
Wenn du die Zahlen von 1-9 nicht einsetzen kannst (-->i=10), dann lösche den Inhalt der leeren Zelle vor der bearbeiteten und berechne die FeldMengen entsprechend.
Da 1-9 nicht einsgesetzt werden können, wird auch kein neues RestRaten aufgerufen,weswegen dieser Schritt dann einfach zuende geht. Die Zahl-Variable der leeren Zelle davor zählt also weiter, bis die zweitniedrigste regelkonforme Zahl gefunden wird (da ja mit der erstniedrigsten Zahl die nächste leere Zelle nicht besetzt werden kann), schreibe diese in diese leere Zelle (also die leere Zelle vor der leeren Zelle, die eben nicht besetzt werden konnte) und berechne die FeldMengen neu...etc.
Falls es etwas schwer verständlich war ein Beispiel:
In LeereZelle[6] kann eine 1 geschrieben werden. Also wird die 1 reingeschrieben, die FeldMengen neu berechnet und dann RestRaten(7) aufgerufen. Dieser findet heraus, dass in LeereZelle[7] keine Zahl regelkonform eingesetzt werden kann, weswegen die Zählschleife bei 10 landet. Nun löscht er den Zellinhalt von LeereZelle[6] und beendet RestRaten(7). Die nächsthöhere Rekursionsebene (bin mir nicht sicher, ob dieser Begriff richtig ist) RestRaten(6) wird nun weiter ausgeführt, die Zählschleife zählt Zahl auf 2 hoch und überprüft, ob die 2 regelkonform in LeereZelle[6] eingesetzt werden kann....etc.
Ich bin mir nicht sicher, wo mein Fehler liegt, das Programm weigert sich ganz einfach, dann den Zellinhalt zu löschen und eine Rekursionsebene höher zu gehen.
So füllt er z.B. bei einem leeren Sudoku die 1. Spalte mit 1-9 aus, füllt dann die ersten 3 Felder der 2. Spalte mit 4-6 aus und das 4.-6. Feld mit 1-3.
Für das 7. Feld gibt es nun keine gültige Zahl mehr, 1-6 stehen in derselben Spalte, 7-9 im selben Block. Also müsste er
theoretisch die 6. Zelle neu berechnen und höhere Zahlen einsetzen, das nächste wäre die 7. Das macht er aber nicht.
Zur Verdeutlichung habe ich mal die .exe Datei angehängt
(im startenden Hauptmenü auf Sudoku lösen klicken, der Löseknopf macht jetzt nur NakedSingles und HiddenSingles, Button 2 macht LeereZellenBestimmen,Button 3 macht RestRaten(0), so gemacht wegen Testen der Prozeduren)