Autor Beitrag
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mi 17.05.06 23:16 
Dafür nimmst Du nun den Minimax / NegaMax Algorithmus. Hast Du schon eine Routine, die Dir eine Liste aller möglichen Züge eines Spielers generiert? Wenn das fertig ist, verwendest Du einfach meinen Pseudocode, oder passt mein TTT (Tic-Tac-Toe) an.

ausblenden volle Höhe 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:
Function FindeBestenZug (Spieler, Gegner : TPlayer;  Brett : TBoard; SpielTiefe, MaxTiefe : Integer; 
  Var BesterZug : TMove; Patt : Boolean) : Integer;
Var
  MovePossible : Boolean;
  M : TMoveList;
  MaxS, S, N, i : Integer;
  DummyZug : TMove;

Begin
  MovePossible := False;
  CreateAllMoves (Spieler, Brett, M, N);      // M ist die Liste der Züge, N die Anzahl der möglichen Züge.
  For i:=0 to N-1 do Begin
     MovePossible := True;
     Board.DoMove(M[i]);                      // Führe ihn aus
     If SpielTiefe = MaxTiefe Then            // Max. Vorschautiefe erreicht?
        S := Board.BewerteStellung (Spieler); // Je höher S, desto besser für den 'Spieler'
     Else                                     // Ansonsten liefert dieser Aufruf ja den besten Zug des Gegners
        S := -FindeBestenZug (Gegner, Spieler, Brett, SpielTiefe + 1, MaxTiefe, DummyZug, False); // wir wollen den Zug,
     If S > MaxS Then          // auf den der Gegner die schlechteste Anwort parat hat, daher das '-FindeBesten....'
        MaxS := S
        BesterZug := M
     End;
     Board.UndoMove (M[i]);    // Mache den Zug abschließend wieder rückgängig, denn wir probieren ja nur
  End

  if Not MovePossible Then // Spieler kann nicht ziehen
     If Patt Then          // der Vorherige auch nicht
        Result := Board.BewerteEndstellung (Spieler)      // Diese Funktion bewertet nicht die strategische 
     else                                                    // Stellung, sondern einfach, wer gewonnen hat
        Result := -FindeBestenZug (Gegner, Spieler, Brett, SpielTiefe + 1, MaxTiefe, DummyZug, True);
End;

Das Prinzip ist einfach: Führe einfach jeden möglichen Zug nacheinander aus und schaue nach, was die beste Antwort des Gegners wird. Der beste eigene Zug ist nun einfach der, der den aus Sicht des Gegners schlechtesten Gegenzug zulässt. Das Ganze wird nun rekursiv aufgerufen, bis die maximale Vorschautiefe (MaxLevel) erreicht wird. Hier wird die Stellung bewertet (wenn nicht schon vorher eine Gewinnstellung erreicht wurde). In der tiefsten Ebene wird also der Zug gewählt, der die besten Stellungsbewertung 'verursacht'.

Das Teil rufst Du einfach so auf:
ausblenden Delphi-Quelltext
1:
S := FindeBestenZug (plHuman, plComputer, MyBoard, 0, MaxLevel, M, False);					

S ist die Bewertung des Zuges 'M'. Und 'M' ist eben der beste Zug. Ganz einfach.

Ach ja: MaxLevel ist sozusagen die Spielstärke von deinem Programm. Ein hoher Wert bedeutet eben, das der Suchbaum, also die Kombination aller möglichen Züge und Gegenzüge sehr weit durchlaufen wird. Das führt zu einer sehr guten Spielweise, kann aber eben auch ewig dauern.

Wenn es z.B. bei Deinem Spiel im Mittel pro Zug 10 Möglichkeiten gibt, dann muss man bei MaxLevel = 1 schon 100 (10*10) Stellungen durchsuchen, bei MaxLevel = 2 sind das schon 1000 usw. Irgendwann werden es so viele Kombinationen, das man zu lange warten müsste. Da aber die meisten Zugmöglichkeiten sowieso Blödsinn sind, könnte man das auch ganz gewaltig optimieren. Das machen wir dann im nächsten Schritt. Wenn das Programm funktioniert.

_________________
Na denn, dann. Bis dann, denn.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 18.05.06 17:20 
user profile iconalzaimar hat folgendes geschrieben:
Hast Du schon eine Routine, die Dir eine Liste aller möglichen Züge eines Spielers generiert?

Ist vielleicht eine blöde Frage: alle generell möglichen Züge, also nur einmal, oder alle Züge, die aus der momentanen Stellung heraus möglich sind, also eine immer aktualisierte Liste? Wirklich eine Liste, zB. TStringList?
//Edit: hätte lesen sollen: TMoveList. :oops:

Was den Pseudocode betrifft, werde ich mich schon durchbeissen (und fragen wahrscheinlich auch)!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 18.05.06 17:42 
Es gibt keine blöden Fragen. Nur blöde Antworten.

Der Minimax spielt ja alle möglichen Zugkombinationen durch. Die Routine 'FindAllMoves' muss zu einer bestimmten Spielstellung, die in 'aBoard' gespeichert ist, für einen Spieler 'aPlayer' alle legalen Züge ermitteln.

Anschließend führt Minimax nacheinander den Zug aus, und prüft, wie der Gegner antworten könnte. Anschließend wird der Zug wieder rückgängig gemacht.

_________________
Na denn, dann. Bis dann, denn.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 18.05.06 17:44 
Bevor ich umsonst weitermache: meinst du so in etwa:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure CreateMoveList(Player: TPlayer);
var
  B, N: Byte;
begin
 Form1.ListBox1.Clear;

 {Spieler, gerade nach oben ziehen}
 for B := 0 to nPlayerCount-1 do
 begin
  for N := 0 to nPlayerCount-1 do
   if (TBoard[B, N] = Human) and (TBoard[B, N-1] = ''then  //Feld oberhalb einer Figur ist frei
    Form1.ListBox1.Items.Add(IntToStr(B)+' '+IntToStr(N-1));
 end;
end;

ListBox1 verwende ich nur im Moment, damit ich auch sehen kann, was der Code macht. Wird, wenn es funktioniert, natürlich gegen TStringList ausgetauscht! Aber: Was ist eine TMoveList, und warum gerade das?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 18.05.06 17:55 
So in etwa, aber Du kannst damit ja nur die 'Human' Züge erzeugen. Du brauchst aber auch (wenn aPlayer = plComputer) die Computerzüge. Da gehst du dann rückwärts. Und wenn du einen gegnerischen Bauern schlagen kannst, prüfst Du ja schräg nach vorne(bzw. hinten) rechts/links. Du kannst also pro Spielstein maximal 3 Züge erzeugen: Vorwärts ziehen, und schräg links und rechts schlagen.

Eine Listbox ist wieder zu langsam und ein GUI-Element.

Eine TMoveList ist einfach eine Datenstruktur, nämlich eine Liste von Zügen.

Ich würde das so machen (schon weiter oben erklärt)
Erstmal eine Position (auf dem Brett) definieren:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
Type
  TPosition = Record
    pRow,
    pCol : Integer;
  End;

Dann einen Zug. Der fängt irgendwo an und hört irgendwo auf. Vielleicht schlägt er den gegnerischen Stein ja auch.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
Type
  TMove = Record
    mFrom,
    mTo : TPosition;
    mCapture : Boolean; // True: auf mTo wird der Gegner weggefegt!
  End;

Und eine TMoveList ist dann einfach ein
ausblenden Delphi-Quelltext
1:
2:
  
TMoveList = Array [0..ccMaxMoves] Of TMove;


ccMaxMoves ist eine Konstante, die die maximal möglichen Züge beschreibt. Wenn man max. 16 Steine auf dem Brett hat, und jeder Stein kann maximal 3 Züge ausführen, wird man nie mehr als 48 Züge erzeugen können.

_________________
Na denn, dann. Bis dann, denn.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 18.05.06 18:36 
user profile iconalzaimar hat folgendes geschrieben:
So in etwa, aber Du kannst damit ja nur die 'Human' Züge erzeugen. Du brauchst aber auch (wenn aPlayer = plComputer) die Computerzüge. Da gehst du dann rückwärts. Und wenn du einen gegnerischen Bauern schlagen kannst, prüfst Du ja schräg nach vorne(bzw. hinten) rechts/links. Du kannst also pro Spielstein maximal 3 Züge erzeugen: Vorwärts ziehen, und schräg links und rechts schlagen.

Ich habe ja auch vor, beide Spieler mit allen ihnen möglichen Zügen zu berücksichtigen!

user profile iconalzaimar hat folgendes geschrieben:

Eine Listbox ist wieder zu langsam und ein GUI-Element.

Die ListBox wird später gegen TStringList ausgetauscht.

user profile iconalzaimar hat folgendes geschrieben:

Eine TMoveList ist einfach eine Datenstruktur, nämlich eine Liste von Zügen.

Vielleicht bin ich zu dämlich, aber es wird immer abstrakter! Ich bewege "Figuren" in einem Array mit in einem Record berechneten Zügen... Ich dachte mir das so: Erstelle eine Liste aller möglichen Züge und gehe diese von 0 bis List.Count-1 durch, stelle das Array TBoard dabei immer auf die Stellung zurück, die beim Aufruf der Prozedur, die die Liste abarbeitet, aktuell war, mache den jeweiligen Zug und merke dir die Werte der Züge. Dann ermittle den besten Wert, mache schliesslich den Zug, der zu diesem Wert führte (wie, weiss ich noch nicht) und verlasse die Schleife. Und je besser dabei die Bewertungsfunktion ist, desto besser wird das Programm spielen. Soweit ist mir das alles ja mittlerweile dank deiner Hilfe klar.

Ich sage dir ehrlich, ich steige da nicht durch mit TPosition = Record und TMove = Record. Ich wil ja keine sichtbaren Komponenten verwenden (nur zum Testen), also geht das nicht auch mit einer einfachen TStringList? Ein paar Millisekunden Zeitersparnis sind mir also wirklich egal, zumal ich sowieso ein Memo einbauen möchte, das die Berechnungsschritte anzeigt!

Wenn du aber auf deine Version bestehst - das wird sicher mindestens Tage dauern, bis ich da etwas hinbekomme! Aber es wäre schade, wenn das Projekt jetzt stirbt, nur weil ich da etwas nicht recht kapiere. :(

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 18.05.06 18:42 
Du kannst es doch so machen, wie Du willst... Ich hab doch nur geschrieben, wie ich das machen würde.

Das mit dem 'Zurückstellen' des spielfeldes geht einfacher, indem Du zwei routinen schreibst: DoMove und UndoMove. Die eine führt den Zug aus, die Andere nimmt ihn wieder zurück. Mit meinen Datenstrukturen geht das recht einfach:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
Procedure DoMove (aBoard : TBoard; aPlayer : TPlayer; aMove : TMove);
Begin
  With aMove do Begin
    aBoard[mFrom.pRow, mFrom.pCol] := plEmpty; // von Start-pos wegnehmen
    aBoard[mTo.pRow, ,mTo.pCol] := aPlayer;   // und zur Ziel-pos bewegen
  End;                                 // was vorher dort war ist nun weg
End;

Procedure UndoMove  (aBoard : TBoard; aPlayer, aOpponent : TPlayer; aMove : TMove);
Begin
  With aMove do Begin
    aBoard[mFrom.pRow, mFrom.pCol] := aPlayer;  // Spieler wieder zurück
    If mCapture Then                   // Wenn der Zug ein Schlagzug war
      aBoard[mTo.pRow, ,mTo.pCol] := aOpponent  // Geschlagenen Stein
    Else
      aBoard[mTo.pRow, ,mTo.pCol] := plEmtpy;  // Sonst leeres Feld
  End;
End;

_________________
Na denn, dann. Bis dann, denn.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 18.05.06 19:28 
user profile iconalzaimar hat folgendes geschrieben:
Du kannst es doch so machen, wie Du willst... Ich hab doch nur geschrieben, wie ich das machen würde.[/delphi]

Ok, die Zugliste ist fertig und funktioniert korrekt. Mein Programm kann:
1. Keine eigenen Züge machen. Alle Züge, auch die des Programms, kann im Moment nur ich machen
2. Alle Züge den Bauern-Zugregeln beim Schach entsprechend in einem Array ausführen
3. Das Array auf das StringGrid anwenden
4. Alle Züge bewerten
5. Die Bewertung erfolgt im Moment noch ohne Sinn: Caption := IntTostr(Bewertung(plComputer)); (oder plHuman)
6. Eine Liste der in der aktuellen Stellung möglichen Züge erstellen, zB. CreateMoveList(plComputer);
Dies ist eine einfache Liste mit je 2 Werten, wobei der 1. Col, der 2. Row des Arrays beschreibt.

Das Programm besteht also nun aus einigen Teilen, die aber noch nicht zusammenarbeiten.

Ich komme mit "primitiven" Mitteln wie StringList einfach besser zurecht; das verstehe ich auf Anhieb, die einfache Struktur mit den zwei Werten für Col und Row habe ich geschrieben und kenne sie daher. Aber wie ich sie nun anwenden soll, wie ich die Teile des Programms zusammenfüge, wie eine Computer-Zug-Prozedur aussieht und wie man das Ganze optimiert - keine Ahnung!

Also - wenn du mir weiter helfen willst, nur zu! :D

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 18.05.06 20:22 
user profile iconalzaimar hat folgendes geschrieben:

Das Prinzip ist einfach: Führe einfach jeden möglichen Zug nacheinander aus und schaue nach, was die beste Antwort des Gegners wird. Der beste eigene Zug ist nun einfach der, der den aus Sicht des Gegners schlechtesten Gegenzug zulässt. Das Ganze wird nun rekursiv aufgerufen, bis die maximale Vorschautiefe (MaxLevel) erreicht wird. Hier wird die Stellung bewertet (wenn nicht schon vorher eine Gewinnstellung erreicht wurde). In der tiefsten Ebene wird also der Zug gewählt, der die besten Stellungsbewertung 'verursacht'.

Ich komme nicht klar. Alles, was ich bis jetzt habe, ist die Bewertungsfunktion und das Ausführen des besten Zuges, der für den Computer ermittelt wurde: Das Programm erstellt eine Liste aller ihm möglichen Züge, ermittelt den besten und führt ihn aus. Das ist alles. Ich kriege weder die Rekursion hin noch komme ich mit deinem Pseudocode klar.

Ich habe alles bis auf eine Routine, die sinnvolle Züge berechnet. Das "Herz" des Programs also fehlt noch. Und ich muss zugeben, ich kann es nicht.

Ich habe, um mich optisch orientieren zu können, dzt. alle Zugkoordinaten in StringList's. Das erste "Wort" ist die Bewertung, ggf. mit Nullen voran, um sortieren zu können, dann folgen die Zugkoordinaten: Quell-Col Quell-Row Ziel-Col Ziel-Row. In der sortierten Liste ist somit das letzte Item der beste Zug - hat die höchste Bewertung. Aber das ist nicht ganz dasselbe, was gemeint war.

@alzaimar: Nicht, dass ich will, dass du mir den Code schreibst, aber ich weiss nicht, wie ich weiter machen soll... :(

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!


Zuletzt bearbeitet von galagher am Sa 20.05.06 15:28, insgesamt 1-mal bearbeitet
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 19.05.06 21:56 
Ich habe eine Prozedur FindeBestenZug, die auf Basis der Bewertung arbeitet, aber ich kann sie nicht rekursiv aufrufen - das nützt nichts, da sie immer wieder dem tatsächlichen Spielstand angeglichen werden muss, schliesslich ist dieser ja die Ausgangslage. Ohne diese Angleichnung werden mehrere Züge auf einmal ausgeführt.

Das Prinzip: Ich erstelle eine Liste aller möglichen Züge, führe diese nacheinander im Array TBoard aus, bewerte sie und sortiere sie in einer Liste. Der Zug mit der höchsten Bewertung wird dann tatsächlich ausgeführt; wenn es mehrere gleichwertige Züge gibt, entscheidet Random. Wie gesagt, nicht rekursiv, nur aus der momentanen Situation heraus und im Moment noch nur für den Computer.

Ich weiss nicht, wie ich das besser und vor allem wie ich es rekursiv hinbekommen soll.

Das Programm schlägt kaum und spielt entsetzlich unsinnig, aber es spielt jetzt immerhin!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Sa 20.05.06 16:46 
Aus irgendeinem Grund wird mein letzter Beitrag, den ich heute (20.5.) geschrieben habe, als am 18.5. geschrieben gereiht. :nixweiss: Also wiederhole ich ihn hier mal einfach (und hoffe, dass es jetzt klappt).

user profile iconalzaimar hat folgendes geschrieben:

Das Prinzip ist einfach: Führe einfach jeden möglichen Zug nacheinander aus und schaue nach, was die beste Antwort des Gegners wird. Der beste eigene Zug ist nun einfach der, der den aus Sicht des Gegners schlechtesten Gegenzug zulässt. Das Ganze wird nun rekursiv aufgerufen, bis die maximale Vorschautiefe (MaxLevel) erreicht wird. Hier wird die Stellung bewertet (wenn nicht schon vorher eine Gewinnstellung erreicht wurde). In der tiefsten Ebene wird also der Zug gewählt, der die besten Stellungsbewertung 'verursacht'.

Ich komme nicht klar. Alles, was ich bis jetzt habe, ist die Bewertungsfunktion und das Ausführen des besten Zuges, der für den Computer ermittelt wurde: Das Programm erstellt eine Liste aller ihm möglichen Züge, ermittelt den besten und führt ihn aus. Das ist alles. Ich kriege weder die Rekursion hin noch komme ich mit deinem Pseudocode klar.

Ich habe alles bis auf eine Routine, die sinnvolle Züge berechnet. Das "Herz" des Programs also fehlt noch. Und ich muss zugeben, ich kann es nicht.

Ich habe, um mich optisch orientieren zu können, dzt. alle Zugkoordinaten in StringList's. Das erste "Wort" ist die Bewertung, ggf. mit Nullen voran, um sortieren zu können, dann folgen die Zugkoordinaten: Quell-Col Quell-Row Ziel-Col Ziel-Row. In der sortierten Liste ist somit das letzte Item der beste Zug - hat die höchste Bewertung. Aber das ist nicht ganz dasselbe, was gemeint war.

@alzaimar: Nicht, dass ich will, dass du mir den Code schreibst, aber ich weiss nicht, wie ich weiter machen soll... :(

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 25.05.06 20:44 
user profile iconalzaimar hat folgendes geschrieben:
Das Prinzip ist einfach: Führe einfach jeden möglichen Zug nacheinander aus und schaue nach, was die beste Antwort des Gegners wird.

Das klappt jetzt: Das Programm prüft bei jedem ihm möglichen Zug, was der beste Gegenzug des Spielers ist. Aber das ist es auch schon. Ich schaffe es nicht, den Computer einen Zug machen zu lassen, den er auf die selbe Weise berechnet hat. Und rekursiv läuft das Ganze auch nicht.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Sa 27.05.06 00:53 
Hier mal eine Rohversion, wie es klappen könnte.

Die GUI ist grauenhaft, die Bewertungsfunktion ziemlich simpel, aber es spielt ganz nett.

Vielleicht hat ja jemand Lust,das aufzupeppen.

Objektorientiert könnte das auch mal werden.

Na ja, spielt aber.


Spieler = 'X'. Zum ziehen auf einen Stein klicken und dann auf die Zielposition.
Einloggen, um Attachments anzusehen!
_________________
Na denn, dann. Bis dann, denn.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1652
Erhaltene Danke: 243

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Sa 27.05.06 09:07 
Hallo,
gibt es soetwas wie eine Pattsituation?
Ich habe es geschafft, keinen Zug mehr machen zu koennen, bevor ein Bauer die gegnerische Grundlinie erreicht hat.
Wer gewinnt oder verliert dann?

Gruss Horst
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Sa 27.05.06 09:16 
Äh... Das zu erkennen, hab ich gar nicht eingebaut. Der Minimax bricht zwar ab, wenn Spieler und Computer direkt hintereinander nicht ziehen können, aber den Rest nicht. Gewonnen hat dann entweder einfach der mit den meisten Steinen, oder eben Keiner (ein Unentschieden).

Kann ich ja noch einbauen...

_________________
Na denn, dann. Bis dann, denn.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: So 28.05.06 10:32 
user profile iconalzaimar hat folgendes geschrieben:
Vielleicht hat ja jemand Lust,das aufzupeppen.

Hab's mir schon angesehen, ist super! Zum Thema aufpeppen: Habe erstmal Spieler und Computer umgedreht, der Spieler spielt jetzt von unten nach oben. Für die ersten, sagen wir, 4 Züge möchte ich eine Random-Funktion einbauen. Weiters möchte ich, dass das Programm weiterspielt, bis keine Figurenbewegungen mehr möglich sind und dann prüft, wer mehr Figuren auf der gegnerischen Grundlinie hat.

Dennoch: das "Herz", die KI, ist von dir geschrieben, und wenn ich das Programm so hinbekomme, wie ich das möchte, werde ich es in einer About-Box und im Quelltext auch vermerken. Dein Ansatz ist völlig anders als meiner es war, und ich muss erstmal versuchen, die Bewertung zu verstehen. Du sagst, sie ist grauenhaft, naja, mal sehen, was man da noch verbessern kann, vielleicht schaffe ich das ja!

Ich habe versucht, während des Berechnens des besten Zuges die jeweils ermittelten Züge in einem zweiten Memo auszugeben, sodass der Benutzer sieht, was das Programm macht. Das geht zwar, aber das Spiel wird um vieles langsamer, ab Levelstufe 6 dauert es einfach zu lange. Wie machen das Schachprogramme bei der Daueranalyse?

Du hast es so programmiert:
ausblenden Delphi-Quelltext
1:
Log(Format('L=%d, S=%d', [tbLevel.Position, l]));					

Ich möchte mehr Informationen anzeigen:
ausblenden Delphi-Quelltext
1:
Log(Format('Rechentiefe=%d, Bester Zug=%d', [tbLevel.Position, l]));					

Stimmen die bezeichnungen "Rechentiefe" und "Bester Zug"?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: So 28.05.06 11:16 
Hi

'l' ist hier die Bewertung des besten Zuges, und tbLevel.Position die eingestellte Rechentiefe.

Wenn Du ein wenig 'Action' in das Spiel bringen willst, dann solltest Du nur die ersten Level anzeigen. Übrigens kann ich das Spiel bei Level 4 schon nicht mehr besiegen, aber vielleicht bin ich auch einfach nur zu blöd. Level 6 dauert mir einfach zu lang.

Ich habe auch ein wenig an der GUI weitergebastelt und stelle das hier mal rein. Derzeit wird ein 'Patt' als unentschieden gewertet. Ich markiere die Stelle im Code, an der ich das einstelle und zeige, wie alternativ die Anzahl der Steine als Kriterium hinhalten kann (suche mal nach 'FinalScore').

Das Programm bemerkt mittlerweile, wer gewonnen hat und das man nicht ziehen kann. Ein Patt sollte mittlerweile erkannt werden.

Da ich das Programm hingerotzt habe, sind die Erweiterungen (Computer spielt gegen sich selbst, Spieloptimierung, Lernen etc.) nur noch schwer umzusetzen. Also, es geht schon noch, aber man will ja auch Vorbild sein :dunce: ...

Ich versuche bei Gelegenheit, die Engine als OOP zu implementieren.

[edit]Bitmaps gepimpt[/edit]
Einloggen, um Attachments anzusehen!
_________________
Na denn, dann. Bis dann, denn.


Zuletzt bearbeitet von alzaimar am So 28.05.06 11:24, insgesamt 1-mal bearbeitet
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: So 28.05.06 11:22 
user profile iconalzaimar hat folgendes geschrieben:
Übrigens kann ich das Spiel bei Level 4 schon nicht mehr besiegen, aber vielleicht bin ich auch einfach nur zu blöd. Level 6 dauert mir einfach zu lang.

Ich habe bei Level 4 auch noch nicht gewonnen, und Level 6 dauert wirklich lang.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: So 28.05.06 11:25 
user profile iconalzaimar hat folgendes geschrieben:
Ich habe auch ein wenig an der GUI weitergebastelt

Toll! Sieht sehr gut aus!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: So 28.05.06 11:50 
Ich schaffe es nicht, das Programm dahingehend zu ändern, dass es spielt, bis keine Figuren mehr bewegt werden können. Ich habe das zunächst einmal auskommentiert; dann findet aber offenbar keine "FindeBestenZug"-Berechnung mehr statt, das Programm spielt dann sehr schnelle Züge:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
    if l >= sWinScore then // Der Zug führt zum Gewinn (kann aber später sein)
      if GameOver then begin
        ShowMessage(szIWin);
        StartGame;
        Exit;
      end;

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!