Vier gewinnt
- fliegermichl
- Lazarusforum e. V.
- Beiträge: 1713
- Registriert: Do 9. Jun 2011, 09:42
- OS, Lazarus, FPC: Lazarus Fixes FPC Stable
- CPU-Target: 32/64Bit
- Wohnort: Echzell
Vier gewinnt
Ich hatte in diesem Thread ein Vier Gewinnt Spiel vorgestellt.
Dort hatte jedes Spielfeld anhand der Gewinnmöglichkeiten an diesem Feld einen Wert zugewiesen bekommen.
Die Bewertungsfunktion für den MiniMax Algorithmus (Bewerten) hat einfach die Werte der Felder, die mit der jeweiligen Farbe besetzt waren, zusammen addiert.
Das hat schon einigermassen geklappt.
Allerdings wurde z.B. nicht berücksichtigt, dass wenn schon 3 Steine beieinander waren, ein vierter das Spiel entscheiden würde.
Bei der Suche nach einer besseren Bewertungsfunktion bin ich auf diese Seite gestoßen und habe da mal den C Quellcode nach Pascal übersetzt.
Er funktioniert auch sehr gut. Ich verstehe nur nicht wie?
Gemeint ist die Funktion scoreBoard, welche auch gleichzeitig ermittelt, ob ein Spieler gewonnen hat.
Dort hatte jedes Spielfeld anhand der Gewinnmöglichkeiten an diesem Feld einen Wert zugewiesen bekommen.
Die Bewertungsfunktion für den MiniMax Algorithmus (Bewerten) hat einfach die Werte der Felder, die mit der jeweiligen Farbe besetzt waren, zusammen addiert.
Das hat schon einigermassen geklappt.
Allerdings wurde z.B. nicht berücksichtigt, dass wenn schon 3 Steine beieinander waren, ein vierter das Spiel entscheiden würde.
Bei der Suche nach einer besseren Bewertungsfunktion bin ich auf diese Seite gestoßen und habe da mal den C Quellcode nach Pascal übersetzt.
Er funktioniert auch sehr gut. Ich verstehe nur nicht wie?
Gemeint ist die Funktion scoreBoard, welche auch gleichzeitig ermittelt, ob ein Spieler gewonnen hat.
- Dateianhänge
-
viergewinnt.zip- (122.12 KiB) 40-mal heruntergeladen
- Zvoni
- Beiträge: 473
- Registriert: Fr 5. Jul 2024, 08:26
- OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
- CPU-Target: 64Bit
- Wohnort: BW
Re: Vier gewinnt
Ist das jetzt ein "klassisches" 4-Gewinnt, oder ein echtes Score 4?
"klassiches" 4 Gewinnt ist nämlich 2D, aber "Score 4" sehe ich immer nur als 3D.
Das 2D "4 Gewinnt" heisst nämlich "Connect 4".
Ich hab mal in den C-Code geschaut.
Find ich unnötig kompliziert, permanent den Score über das gesamte Brett zu berechnen.
Begründung:
Das Spielbrett hat eine finite Grösse (6 hoch, 7 breit), heisst: Es gibt auch eine finite Anzahl möglicher Gewinn-Kombinationen.
Hätte mir die möglichen Gewinn-"Koordinaten" als separate Struktur (Array, Liste, was auch immer) gespeichert, und jedes mal wenn ein neuer Stein gesetzt wird, einfach dort reingeschaut, statt jedesmal durch das ganze Brett zu laufen.
Im Prinzip sowas wie ein Reverse Lookup:
Für jedes Feld auf dem Brett hälst du eine Struktur vor, in WELCHEM es als Gewinn-Möglichkeit vorkommt, und dann rennst du auch nur durch diese Felder.
Beispiel
y=Höhe
x=Breite
[0,0] sei links unten
Das Feld [0,1] ist in 4 Gewinn-Möglichkeiten ein "Mitglied":
[0,0],[0,1],[0,2],[0,3] --> waagrecht, ab ganz links
[0,1],[0,2],[0,3],[0,4] --> waagrecht, ab 2. Spalte
[0,1],[1,1],[2,1],[3,1] --> senkrecht 2. Spalte
[0,1],[1,2],[2,3],[3,4] --> Diagonal nach rechts oben
Heisst: Fällt ein Stein auf [0,1], rennst du eben nicht durch alle Felder, sondern nur durch diese 16
würde übrigens das Spielfeld nicht als 2D-Array speichern sondern als 1D. Koordinaten-Berechnung ist dann einfach mit DIV bzw. MOD.
Beispiel:
Felder 0 bis 6 sind die unterste Reihe, 7 bis 13 die zweite usw.
In meinem Beispiel oben wäre das dann wie folgt:
Feld "0" ist das ganz links unten
Das Feld "1" (unterste Reihe, 2. von links) hätte als Gewinn-Möglichkeit dann
0,1,2,3 -- waagrecht
1,2,3,4 -- waagrecht
1,8,15,22 -- senkrecht
1,9,17,25 -- Diagonal links unten nach rechts oben
Das Feld "6" (ganz rechts unten) hat "nur" 3 Gewinnreihen:
3,4,5,6 --waagrecht
6,13,20,27 --senkrecht
6,12,18,24 -- Diagonal von Links oben nach rechts unten
Feld "3" (unterste Reihe Mitte) hat 7 GewinnReihen
0,1,2,3 --waagrecht
1,2,3,4 --waagrecht
2,3,4,5--waagrecht
3,4,5,6 --waagrecht
3,10,17,24 --senkrecht
3,9,15,21 -- Diagonal von Links oben nach rechts unten
3,11,19,27 -- Diagonal von Links unten nach rechts oben
Und in diesen "Gewinn-Strukturen" speicherst du eben nur die Indizes der Gewinn Felder.
Hätte wahrscheinlich nen Record mit dynamischem Array gemacht
Da die Gewinn-Reihen "statisch" sind, würde ich die in einer kleine Datenbank, INI-File, Datei, Socken-Schublade, was auch immer, permanent vorhalten
"klassiches" 4 Gewinnt ist nämlich 2D, aber "Score 4" sehe ich immer nur als 3D.
Das 2D "4 Gewinnt" heisst nämlich "Connect 4".
Ich hab mal in den C-Code geschaut.
Find ich unnötig kompliziert, permanent den Score über das gesamte Brett zu berechnen.
Begründung:
Das Spielbrett hat eine finite Grösse (6 hoch, 7 breit), heisst: Es gibt auch eine finite Anzahl möglicher Gewinn-Kombinationen.
Hätte mir die möglichen Gewinn-"Koordinaten" als separate Struktur (Array, Liste, was auch immer) gespeichert, und jedes mal wenn ein neuer Stein gesetzt wird, einfach dort reingeschaut, statt jedesmal durch das ganze Brett zu laufen.
Im Prinzip sowas wie ein Reverse Lookup:
Für jedes Feld auf dem Brett hälst du eine Struktur vor, in WELCHEM es als Gewinn-Möglichkeit vorkommt, und dann rennst du auch nur durch diese Felder.
Beispiel
y=Höhe
x=Breite
[0,0] sei links unten
Das Feld [0,1] ist in 4 Gewinn-Möglichkeiten ein "Mitglied":
[0,0],[0,1],[0,2],[0,3] --> waagrecht, ab ganz links
[0,1],[0,2],[0,3],[0,4] --> waagrecht, ab 2. Spalte
[0,1],[1,1],[2,1],[3,1] --> senkrecht 2. Spalte
[0,1],[1,2],[2,3],[3,4] --> Diagonal nach rechts oben
Heisst: Fällt ein Stein auf [0,1], rennst du eben nicht durch alle Felder, sondern nur durch diese 16
würde übrigens das Spielfeld nicht als 2D-Array speichern sondern als 1D. Koordinaten-Berechnung ist dann einfach mit DIV bzw. MOD.
Beispiel:
Felder 0 bis 6 sind die unterste Reihe, 7 bis 13 die zweite usw.
In meinem Beispiel oben wäre das dann wie folgt:
Feld "0" ist das ganz links unten
Das Feld "1" (unterste Reihe, 2. von links) hätte als Gewinn-Möglichkeit dann
0,1,2,3 -- waagrecht
1,2,3,4 -- waagrecht
1,8,15,22 -- senkrecht
1,9,17,25 -- Diagonal links unten nach rechts oben
Das Feld "6" (ganz rechts unten) hat "nur" 3 Gewinnreihen:
3,4,5,6 --waagrecht
6,13,20,27 --senkrecht
6,12,18,24 -- Diagonal von Links oben nach rechts unten
Feld "3" (unterste Reihe Mitte) hat 7 GewinnReihen
0,1,2,3 --waagrecht
1,2,3,4 --waagrecht
2,3,4,5--waagrecht
3,4,5,6 --waagrecht
3,10,17,24 --senkrecht
3,9,15,21 -- Diagonal von Links oben nach rechts unten
3,11,19,27 -- Diagonal von Links unten nach rechts oben
Und in diesen "Gewinn-Strukturen" speicherst du eben nur die Indizes der Gewinn Felder.
Hätte wahrscheinlich nen Record mit dynamischem Array gemacht
Code: Alles auswählen
Type
TFeld = Record
FeldIndex:Integer;
GewinnReihen: Array Of Array[0..3] Of Integer;
End;
Var SpielFeld:Array[0..41] Of TFeld;
//Initialisiere alles ...blablaEin System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.
- fliegermichl
- Lazarusforum e. V.
- Beiträge: 1713
- Registriert: Do 9. Jun 2011, 09:42
- OS, Lazarus, FPC: Lazarus Fixes FPC Stable
- CPU-Target: 32/64Bit
- Wohnort: Echzell
Re: Vier gewinnt
Zunächst einmal vielen Dank für deine Ausführungen.
Mir geht es aber in erster Linie darum, zu verstehen, wie die Bewertungsfunktion scoreBoard zu ihren Ergebnissen kommt.
Sie berücksichtigt dabei nämlich auch "Angriffe" vom Gegner mit ziemlich wirksamer Abwehr.
Mir geht es aber in erster Linie darum, zu verstehen, wie die Bewertungsfunktion scoreBoard zu ihren Ergebnissen kommt.
Sie berücksichtigt dabei nämlich auch "Angriffe" vom Gegner mit ziemlich wirksamer Abwehr.
- Zvoni
- Beiträge: 473
- Registriert: Fr 5. Jul 2024, 08:26
- OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
- CPU-Target: 64Bit
- Wohnort: BW
Re: Vier gewinnt
Also wenn ich es richtig verstanden habe, speichert er die „Konter“ in counters, und nutzt diese für eine schnelle Entscheidung.fliegermichl hat geschrieben: Fr 21. Nov 2025, 15:31 Zunächst einmal vielen Dank für deine Ausführungen.
Mir geht es aber in erster Linie darum, zu verstehen, wie die Bewertungsfunktion scoreBoard zu ihren Ergebnissen kommt.
Sie berücksichtigt dabei nämlich auch "Angriffe" vom Gegner mit ziemlich wirksamer Abwehr.
Nach dem Motto: Wenn gelb in der untersten Reihe in der Mitte ist, braucht er für Orange die unterste Reihe erst gar nicht zu prüfen, weil orange da nie gewinnen kann.
Mag mich aber auch irren. Bin aus dem Code auch nicht schlau geworden.
Außerdem gibts ne Funktion „inside“ die nie aufgerufen wird!?!??!
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.
- corpsman
- Lazarusforum e. V.
- Beiträge: 1671
- Registriert: Sa 28. Feb 2009, 08:54
- OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
- CPU-Target: 64Bit
- Wohnort: Stuttgart
- Kontaktdaten:
Re: Vier gewinnt
Komisch,
wenn man das Spiel gewinnt, dann passiert nichts ...
Laut Source sollte da eine Meldung kommen.
Auch musste ich Ausdrücke wie
zu
umschreiben, du hast da wohl eine Einstellung Aktive die nicht by Default aktiv ist ..
by the way das repo ist witzig, ggf portiere ich das nach FPC und wir schaun mal wie wir mit FPC in seinen Benchmarks so abschneiden
wenn man das Spiel gewinnt, dann passiert nichts ...
Laut Source sollte da eine Meldung kommen.
Auch musste ich Ausdrücke wie
Code: Alles auswählen
score -= scores[y][x - 3]; Code: Alles auswählen
score := score - scores[y][x - 3]; umschreiben, du hast da wohl eine Einstellung Aktive die nicht by Default aktiv ist ..
by the way das repo ist witzig, ggf portiere ich das nach FPC und wir schaun mal wie wir mit FPC in seinen Benchmarks so abschneiden
--
Just try it
Just try it
- fliegermichl
- Lazarusforum e. V.
- Beiträge: 1713
- Registriert: Do 9. Jun 2011, 09:42
- OS, Lazarus, FPC: Lazarus Fixes FPC Stable
- CPU-Target: 32/64Bit
- Wohnort: Echzell
Re: Vier gewinnt
Doch, in dem Memo rechts erscheint dann, "Du hast gewonnen"corpsman hat geschrieben: Fr 21. Nov 2025, 16:46 Komisch,
wenn man das Spiel gewinnt, dann passiert nichts ...
Laut Source sollte da eine Meldung kommen.
Ich habe unter Projekteinstellungen -> Compilereinstellungen -> Parsen -> Syntaxeinstellungen die Option "C-artige Operatoren" aktiv. Das ist aber per default eingestellt.Auch musste ich Ausdrücke wiezuCode: Alles auswählen
score -= scores[y][x - 3];Code: Alles auswählen
score := score - scores[y][x - 3];
umschreiben, du hast da wohl eine Einstellung Aktive die nicht by Default aktiv ist ..
Ja, das könnte man mal machen.by the way das repo ist witzig, ggf portiere ich das nach FPC und wir schaun mal wie wir mit FPC in seinen Benchmarks so abschneiden![]()
- fliegermichl
- Lazarusforum e. V.
- Beiträge: 1713
- Registriert: Do 9. Jun 2011, 09:42
- OS, Lazarus, FPC: Lazarus Fixes FPC Stable
- CPU-Target: 32/64Bit
- Wohnort: Echzell
Re: Vier gewinnt
Die hatte ich aus dem C Code übernommen, wird aber hier nicht gebraucht, da man keinen Stein ausserhalb des Spieles einwerfen kann.Zvoni hat geschrieben: Fr 21. Nov 2025, 16:38 ...
Außerdem gibts ne Funktion „inside“ die nie aufgerufen wird!?!??!
- corpsman
- Lazarusforum e. V.
- Beiträge: 1671
- Registriert: Sa 28. Feb 2009, 08:54
- OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
- CPU-Target: 64Bit
- Wohnort: Stuttgart
- Kontaktdaten:
Re: Vier gewinnt
Weil es nicht mehr wirklich zu diesem Thread gehört hab ich mal einen Follow up gestartet siehe hier 
--
Just try it
Just try it