Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - 8-Damen-Problem


klabri - Mo 05.01.09 19:34
Titel: 8-Damen-Problem
Hallo, ich weiss....
warum funktioniert das so nicht ?
Was funktioniert nicht... das Zurücknehmen der Dame
in Zeile x-1 ,wenn 'Sackgasse=True'....




Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
procedure Suche(x,y:integer);
 begin
if (Sackgasse=True) and (Feld[x][y]=True)//Markierung d.Dame
then
begin
dauf[x+y]:=false;    //Dame zurück,Markierung weg
dab[y-x]:=false;     //dauf,dab:Diagonalen 

Feld[x][y]:=False;
end;
erfolg:=false;  //noch keine Dame gesetzt
if (erfolg=false) and (y<8then
begin
y:=y+1;
d[x]:=y;

erfolg:=True ; //Dame gesetzt
if (dauf[x+y]=True)// Dame bedroht ?
or (dab[y-x]=True)
then

erfolg:=false;

if (erfolg=false) and(y<8)Then //neue Position suchen
begin
Suche (x,y);
end;
if (erfolg=False) and(y=8AND (x>1then //Sackgasse,
begin                                     //keine Lösung
Sackgasse:=True;                          //in einer Zeile

 Damen(x-1,d[x-1]);    // hier sollte das "Backtracking
                       // kommen ...

end;                  //d[x-1] Pos. der Dame in Zeile x-1
end;
{******************************************};
If erfolg=true then
begin
dauf[x+y]:=True;      //Dame gesetzt
dab[y-x]:=True;


Feld[x][y]:=True;  //Feld der Dame markiert
ListBox1.Items.Add('Dame:'+IntToStr(x)+'**'+IntToStr(d[x]));
  //Ausgabe
 y:=0;
end;
if x<8 then
Suche  (x+1,y);  //neur Aufruf
end;



Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Mo 05.01.2009 um 20:09


jaenicke - Mo 05.01.09 20:06

Durch die globalen Variablen und die fehlenden Einrückungen ist der Code so gut wie unlesbar. :roll:

Was mir auffällt:

Delphi-Quelltext
1:
2:
3:
if (Sackgasse=True) and (Feld[x][y]=True)//Markierung d.Dame
then
begin
Das ist falsch. Es muss heißen:

Delphi-Quelltext
1:
2:
if Sackgasse and Feld[x][y] then //Markierung d.Dame
begin
Erklärung:
http://www.delphi-treff.de/tutorials/objectpascal/programmierung-mit-boolean-werten/page/4/

Und dann noch etwas, was vielleicht der Fehler ist:
Du setzt Sackgasse auf True, aber nie wieder auf False.

Und was ist hier Damen? Mit Suche rufst du die eigene Prozedur rekursiv selbst auf. Aber wo ist Damen definiert?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure Suche(x,y:integer);
...
if (erfolg=false) and(y<8)Then //neue Position suchen
begin
Suche (x,y);
end;
if (erfolg=False) and(y=8AND (x>1then //Sackgasse,
begin                                     //keine Lösung
Sackgasse:=True;                          //in einer Zeile

 Damen(x-1,d[x-1]);    // hier sollte das "Backtracking
                       // kommen ...


Jakob_Ullmann - Mo 05.01.09 21:21

Also ich hab irgendwie gar nichts verstanden. Bitte formuliere deine Frage noch mal. :roll:

Was weißt du? Was soll das Programm machen? Was ist Zeile x-1?


klabri - Di 06.01.09 00:54

Hallo, das war sehr unverständlich gefragt;
Danke für's Ansehen,da steckten noch eine Menge Fehler
drin...
also,dass Programm findet Lösungen für das
8-Dame-Problem.
Inzwischen hab ich alles noch mal neu gemacht und
,welche Freude,scheinbar funktioniert das Backtracking,
darum ging's mir eigentlich.
Also so funktioniert's; zumindest lässt sich das Back-
tracking gut verfolgen;
Die Ausgabe erfolgt in einer Listbox;


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
unit Unitrec59;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
        procedure Suche(x:integer);
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
 erfolg:boolean;
 d:array[1..8]of integer;
 dauf:array[2..16]of boolean;
 dab:array[-7..7]of boolean;
 vertikal:array[1..8]of boolean;
  y:integer;
 sackgasse:boolean;
 implementation

{$R *.dfm}

procedure TForm1.Suche(x:integer);

begin
if sackgasse=True then
begin
dauf[x+d[x]]:=false; //Dame zurücknehmen 
dab[d[x]-x]:=false;
vertikal[d[x]]:=false;
d[x]:=0//zurückgenomme Dame erscheint i.d. Listbox als Null
         // sonst "verwirrt" die Ausgabe.

end;
erfolg:=false; // noch keine Dame gesetzt 
if (erfolg=false)and (y<8then
begin
y:=y+1;
//d[x]:=y; // hier lag ein Fehler ...
erfolg:=True;
if dauf[x+y]=true then Erfolg:=false; //wenn Dame bedroht
if dab[y-x]=true then Erfolg:=false;  // 
if vertikal[y]=True then Erfolg:=false;
if erfolg=false then  //Suche weiter 
begin
//ListBox1.Items.Add(IntToStr(x)+'****'+ IntToStr(d[x]));
Suche(x);
end;
end;
{********************************************}
if erfolg=True  then  //Dame auf einem nicht bedrohten Feld 
d[x]:=y;
dauf[x+y]:=True;    // Diagonalen,Vertikale markieren 
dab[y-x] :=true;
vertikal[y]:=True;


ListBox1.Items.Add(IntToStr(x)+'*'+IntToStr(d[x]));//Ausgabe
y:=0;
end;
if (x<8and (erfolg=True) Then
begin

Suche(x+1); //Neuer Aufruf 
end;
{:::::::::::::::::::::::::::::::::}
if (y=8)and (erfolg=false)  then //hier beginnt das                              //Backtracking
begin
Sackgasse:=True;  // keine Lösung mehr  
//ListBox1.Items.Add('Sackgasse');
y:=d[x-1];
 Suche(x-1);
 end;
 end;


procedure TForm1.Button1Click(Sender: TObject);
begin
Suche(1);
end;

end.


F34r0fTh3D4rk - Di 06.01.09 10:29

user profile iconjaenickes Beitrag hast du aber nicht zur Kenntnis genommen, oder? Auch wenn es in deinem Fall höchstwahrscheinlich nicht zu Problemen führt, sind Konstrukte wie (erfolg=True) auch meiner Ansicht nach unsinnig.

Delphi-Quelltext
1:
if (erfolg = true) then                    

wird zu:

Delphi-Quelltext
1:
if (erfolg) then //Klammern sind (zumindest in Delphi) Geschmackssache                    


Delphi-Quelltext
1:
if (erfolg = false) then                    

wird zu

Delphi-Quelltext
1:
if (not erfolg) then                    

Man kann nämlich nicht immer davon ausgehen, dass trueauch wirklich trueist. Klingt komisch, ist aber so. Das liegt daran, dass man keine einzelnen Bits speichern kann und ein booleandeshalb immer als ein Byte abgelegt wird. Wobei man sich selbst da nicht sicher sein kann. Es gibt also 256 Zustände (statt 2) die rein theoretisch von boolean angenommen werden können. Ob das jetzt immer die Werte 1 (true) oder 0 (false) sind, kann man nicht mit Bestimmtheit sagen.
mfg


WInfo - Di 06.01.09 10:48

user profile iconklabri hat folgendes geschrieben Zum zitierten Posting springen:
Hallo, das war sehr unverständlich gefragt;


Moin Moin klabri,

wenn dein Codebeispiel verständlich formatiert und dokumentiert wäre, werden sich sicher auch andere den Code mal ansehen. Aktuell finde ich das nur für Grauenhaft und ist mir keines Blickes wert.


klabri - Di 06.01.09 12:34

Hallo,
erstmal danke an alle,die hier geantwortet haben.
Ich hab jänickes beitrag gelesen und war auch auf dem
Delphi-Link;
Ich schreib das noch mal richtig und erklär das auch aus-
führlich und stell's hier dann noch mal als PDF-Datei rein.


klabri - Di 06.01.09 13:37

Hallo

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure Suche(x:integer);
begin 
....
.....
erfolg:=false; // noch keine Dame gesetzt 
if (erfolg=false)and (y<8then
begin
y:=y+1;

erfolg:=True;


ich bemüh mich mal, dieses erfolg:=false am Anfang
der Procedur Suche(x) zu erklären:
-Die Procedure wird mit Suche(1) aufgerufen
-auf einem Schachbrett wäre wir jetzt in der ersten Zeile
-y:=y+1, die erste Spalte in der Zeile oder das erste Feld
-erfolg:=True :wir haben ein nicht besetztes Feld gefunden
-in der Procedure geht es mit erfolg:=True weiter
-die Diagonalen und Vertikal werden als besetzt
-dauf[x+y]:=True etc. markiert
-die Procedure wird wieder aufgerufen :Suche(2)
-wenn dieses erfolg=false fehlt
-wird alles ,was in "If erfolg=false...."steht
übersprungen
-das Programm prüft dann nicht,ob die Dame in der zweiten
Zeile bedroht wird und sucht auch in dieser Zeile keine
neue Lösung
Ich weiss,es ist nicht verständlich so,aber dieses
erfolg:=false am Anfang der Procedure hat so seinen Sinn.


Dunkel - Di 06.01.09 18:10

user profile iconklabri hat folgendes geschrieben Zum zitierten Posting springen:

Ich weiss,es ist nicht verständlich so,aber dieses
erfolg:=false am Anfang der Procedure hat so seinen Sinn.

Darum geht es ja auch garnicht.

Es geht um Deine if-Konstrukte, in denen Du explizit auf True oder False prüfst. Dass das zu Problemen führen kann (nicht muss!), steht recht gut erklärt in dem Link, welchen Du Dir offensichtlich nicht genau genug durchgelesen hast.


klabri - Di 06.01.09 20:39

Hallo,
stimmt,ich hab mal so schnell drüber gelesen; aber es
leuchtet mir ein und ich werd's mal ändern;
Danke noch einmal für den Hinweis

-- Moderiert von user profile iconKha: Beiträge zusammengefügt - ab hier 10.03.10 --

Hallo,
ich beschäftige mich gerade mal wieder mit diesem 8-Damen-Problem.
Mein Programm findet mit 8 Damen, mit Back-Tracking 1 Lösung,
dabei steht die erste Dame in der ersten Zeile,in der ersten Spalte.
Während der Lösungssuche läuft das Backtracking von der achten Zeile bis zur
zweiten Zeile,dann findet es eine Lösung.
Die erste Dame müsste sich dann auf das nächste Feld bewegen,aber wie stelle ich das an ?

-- Moderiert von user profile iconKha: Beiträge zusammengefügt --

Hallo,
das Programm läuft nach folgendem Schema ab:

-Suche Position ,in der Dame(x) nicht geschlagen wird
-wenn Position gefunden,dann setze Dame(x)

-wenn in Zeile x keine Lösung ,
,mache in Zeile(x-1)weiter
-Suche Position....setze Dame.....

usw.

es gibt eine Funktion Setze_Dame(x:integer):integer;
,die,wenn eine Position gefunden ist mit Setze_Dame(x+1) wieder aufgerufen wird.
In dem Programm lässt sich das Backtracking gut verfolgen,aber
es findet eben nur eine Lösung..
Setze_Dame(x) wird so aufgerufen

if x<8 and gefunden:=True then
Setze_dame(x+1);


Kha - Do 11.03.10 01:23

Da war ich mit dem Zusammenfassen wohl etwas übereifrig, also zum Pushen gleich eine Antwort hinterher ;) .

Im Prinzip darfst du nach dem Fund einer gültigen Position nicht aufhören, sondern musst für jede gültige Position in der Reihe die Funktion rekursiv aufrufen. Wenn dein Algorithmus die Menge aller Lösungen zurückgeben soll, bräuchtest du noch eine verschachtelte Liste wie im Wikipedia-Beispiel [http://de.wikipedia.org/wiki/Damenproblem#Rekursives_Backtracking], für die bloße Anzahl oder weiterhin die direkte Ausgabe in einer Listbox solltest du nicht viel ändern müssen.


klabri - Do 11.03.10 11:09

Hallo,
ich guck mir das Wikedepia mal ;
irgendwo fehlt ein rekursiver Aufruf.
Die Funktion Setze_dame(x+1) ruft sich auf bis
diese Abbruchbedingung
x<8 and gefunden =True erfüllt ist, beim Setzen der achten Dame.
dame(1): Pos 1
dame(2): Pos 5
dame(3): Pos 8
..
dame(8): Pos 4

Ende, weil Lösung gefunden...

weitergehn müsste die Suche mit dame(2),indem Pos 6,7,8 geprüft wird..
Hier fehlt mir also ein entsprechender Aufruf.
Wenn diese Positionen geprüft sind und die Lösungen gefunden sind,müsste die
1.Dame auf Pos 2 vorrücken usw.... ,dieser neue Aufruf fehlt mir aucn noch...
Aber ich bin schon mal zufrieden,dass das Backtracking so funktioniert
Ich häng die Unit mal als Datei dran,vielleicht hat jemand eine gute Idee,was
da noch fehlt..


klabri - So 14.03.10 17:58

So, inzwischen ist das Problem gelost;
nachdem das Programm eine Lösung gefunden hat, also die achte Dame in gesetzt ist
ruft es eine zweite Funktion auf, die weiter Positionen absucht
-zuerst in der Zeile, in der die letzte Dame gesetzt worden ist
-dann kommt das Backtracking in Zeile -1 ,wenn keine Lösung gefunden usw,
alle Fragen sind beantwortet,dass Rad wurde zum x-ten Mal erfunden.
Jetzt verpacke ich das ganze noch ein wenig.
Vielen Dank für das Beantworten meiner Fragen.Ich habe als verstanden,
wie "Backtracking" funktioniert.