|
Antwort |
Registriert seit: 13. Feb 2010 33 Beiträge |
#1
Hallo,
mein Sudoku ist jetzt schon 'relativ' weit, er löst die meisten Sudokus (Nutzung von NakedSingles sowie HiddenSingles der Zeile&Spalte). Es ist nicht möglich, in eine bereits beschriebene Zelle eine Zahl rein zu schreiben, stattdessen wird der Zellinhalt mittels Entf oder Backspace gelöscht. Mein Ansatz dabei ist, dass erstmal die gelöschte Zahl zu den FeldMengen der Zellen der gleichen Zelle, Spalte, Block hinzugefügt werden. Es ist jedoch auch möglich, dass eine Zahl nicht in einer Zelle stehen darf (=kein Element der FeldMenge),weil es diese Zahl bereits in der selben Spalte und der selben Zeile steht. Würde man die Zahl aus der Zeile löschen, so würde in der FeldMenge der betroffenen Zelle die Zahl stehen, obwohl die Zahl in der selben Spalte steht, was nicht regelkonform ist. Daher wird so getan, als ob alle Zahlen neu eingegeben werden und dadurch die betreffenden FeldMengen reduziert werden. Fall 1: Alle vorgegebenen Zahlen werden fehlerfrei eingegeben --> Programm löst das Sudoku Fall 2: Alle vorgegebenen Zahlen werden eingegeben, jedoch muss man einmal eine Zahl (die regelkonform ist) löschen und stattdessen eine andere Zahl eingeben-->Programm macht Murks, pro Block bleiben 2-3 Zellen zurück, die entweder eine leere FeldMenge haben oder eine FeldMenge mit 2 Zahlen haben -->Warum? Fall 3:Alle vorgegebenen Zahlen werden eingegeben, einmal löscht man eine Zahl und gibt noch einmal genau dieselbe ein-->Programm löst Sudoku Ich habe überlegt und überlegt, komme jedoch einfach nicht auf den Fehler Hier mal der Quelltext, vielleicht findet ihr den Fehler Button1 ist der Knopf den man drückt, um das Sudoku zu lösen, die Entfernungsprozedur steht in OnKeyUP
Delphi-Quellcode:
procedure TForm4.FormCreate(Sender: TObject);
var Spalte,Zeile:integer; begin For Zeile:=0 to 8 do For Spalte:=0 to 8 do begin StringGrid1.cells[Spalte,Zeile]:=' '; //normalerweise steht in jedem Feld '', so aber ' ' ; wichtig für Speicherung FeldMenge[Spalte,Zeile]:=[1,2,3,4,5,6,7,8,9]; //Zu Beginn kann in jedem Feld jeder Zahl zwischen 1 und 9 stehen end; end; procedure TForm4.StringGrid1KeyPress(Sender: TObject; var Key: Char); begin If (Key in ['1'..'9']) and (StringGrid1.Cells[StringGrid1.col,StringGrid1.row]=' ') //wenn die EIngabe eine Zahl ist und im angeklickten Feld nicht schon eine Zahl steht then If StrToInt(Key) in FeldMenge[StringGrid1.col,StringGrid1.row] //wenn die Eingabe regelkonform ist then begin StringGrid1.Cells[StringGrid1.col,StringGrid1.row]:=Key; //im angeklickten Feld die Zahl reinschreiben FeldMenge[StringGrid1.col,StringGrid1.row]:=[]; //da das Feld eine Zahl enthält, kann dort keine andere Zahl mehr eingesetzt werden RestMengeNeuZuOrdnen(strtoint(Key),StringGrid1.col,StringGrid1.row); //die eingegebene Zahl wird aus den FeldMengen der Zellen im gleichen Block sowie in der gleichen Spalte oder Zelle gelöscht end else begin //Fehlermeldung, dass Eingabe nicht regelkonform ist Form5.Top:=Mouse.CursorPos.y-85; Form5.Left:=Mouse.CursorPos.x-210; //damit die Fehlermeldung so auftaucht, dass die Maus bereits auf dem Fehlermeldung-wegklicken-Button Form5.Show; //Fehlermeldung anzeigen beep; //Fehlergeräusch machen end; end; procedure TForm4.StringGrid1Click(Sender: TObject); var RestMengeDerZelle:Zahlen; Spalte,Zeile,Zahl:integer; begin //ist eine Hilfsfunkion währen der Erstellzeit, damit wird die FeldMenge der angeklickten Zelle in einem zweiten StringGrid gezeigt RestMengeDerZelle:=FeldMenge[StringGrid1.col,StringGrid1.row]; For Spalte:=0 to 2 do FOr Zeile:=0 to 2 do begin Zahl:=Spalte+1+Zeile*3; If Zahl in RestMengeDerZelle then Stringgrid2.Cells[Spalte,Zeile]:=inttostr(Zahl) else Stringgrid2.Cells[Spalte,Zeile]:=' '; end; end; procedure TForm4.RestMengeNeuZuordnen(EingegebeneZahl,Spalte,Zeile:integer); var untersuchteZeile,untersuchteSpalte,x,y,xAdd,yAdd:integer; begin //Die Zahl aus allen FeldMengen der gleichen Spalte löschen For untersuchteZeile:=0 to 8 do FeldMenge[Spalte,untersuchteZeile]:=FeldMenge[Spalte,untersuchteZeile]-[EingegebeneZahl]; //Die Zahl aus allen FeldMengen der gleichen Zeile löschen For untersuchteSpalte:=0 to 8 do FeldMenge[untersuchteSpalte,Zeile]:=FeldMenge[untersuchteSpalte,Zeile]-[EingegebeneZahl]; //Die Zahl aus allen FeldMengen des gleichen Blocks löschen Block.x:=Spalte div 3; //dient der Bestimmung des Blocks, in dem die FeldMengen verändert werden sollen Block.y:=Zeile div 3; //x und y gehen von 0..2, der Block 0,0 ist links oben, der Block 2,2 rechts unten x:=Block.X*3; //dient der Bestimmung der Koordinaten der Zelle links oben in y:=Block.Y*3; //dem betreffenden Block For yAdd:=0 to 2 do For xAdd:=0 to 2 do begin FeldMenge[x+xAdd,y+yAdd]:=FeldMenge[x+xAdd,y+yAdd]-[EingegebeneZahl]; end; {entspricht FeldMenge[x,y]:=FeldMenge[x,y]-[EingegebeneZahl]; FeldMenge[x+1,y]:=FeldMenge[x+1,y]-[EingegebeneZahl]; FeldMenge[x+2,y]:=FeldMenge[x+2,y]-[EingegebeneZahl]; FeldMenge[x,y+1]:=FeldMenge[x,y+1]-[EingegebeneZahl]; FeldMenge[x+1,y+1]:=FeldMenge[x+1,y+1]-[EingegebeneZahl]; FeldMenge[x+2,y+1]:=FeldMenge[x+2,y+1]-[EingegebeneZahl]; FeldMenge[x,y+2]:=FeldMenge[x,y+2]-[EingegebeneZahl]; FeldMenge[x+1,y+2]:=FeldMenge[x+1,y+2]-[EingegebeneZahl]; FeldMenge[x+2,y+2]:=FeldMenge[x+2,y+2]-[EingegebeneZahl]; die obere Variante ist aber eleganter} end; procedure TForm4.Button1Click(Sender: TObject); begin //wenn der Knopf gedrückt wird, löse das Sudoku NakedSingles; HiddenSingles; RestRaten; end; procedure TForm4.NakedSingles; var Zahl,Spalte,Zeile:integer; anders:boolean; begin anders:=false; For Spalte:=0 to 8 do For Zeile:=0 to 8 do For Zahl:=1 to 9 do if FeldMenge[Spalte,Zeile]=[Zahl] //wenn in der FeldMenge einer Zelle nur eine Zahl steht, so muss diese Zahl darin stehen then begin StringGrid1.cells[Spalte,Zeile]:=inttostr(Zahl); //im betroffenen Feld die Zahl reinschreiben FeldMenge[Spalte,Zeile]:=[]; //da das Feld eine Zahl enthält, kann dort keine andere Zahl mehr eingesetzt werden RestMengeNeuZuOrdnen(Zahl,Spalte,Zeile); //die eingegebene Zahl wird aus den FeldMengen der Zellen im gleichen Block sowie in der gleichen Spalte oder Zelle gelöscht anders:=true; end; If anders then Button1CLick(Form4); //durch "anders" wird nach dem Durchlaufen der Schleifen die Löseprozedur noch einmal aufgerufen, da bei einmaligen Durchlauf von NakedSingles nur max. eine Zelle gelöst werden kann //wenn sich durch die Prozedur jedoch nichts ändert (-->anders bleibt false), dann muss die Löseprozedur nicht noch einmal aufgerufen werden; man kann in ihr einen Schritt weiter gehen (-->HiddenSingles) end; procedure TForm4.HiddenSingles; var Zahl,Spalte,Zeile,UntersuchteZeile,UntersuchteSpalte:integer; RestMenge:Zahlen; anders:boolean; begin anders:=false; //Einsatz von anders genauso wie in NakedSingles //Zeilenweise For Zeile:=0 to 8 do For Spalte:=0 to 8 do begin RestMenge:=FeldMenge[Spalte,Zeile]; For UntersuchteSpalte:=0 to 8 do If Spalte<>UntersuchteSpalte //damit die FeldMenge der Zelle der RestMenge nicht abgezogen wird, würde immer zu RestMenge=[] führen then RestMenge:=RestMenge-FeldMenge[UntersuchteSpalte,Zeile]; For Zahl:=1 to 9 do If RestMenge=[Zahl] then //Es wird untersucht, ob in einer Zeile oder Spalte eine bestimmte Zahl nur in genau einer Zelle vorkommt; denn wenn das zutrifft, so muss diese Zahl in dieser Zelle stehen //dazu wird von der FeldMenge einer Zelle die FeldMengen aller anderen Zellen der gleichen Spalte oder des gleichen Blocks abgezogen; wenn nur eine Zahl übrigbleibt, dann deswegen, weil sie nie abgezogen wurde //diese Zahl steht also in keiner anderen FeldMengen begin StringGrid1.cells[Spalte,Zeile]:=inttostr(Zahl); FeldMenge[Spalte,Zeile]:=[]; //da das Feld eine Zahl enthält, kann dort keine andere Zahl mehr eingesetzt werden RestMengeNeuZuOrdnen(Zahl,Spalte,Zeile); //die eingegebene Zahl wird aus den FeldMengen der Zellen im gleichen Block sowie in der gleichen Spalte oder Zelle gelöscht anders:=true; end; end; //Spaltenweise For Zeile:=0 to 8 do For Spalte:=0 to 8 do begin RestMenge:=FeldMenge[Spalte,Zeile]; For UntersuchteZeile:=0 to 8 do If Spalte<>UntersuchteZeile //damit die FeldMenge der Zelle der RestMenge nicht abgezogen wird, führt immer zu RestMenge=[] then RestMenge:=RestMenge-FeldMenge[Spalte,UntersuchteZeile]; For Zahl:=1 to 9 do If RestMenge=[Zahl] then begin StringGrid1.cells[Spalte,Zeile]:=inttostr(Zahl); FeldMenge[Spalte,Zeile]:=[]; RestMengeNeuZuOrdnen(Zahl,Spalte,Zeile); anders:=true end; end; If anders then Button1CLick(Form4); end; procedure TForm4.RestRaten; var Spalte,Zeile,Zahl:integer; ZellInhalt:string; begin //Baustelle end; procedure TForm4.StringGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); var Spalte,Zeile,Zahl,xAdd,yAdd,x,y:integer; begin If ((Key=vk_delete) or (Key=vk_Back)) //wenn Backspace oder Entfernen gedrückt wurde and (StringGrid1.Cells[StringGrid1.col,StringGrid1.row]<>' ') then begin Zahl:=strtoint(StringGrid1.Cells[StringGrid1.col,StringGrid1.row]); StringGrid1.Cells[StringGrid1.col,StringGrid1.row]:=' '; //dann lösche den Zellinhalt FeldMenge[StringGrid1.col,StringGrid1.row]:=[1,2,3,4,5,6,7,8,9]; //in dieser Zelle kann erstmal wieder jede Zahl stehen, die tatsächliche FeldMenge wird gleich bestimmt //der folgende Block bewirkt, dass die gelöschte Zahl zu den FeldMengen der Zellen der //gleichen Zelle, Spalte, Block hinzugefügt werden For Zeile:=0 to 8 do FeldMenge[StringGrid1.col,Zeile]:=FeldMenge[StringGrid1.col,Zeile]+[Zahl]; For Spalte:=0 to 8 do FeldMenge[Spalte,StringGrid1.row]:=FeldMenge[Spalte,StringGrid1.row]+[Zahl]; Block.x:=StringGrid1.col div 3; //dient der Bestimmung des Blocks, in dem die FeldMengen verändert werden sollen Block.y:=StringGrid1.row div 3; //x und y gehen von 0..2, der Block 0,0 ist links oben, der Block 2,2 rechts unten x:=Block.X*3; //dient der Bestimmung der Koordinaten der Zelle links oben in y:=Block.Y*3; //dem betreffenden Block For yAdd:=0 to 2 do For xAdd:=0 to 2 do FeldMenge[x+xAdd,y+yAdd]:=FeldMenge[x+xAdd,y+yAdd]+[Zahl]; //es ist jedoch auch möglich, dass eine Zahl nicht in einer Zelle stehen darf (=kein Element der FeldMenge) //weil es diese Zahl bereits in der selben Spalte und der selben Zeile steht //Würde man die Zahl aus der Zeile löschen, so würde in der FeldMenge der betroffenen //Zelle die Zahl stehen, obwohl die Zahl in der selben Spalte steht, was nicht regelkonform ist //daher wird so getan, als ob alle Zahlen neu eingegeben werden und dadurch die betreffenden FeldMengen reduziert werden For Zeile:=0 to 8 do For Spalte:=0 to 8 do If StringGrid1.Cells[Spalte,Zeile]<>' ' then begin Zahl:=strtoint(StringGrid1.Cells[Spalte,Zeile]); RestMengeNeuZuOrdnen(Zahl,Spalte,Zeile); end; end; end; |
Zitat |
Registriert seit: 7. Aug 2008 Ort: Brandenburg 1.464 Beiträge Delphi 12 Athens |
#2
Wenn man eine Zahl löscht, muss das Array FeldMenge komplett neu berechnet werden.
|
Zitat |
Registriert seit: 13. Feb 2010 33 Beiträge |
#3
Ehrlich gesagt war das auch mein erster Ansatz
Delphi-Quellcode:
Das Problem: es funktioniert genauso nicht -.-
procedure TForm4.StringGrid1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState); var Spalte,Zeile,Zahl,xAdd,yAdd,x,y:integer; Sudoku:string; begin If ((Key=vk_delete) or (Key=vk_Back)) //wenn Backspace oder Entfernen gedrückt wurde and (StringGrid1.Cells[StringGrid1.col,StringGrid1.row]<>' ') then begin StringGrid1.Cells[StringGrid1.col,StringGrid1.row]:=' '; //dann lösche den Zellinhalt For Zeile:=0 to 8 do For Spalte:=0 to 8 do FeldMenge[Spalte,Zeile]:=[1,2,3,4,5,6,7,8,9]; //FeldMengen neu füllen For Zeile:=0 to 8 do For Spalte:=0 to 8 do If StringGrid1.Cells[Spalte,Zeile]<>' ' then begin Zahl:=strtoint(StringGrid1.Cells[Spalte,Zeile]); RestMengeNeuZuOrdnen(Zahl,Spalte,Zeile); //FeldMengen reduzieren end; end; end; Aber ich habe imzwischen eine Lösung des Problems gefunden: Zum Speichern einer Sudoku-Datei wandle ich das Sudoku in einen String um und zum Laden wandle ich den String in das Sudoku um
Delphi-Quellcode:
Und das funktioniert seltsamerweise, obwohl der Unterschied eigentlich nur im Löschen und Neuschreiben aller Zahlen liegt
function TForm4.SudokuInListeSpeichern:String;
var Spalte,Zeile:integer; Datei:String; begin For Zeile:=0 to 8 do For Spalte:=0 to 8 do Datei:=Datei+StringGrid1.cells[Spalte,Zeile]; Result:=Datei; end; procedure TForm4.SudokuAusListeLaden(Datei:string); var Spalte,Zeile,i:integer; begin FormCreate(Form4); For i:=1 to 81 do //die gespeicherte Datei besteht aus 81 Zeichen begin Spalte:=(i-1) mod 9; Zeile:=(i-1) div 9; // i-1 da Zellen/Spalten von 0..8 StringGrid1.Cells[Spalte,Zeile]:=Datei[i]; If Datei[i] in ['1'..'9'] then begin FeldMenge[Spalte,Zeile]:=[]; RestMengeNeuZuordnen(strtoint(Datei[i]),Spalte,Zeile); end; end; end; Aber gestern Nacht kam mir ein wahrer Geistesblitz, als ich mit was völlig anderem beschäftigt war
Delphi-Quellcode:
Das ist wahrscheinlich nicht die schnellste Methode, aber es funktioniert schonmal
procedure TForm4.StringGrid1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState); var Spalte,Zeile,Zahl,xAdd,yAdd,x,y:integer; Sudoku:string; begin If ((Key=vk_delete) or (Key=vk_Back)) //wenn Backspace oder Entfernen gedrückt wurde and (StringGrid1.Cells[StringGrid1.col,StringGrid1.row]<>' ') then begin Sudoku:=SudokuInListeSpeichern; Sudoku[StringGrid1.Row*9+StringGrid1.Col+1]:=' '; SudokuAusListeLaden(Sudoku); end; Obwohl ich mich wirklich frage, warum die ersten 2 Ansätze fehlerhaft sind... |
Zitat |
Registriert seit: 7. Aug 2008 Ort: Brandenburg 1.464 Beiträge Delphi 12 Athens |
#4
Eine Ursache für dein Problem ist, das Oberfläche und Datenhaltung/verarbeitung nicht getrennt sind.
Wenn du im KeyUp auf den Inhalt der Zelle zugreifst, hat der sich noch lange nicht geändert. Das Grid zeigt zum Bearbeiten ein Editfeld an, dessen Inhalt erst nach OnSetEditValue in die Zelle übernommen wird. Deshalb wurde RestMengeNeuZuOrdnen immer noch der alte Wert übergeben. |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |