Einfaches Schachprogramm - Designproblem (Beziehung Figuren <-> Brett)



  • walker schrieb:

    [*] Alle Spielfigurenklassen (Pawn, Rook, Knight, Queen...) werden von der abstrakten Basisklasse "Figure" abgeleitet und müssen die Methode "calculatePossibleFields" implementieren

    nicht gut. attributlose konkrete objekte sind immer ein grund des nachdenklichwerdens. fragst du nachher wirklich das objekt oder willste eigentlich dessen klasse fragen? immerhin sind alle objekte dieser klasse ja identisch. wenn du dann eh eine klasse fragte mithilfe genau einer methode, war es überhaupt sinnvoll, für eine static methode eine klasse zu bauen?

    Letztgenannte Methode erstellt eine Liste (höchstwahrscheinlich verwende ich einen std::vector) von allen möglichen Feldern, die die Figur betreten darf und wird immer aufgerufen, bevor mit ihr ein Zug gemacht wird

    das ist gut. so ne liste ist sehr praktisch.

    Woher "weiß" die Figur nun überhaupt, wo sie steht?

    fragst du beim schachspiel wirklich dir figur, ob sie dahinlaufen kann? also wenn ich nicht bescheid weiß, befrage ich das regelwerk. ein wenig umherschieben der kompetenzen können wir ruhig. ich finde es gut, wenn dewr spielleiter die spieler nach zügen fragt und nach dem zug auch feststellt, ob der gültig war und dann auf dem brett ausführt.
    ich finde es praktisch, wenn er das brett befragen kann, ob ein zug gültig ist.

    Ich wollte ursprünglich eine "Chessboard" Klasse erstellen, die aus einem 8x8 Array der Klasse "Field" besteht, welche wiederum einen Zeiger auf die dort stehende Figur (falls sich dort überhaupt eine befindet) beinhaltet.

    8x8-Array des enums spielstein reicht eigentlich.

    Das heißt, einzig und allein die Chessboard Klasse weiß, wo sich die Figuren befinden.

    klingt gut.

    Bei dieser Gelegenheit möchte ich gleich Fragen, ob ihr ein paar Links zu Seiten/Foren (oder auch Bücher) für mich parat habt, die sich speziell mit solchen Designproblemen beschäftigen, die ich in letzter Zeit verstärkt habe - vorher, zu C-Zeiten habe ich einfach immer drauflosgeschrieben 😋 , aber nun wird mir gutes Design doch immer wichtiger.

    das beste, was du machen kannst, ist das schachprogramm zu schreiben, nachdem du ein 4-gewinnt-programm geschrieben hast.
    schach ist schon zu komplex, um noch an einfache lösungen zu glauben.
    schau dir die tricks der profis an (ok, sie schreiben zwar nen miesen stil, aber sachen wie das 12x12-feld mit todesrand (es gibt 4 farben. schwarz, weiss, leer, blockiert. und ein weißer kann jedes leer- oder schwarzfeld betreten. nie ein weiß- oder blockiert-feld. um das eigentliche spiel sind 2 reihen blockiert. du brauchst dann nie mehr bei irgend einer figur den test machen, ob ein zu überhaupt wegen der brett-dimensionen gültig war) vereinfachen auch deinen code).

    entwurfmuster bringen hier einen scheiß. sind eher hinderlich. manchmal ist eine zigarre nur eine zigarre. du mußt den richtigen weg finden. das ist irgendwo zwischen overengeneering und C.

    edit: enum ist doch zu schwach. also ne klasse für hjeden stein-typ.
    edit2: enum reicht doch. ist einfacher.
    edit3: enum ist doch zu schwach. also ne klasse für jeden stein-typ.

    ach, mach einfach beides und stelle fest, was einfacher war.



  • Hm, also ich würde evtl. es so versuchen:

    Spielsteine (egal ob jetzt Turm, Springer, Läufer) von einer
    Basisklasse ableiten, dann kann man später ein nettes Array
    von Basisklasse *weiss[16] machen. (für schwarz das selbe ;))
    weiss[0]= new Turm;

    Dieses Array könnte man in eine Chessboard klasse tun, oder sagen
    wir eine Klasse die das Schachbrett enthält. Dort gibts nun
    neben den beiden Arrays eine map<position,BaseFigure> pos_fig;
    Darin speicherst du die Position jeder Figur. Die Methode
    GetPossibleFields(position & pos) könnte man implementieren,
    aber ich glaube man könnte das auch eleganter machen, in dem
    man dies irgendwie in der Schachbrettklasse implementiert,
    und man nur noch die Regeln von der Spielfigur klasse definieren
    lässt, evtl. per Funktionszeiger.

    Devil



  • <doppelpost> </doppelpost>



  • volkard schrieb:

    edit: enum ist doch zu schwach. also ne klasse für hjeden stein-typ.
    edit2: enum reicht doch. ist einfacher.
    edit3: enum ist doch zu schwach. also ne klasse für jeden stein-typ.

    Forumsoftware schrieb:

    Zuletzt bearbeitet von volkard am 16 Dez 2004 20:46, insgesamt 1-mal bearbeitet

    😃 👍



  • Also erstmal vielen Dank für die Antworten 😉

    @volkard:

    volkard schrieb:

    walker schrieb:

    [*] Alle Spielfigurenklassen (Pawn, Rook, Knight, Queen...) werden von der abstrakten Basisklasse "Figure" abgeleitet und müssen die Methode "calculatePossibleFields" implementieren

    nicht gut. attributlose konkrete objekte sind immer ein grund des nachdenklichwerdens. fragst du nachher wirklich das objekt oder willste eigentlich dessen klasse fragen? immerhin sind alle objekte dieser klasse ja identisch. wenn du dann eh eine klasse fragte mithilfe genau einer methode, war es überhaupt sinnvoll, für eine static methode eine klasse zu bauen?

    Naja, die unterschiedlichen Objekte würden sich sehr wohl unterscheiden, und zwar wegen der jeweiligen Liste der Felder, die sie betreten dürfen (sie sind also doch nicht attributlos!)

    Oder meinst du ich sollte generell nur _eine_ Liste verwenden, die dann z.B. in der Schachbrett Klasse gespeichert wird und zwar für gerade die Figur, die ziehen wird? Das wär, wenn ich recht überlege, eigentlich ausreichend.

    Ich werd mir wohl morgen in der Schule nochmal den Kopf darüber zerbrechen... was den Spielsteintyp betrifft werd ich es wohl vorerst bei einem enum belassen -- aber wenn es kein enum ist, dann ist es ja wieder eine Klasse, was ja laut deiner ersten Aussage schlecht ist, wenn sie attributlos sind...

    Naja ich hoffe nicht allzu konfus geschrieben dazu haben 🙂

    Letzte Frage: Warum sollten Entwurfsmuster hinderlich sein?

    Gruß,
    walker



  • walker schrieb:

    Naja, die unterschiedlichen Objekte würden sich sehr wohl unterscheiden, und zwar wegen der jeweiligen Liste der Felder, die sie betreten dürfen (sie sind also doch nicht attributlos!)

    es ist auf jeden fall komisch, wenn ein objekt sowohl selber weiß, wo es steht, als auch einfach sich nur in diesem wissen von seinen kollegen unterschiedet, obwohl der benuter des objekts (das spielbrett) eh immer weiß, wo es steht und das billig weitersagen könnte.

    Oder meinst du ich sollte generell nur _eine_ Liste verwenden, die dann z.B. in der Schachbrett Klasse gespeichert wird und zwar für gerade die Figur, die ziehen wird? Das wär, wenn ich recht überlege, eigentlich ausreichend.

    noch weniger. die liste ist weder attribut des steins (ein bauer ist keine figur nach schachterminologie!) noch attribut des bretts. einfach nur kurzlebiger returnwert.

    Ich werd mir wohl morgen in der Schule nochmal den Kopf darüber zerbrechen...

    ein paar wochen darf es schon noch dauern. mit versuchen natürlich. und ich sage dir, es wird einfach nicht funktionieren, daß du erst planst und dann klappt es. du wirst beim implementieren voll oft sehen, daß ein leicht anderer plan am anfang doch besser am ende wäre. manchmal so erheblich besser, daß man 5 klassen wegwerfen muss und mit der anderung am anfang nochmal aufsetzen. aber mach das. sei da ganz cool nd tu so, als würdest du nicht deine fehler korrigieren, sondern die deines feindes und sei stolz auf jede verbesserung.

    was den Spielsteintyp betrifft werd ich es wohl vorerst bei einem enum belassen -- aber wenn es kein enum ist, dann ist es ja wieder eine Klasse, was ja laut deiner ersten Aussage schlecht ist, wenn sie attributlos sind...
    

    enum oder klasse. es gibt wieder aktuelle forschungsergebnisse, die für klasse sprechen. wenn funktionszeiger echt nötig wären, um eine switch-orgie zu vermeiden, dann ist im allgemeinen stattdessen das dispatchen per vtbl noch besser. und genau da kann dann doch wieder die attributlose klasse kommen, die ist normal, um funktionszeigertabellen zu umgehen.

    Naja ich hoffe nicht allzu konfus geschrieben dazu haben  :)
    

    konfuser als ich schreibste bestimmt nicht. ich kann deine texte schneller lesen als meine.

    Letzte Frage: Warum sollten Entwurfsmuster hinderlich sein?

    weil du nicht suchst, WIE du was zu machen hast, sondern WAS du zu machen hast. entwurfsmuster sind IMHO einfach noch zu früh für dich. sie würden deine probleme ganz verwischiwaschien. du würdes auf einmal überlegen, wie du muster einbaust, ohne zu wissen, was rauskommen soll. das erscheint mir fatal hinderlich. ich hab mal ein 4-gewinnt-programm gebaut. so auf meine weise. so lange, bis ich echt keine vereinfachung mehr sah. es war fast nur begriffsbildung. kein akte, der algorithmische oder musterliche hilfe gebrauchen könnte. es war nur eine sehr, sehr lange suche nach den begriffen, die sowohl in der außenwelt klar verständlich als auch im programm mit fast gleicher bedeutung klar verständlich sind. deswegen auch der oben genannte spielleiter. er hatte sich zwei spieler genommen (zeiger auf Spieler), ein brett (Brett) und je abwechslend ie speiler gefragt, welchen zug soie machen sollen (Zug Spieler::getZug(brett const& brett)). und nochj halt nach jedem zug auf unentschieden und gewonnen geprüft. an sich eine triviale sache. und so einfach sollte es bis unten gehen. und ich gebe dir jetzt nicht meinen 4-gewinnt-code, obwohl ich sehr stolz darauf bin. du hast mit deiner programmieraufgabe dir eine aufgabe gestellt, die dich enorm weiterbringen kann und das kostet zwar zeit, wird sich aber vielmals auszahlen, weil du in folgenden aufgaben einfach erfahrung hast. in wichtigen sachen. in entscheidungen, die echt nicht von vorn herein absehbare resultate zeitigen, sodern wo sich fehlentscheidungen erst spät rächen. und diesen gemeinen effekt haste hier fast kostenlos (andere projekte mit so ner gemeinheit kosten immer monatelange arbeit, bevor sich der fehler rächt).



  • Ich denke Grundproblem ist, das das "Schachbrett" weis, wo die Figur steht,
    die Figur weiss wie sie ziehen kann, das Schachbrett weis aber als einziges
    ob sie da überhaupt hin ziehen kann. So kann die Figur nicht wissen,
    ob das Feld besetzt ist oder nicht.



  • volkard schrieb:

    Ich wollte ursprünglich eine "Chessboard" Klasse erstellen, die aus einem 8x8 Array der Klasse "Field" besteht, welche wiederum einen Zeiger auf die dort stehende Figur (falls sich dort überhaupt eine befindet) beinhaltet.

    8x8-Array des enums spielstein reicht eigentlich.

    Da möchte ich widersprechen. Vielleicht willst du deinem Programm
    ja doch irgendwann eine KI verpassen und dann brauchst eine
    Bewertung der Positionen.
    (Mittendrin steht man besser, als am Rand, usw...)

    Jockel



  • Dieses Wissen und die dazugehörigen Daten kann man dann aber bequem in der Klasse KiSpieler unterbringen.



  • Da sehe ich keinen Vorteil. Insbesondere da man ja noch mehr
    Informationen auf das Spielfeld legen kann, z.B. 'Visible' bei
    12x12 - Brettern. Das aufteilen des Bretts in viele 12x12 (oder 8x8)
    Arrays macht meiner Meinung nach keinen Sinn und verwirrt nur.

    Jockel



  • Jockelx schrieb:

    Da sehe ich keinen Vorteil. Insbesondere da man ja noch mehr
    Informationen auf das Spielfeld legen kann, z.B. 'Visible' bei
    12x12 - Brettern. Das aufteilen des Bretts in viele 12x12 (oder 8x8)
    Arrays macht meiner Meinung nach keinen Sinn und verwirrt nur.
    Jockel

    wer spricht von vielen arrays?



  • volkard schrieb:

    wer spricht von vielen arrays?

    Ein Volkard und ein Jester 😉

    Vielleicht hab ich euch auch missverstanden, aber dein Vorschlag
    war doch ein enum-Array mit enum {BAUER, TURM,..} oder sowas zu
    nehmen. Meiner Ansicht nach gehören aber in ein Schachfeld
    mehrere Informationen, weshalb eine Feldklasse vorteilhaft ist.

    Jockel



  • Jo, genau ein Array sollte es geben mit 12x12 Größe. Und da sollte drinstehen können was auf dem Feld ist (Bauer, Läufer, etc. oder auch Leer/blockiert), also ein enum.

    Welche Informationen möchtest Du denn noch im Feld unterbringen?



  • Wie gesagt, beispielsweise wie 'wertvoll' die Position ist.



  • Jockelx schrieb:

    Wie gesagt, beispielsweise wie 'wertvoll' die Position ist.

    Er will ja keine KI schreiben, hier ist nur relevant, welche Figur sich wo befindet.



  • Jockelx schrieb:

    Wie gesagt, beispielsweise wie 'wertvoll' die Position ist.

    Das ist ne KI-Sache. Ein TryToControlCenterAiPlayer kann andere Prioritäten setzen, als ein AttackFromSidesAiPlayer oder ein menschlicher Spieler. Und dem Feld geht das schon gleich gar nichts an, wie irgendein Spieler irgendwas bewertet, IMHO.



  • Langsam komme ich mir veräppelt vor!

    Ja, natürlich ist das eine KI-Sache, hab ich ja auch gesagt, dass
    eine spätere Änderung auf KI dann umständlich wäre.
    Bei der Schachprogrammierung hat jedes Feld im Mittelspiel eine
    (zunächst) konstante Wertigkeit, d.h. dass nicht nur wieviel schlage ich/
    wieviel verliere ich, sondern auch wo stehe ich anschliessend bewertet
    wird. Daher brauch man ein 8x8-int-Array, wo die Wertigkeiten drinstehen
    und das wären dann schonmal 2 Arrays. Wenn ich noch etwas überlege,
    fallen mir sicher noch weitere ein.

    Jockel



  • Jo, diese Wertigkeit gehört aber vom Konzept her trotzdem in die KI und nicht in das Spielfeld.


Anmelden zum Antworten