Autor |
Beitrag |
alzaimar
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: 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.
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); For i:=0 to N-1 do Begin MovePossible := True; Board.DoMove(M[i]); If SpielTiefe = MaxTiefe Then S := Board.BewerteStellung (Spieler); Else S := -FindeBestenZug (Gegner, Spieler, Brett, SpielTiefe + 1, MaxTiefe, DummyZug, False); If S > MaxS Then MaxS := S BesterZug := M End; Board.UndoMove (M[i]); End
if Not MovePossible Then If Patt Then Result := Board.BewerteEndstellung (Spieler) else 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:
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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 18.05.06 17:20
alzaimar 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.
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
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: 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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 18.05.06 17:44
Bevor ich umsonst weitermache: meinst du so in etwa:
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;
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 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
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: 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:
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.
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| Type TMove = Record mFrom, mTo : TPosition; mCapture : Boolean; End; |
Und eine TMoveList ist dann einfach ein
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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 18.05.06 18:36
alzaimar 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!
alzaimar hat folgendes geschrieben: |
Eine Listbox ist wieder zu langsam und ein GUI-Element.
|
Die ListBox wird später gegen TStringList ausgetauscht.
alzaimar 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
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: 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:
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; aBoard[mTo.pRow, ,mTo.pCol] := aPlayer; End; End;
Procedure UndoMove (aBoard : TBoard; aPlayer, aOpponent : TPlayer; aMove : TMove); Begin With aMove do Begin aBoard[mFrom.pRow, mFrom.pCol] := aPlayer; If mCapture Then aBoard[mTo.pRow, ,mTo.pCol] := aOpponent Else aBoard[mTo.pRow, ,mTo.pCol] := plEmtpy; End; End; |
_________________ Na denn, dann. Bis dann, denn.
|
|
galagher
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 18.05.06 19:28
alzaimar 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!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 18.05.06 20:22
alzaimar 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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: 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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: 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. Also wiederhole ich ihn hier mal einfach (und hoffe, dass es jetzt klappt).
alzaimar 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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 25.05.06 20:44
alzaimar 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
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: 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
Beiträge: 1652
Erhaltene Danke: 243
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: 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
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: 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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 28.05.06 10:32
alzaimar 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:
Delphi-Quelltext 1:
| Log(Format('L=%d, S=%d', [tbLevel.Position, l])); |
Ich möchte mehr Informationen anzeigen:
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
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: 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 ...
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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 28.05.06 11:22
alzaimar 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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 28.05.06 11:25
alzaimar 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
Beiträge: 2510
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: 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:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| if l >= sWinScore then 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!
|
|
|