Schach-Programm (Anfangs-tipps)
-
Hacker schrieb:
µ schrieb:
Hacker schrieb:
Was die graphische Oberfläche angeht
Würde ich an Deiner Stelle vorerst drauf verzichten, bis das Ding in der Console läuft.
Das ist doch klar. Ich meinte, jetzt so ein ein paar Wochen, wenn das erste Spiel gespielt ist.
Warum ein paar Wochen? Mach Dir das Leben nicht so schwer und programmiere drauf los, immer mit dem Hintergedanken, dass die Verantwortlichkeiten verteilt sein müssen. Halte die Klassen extrem Schlank. Verzichte, außer bei den Figuren, auf Vererbung. Führe alle anderen Aktionen als Konstruktorparameter in die Klassen (Dependency-Injection). Verzichte auf Template-Gehacke.
Um ehrlich zu sein kam ich gestern Abend nach dem erneuten Lesen dieses Threads auf den Geschmack.
Habe nun meinen Vorschlag von gestern mal realisiert und es funktioniert ohne Probleme.
Heißt: Spiele gegen eine Random-KI (die aber trotz Random nur gültige Züge abliefert), Spiele zwischen zwei solchen Dumm-KIs und Spiele zwischen zwei Menschen sind bereits möglich.
Ausgabe bisher nur Console. Schachsituation und Rochaden (Remis, Bauerntausch ebenfalls) fehlen noch. Beliebige Aktionen können über eine History-Klasse mit internem Stack von "Move/Zug"-Objekten rückgängig gemacht werden. Die Board-Klasse hat kaum 100 Zeilen und besteht nur aus dümmsten Hilfsfunktionen. (EnemyAt, FriendAt und solche Dinge).
-
µ schrieb:
Hacker schrieb:
µ schrieb:
Hacker schrieb:
Was die graphische Oberfläche angeht
Würde ich an Deiner Stelle vorerst drauf verzichten, bis das Ding in der Console läuft.
Das ist doch klar. Ich meinte, jetzt so ein ein paar Wochen, wenn das erste Spiel gespielt ist.
Warum ein paar Wochen? Mach Dir das Leben nicht so schwer und programmiere drauf los, immer mit dem Hintergedanken, dass die Verantwortlichkeiten verteilt sein müssen. Halte die Klassen extrem Schlank. Verzichte, außer bei den Figuren, auf Vererbung. Führe alle anderen Aktionen als Konstruktorparameter in die Klassen (Dependency-Injection). Verzichte auf Template-Gehacke.
Um ehrlich zu sein kam ich gestern Abend nach dem erneuten Lesen dieses Threads auf den Geschmack.
Habe nun meinen Vorschlag von gestern mal realisiert und es funktioniert ohne Probleme.
Heißt: Spiele gegen eine Random-KI (die aber trotz Random nur gültige Züge abliefert), Spiele zwischen zwei solchen Dumm-KIs und Spiele zwischen zwei Menschen sind bereits möglich.
Ausgabe bisher nur Console. Schachsituation und Rochaden (Remis, Bauerntausch ebenfalls) fehlen noch. Beliebige Aktionen können über eine History-Klasse mit internem Stack von "Move/Zug"-Objekten rückgängig gemacht werden. Die Board-Klasse hat kaum 100 Zeilen und besteht nur aus dümmsten Hilfsfunktionen. (EnemyAt, FriendAt und solche Dinge).WHAT THE ?
In ein paar Stunden? Mannoman....
Wie hast du das mit dem Schach realisiert? Also, wie überprüfst du ob ein Zug gültig ist, wenn danach noch Schach ist ist er das ja nicht?
-
Du mußt dir die Position der Könige merken und schauen, ob einer der gegnerischen Figuren dorthin ziehen kann (also den König schlagen könnte). Einzig bei einer Rochade mußt du auch das jeweils übersprungene Feld zusätzlich auf Schach abfragen.
Habe gerade meine alten Sourcen durchsucht und mein Konsolen-Schackprogramm (in C, auf dem Amiga, von 1993) wiederentdeckt. Hat ca. 500 Zeilen und wurde von mir - laut Kommentar - innerhalb von 4 Tagen erstellt.
-
Th69 schrieb:
Du mußt dir die Position der Könige merken und schauen, ob einer der gegnerischen Figuren dorthin ziehen kann (also den König schlagen könnte).
Das reicht nicht ganz. Der Königszug muss simuliert werden um erst dann zu schauen, ob er bedroht ist. Es könnte nämlich sein, dass ein Feld, auf das der König zieht, sowohl von einem Gegner besetzt als auch gedeckt ist. Die deckende Figur konnte in der ausgangsituation nicht hinziehen, weil dort eine Figur gleicher Farbe stand.
8 | | | | | | | | | - - - - - - - - 7 | | | | | | | | | - - - - - - - - 6 | | | | | | | | | - - - - - - - - 5 | |b| | | | | | | - - - - - - - - 4 | | |r| | | | | | - - - - - - - - 3 | | | |K| | | | | - - - - - - - - 2 | | | | | | | | | - - - - - - - - 1 | | | | | | | | | - - - - - - - - A B C D E F G H
König auf D3 kann nicht auf C4 ziehen, weil der Bauer auf B5 dieses Feld schützt. In dieser Ausgangssituation ist C4 für den Bauer aber eben noch nicht erreichbar.
Umgesetzt: Mögliche Züge für König ermitteln, Historystack puschen (Zug simulieren), schauen ob König bedroht, Stack popen und Zugvorschlag verwerfen.
-
Hallo µ,
genau so meinte ich es ja, d.h. man führt den Zug aus (d.h. simuliert ihn) und überprüft dann, ob der König bedroht ist (und bei einem Zug des Königs selbst wird natürlich auf dessen neue Position überprüft).
-
Hi Th69,
dann habe ich dich missverstanden.
Vorhin habe ich diesen Fall selbst vergessen und erst in einem Testlauf entdeckt.
-
Hacker schrieb:
WHAT THE ?
In ein paar Stunden? Mannoman....
Und deshalb mag ich C# so sehr
-
VERDAMMT! Jetzt gibt es auf einmal einen Fehler, bei dem
this
0 ist... Wie blöd
-
Hintergrund: Im Debugger wird angezeigt,
this
sei hier noch 0x7..... :bool figure::is_enemy(figure const& a) const { return a.white() != white(); }
Jetzt, in der folgenden Funktion ist
this
0!bool figure::white() const { return m_white;//Wird zu this->m_white was natürlich einen Speicherzugriffsfehler gibt. }
Ich allokiere die Figuren mit new im Konstruktor von der Hauptklasse chessGame, wo das ptr_array mit allen Bauern gefüllt wird:
for(size_t white(0);white < 2;++white) for(size_t a(0);a < 8;++a) { auto index(a + 8 * white); auto newPawn = new chess::pawn({a, ((white)? 1 : 6)}, white, &m_board); //Im Konstruktor werden Funktionen aufgerufen, die nacheinander bei is_enemy (und schließlich bei white() ) landen. m_Pawns.replace(index, newPawn); }
-
Vielleicht könnte mir jemand, der mit den Schachregeln besser vertraut ist, folgende Frage beantworten:
- - - - - - - - 8 | | | | | | | | | - - - - - - - - 7 | | | | | | | | | - - - - - - - - 6 | | | | | | | | | - - - - - - - - 5 | | | | |r| | | | - - - - - - - - 4 | |k| | |Q| | | | - - - - - - - - 3 | | | | |K| | | | - - - - - - - - 2 | | | | | | | | | - - - - - - - - 1 | | | | | | | | | - - - - - - - - A B C D E F G H
(r = schwarzer Turm, k = schwarzer König, K = weißer König, Q = weiße Königin)
Befindet sich der schwarze König im Schach oder nicht?
Die Queen könnte ihn ja nicht schlagen, ohne ihren König selbst ins Schach zu stellen.
-
Ja, er befindet sich im Schach.
-
Wenn ein König gefressen würde, wäre das Spiel sofort aus.
-
Finde nur am Wochenende Zeit daran zu arbeiten. Diesmal eine, vorläufige, GUI:
http://img834.imageshack.us/img834/9555/chessk.png
EDIT: Der GUI-Code ist ein Schlachtfeld. Ich hasse GUIs
-
Wie hast du es denn geschafft diese Stellung zu produzieren, die sieht ja abenteuerlich aus
-
KPC schrieb:
Wie hast du es denn geschafft diese Stellung zu produzieren, die sieht ja abenteuerlich aus
Die Models haben sich einzig und allein für einen hübschen Screenshot in Stellung gebracht
-
KPC schrieb:
Wie hast du es denn geschafft diese Stellung zu produzieren, die sieht ja abenteuerlich aus
Steht sogar im Log.
@µ Geile Figuren.
-
cooky451 schrieb:
@µ Geile Figuren.
Jeder der mir hübschere Grafiken liefern möchte, fühle sich hiermit angesprochen
-
Das Command Pattern bietet sich für eine History ganz gut an, damit lassen sich Funktionen wie undo() / redo() sehr gut realisieren. Gerade in diesem Fall ist es trivial zu implementieren, z.B.
CommandMovePiece { Position OldPosition_; Position NewPosition_; Piece* Piece_; Board* Board_; public: CommandMovePiece( Board* Board, Piece* Piece, const Position& op, const Position& np ) : Board_( Board ), Piece_( Piece ), OldPosition_( op ), NewPosition_( np ) { assert( Board ); assert( Piece ); } void execute() { // normale Aktion ist identisch mit redo() redo(); } void undo() { // Figur von neuer Position an alte zurückstellen assert( Board_->at( NewPosition ) == Piece_ ); move_piece( Piece_, Board_, NewPosition_, OldPosition_ ); } void redo() { // Figur von alter Position an neue stellen assert( Board_->at( OldPosition ) == Piece_ ); move_piece( Piece_, Board_, OldPosition_, NewPosition_ ); } }
So kannt du die komplette Zughistorie in einem std::vector halten und jede beliebige Stellung wiederherstellen. Das ist ganz brauchbar, wenn man verschiedene Stellungen bewerten will.
Ein Sonderfall ist natürlich, wenn man zu einer Stellung zurückgeht und ab da weiterspielt, da muss man Teile der Historie verwerfen.Im übrigen würde ich keine verschachtelten Arrays zur Boarddarstellung benutzen, beim Schach kann man davon ausgehen, dass das Board immer 8x8 Felder groß ist. Ein statisches 2D Array tut´s genauso gut.
-
(Auch wenn ich das Schach-Programm vorerst "aufgeben" musste
) Wenn du eine Figur schlägst, dann ist dieser Zug eigentlich zwei (also der "schlag"-Zug und der Zug der geschlagenen Figur vom Brett woanders hin (z.B. In einen graveyard-Bereich)?
-
Das sind Spezialfälle, die natürlich bedacht werden müssen. Eine Rochade kannst du damit auch nicht durchführen. Jeder Zug sollte atomar sein, d.h. wenn ich ihn zurücknehme sollen alle Folgen ebenfalls rückgängig gemacht werden. Vielleicht macht Polymorphismus da Sinn, mit einem MoveCommand, CaptureCommand, CaptureEnPassantCommand und CastlingCommand.