Durchreichmethoden vermeiden?
-
Hallo zusammen, ich habe in den letzten Tagen das Kartenspiel Black Jack implementiert und bin mit dem Gesamtergebnis etwas unzufrieden.
Es ist spielbar und läuft so ganz gut aber meinen Code finde ich merkwürdig.
Vor Allem gefallen mir diese "Durchreichmethoden" nicht:stack.h:
#ifndef STACK_H #define STACK_H #include <vector> #include "card.h" #include "deck.h" class Stack { private: vector <Card*> m_cards; public: Stack(void); ~Stack(void); void Set(Deck&); void Clear(void); void Stack::AddCard(Card*); void PullCard(Stack&); Card* GetCard(int); int GetSize(void); void Shuffle(void); }; #endif
player.h:
#ifndef PLAYER_H #define PLAYER_H #include "stack.h" class Player { private: Stack m_hand; string m_name; float m_money; float m_bets; public: Player(); Player(string, int); ~Player(void); void SetName(string); string GetName(void); Stack* GetHand(void); float GetMoney(void); int GetTotal(void); void ClearHand(void); void SetBet(float); void PullFirstCards(Stack&); void Hit(Stack&); void Double(Stack&); void Win(void); Card* GetCard(int); bool CheckBlackJack(void); void Push(void); void BlackJack(); }; #endif
Wie man sieht, taucht die Methode Card* GetCard(int); in beiden Klassen auf.
stack.cpp:
Card* Stack::GetCard(int index) { return m_cards[index]; }
player.cpp:
Card* Player::GetCard(int index) { return m_hand.GetCard(index); }
Es ist quasi das Selbe nur der Player reicht sozusagen einfach die Karte des Stapels (der eigenen Hand) durch und ich finde es irgendwie doof
Sind solche Durchreichmethoden normal, oder ist mein Code unvorteilhaft?Ich würde mich freuen wenn sich soetwas vermeiden lässt.
MfG oop-greenhorn
-
Zum Einen sind solche "durchreichemethoden" durchaus üblich und nicht sofort schlecht. Zum Anderen hast du aber bei deiner Player-klasse eh schon die "GetHand"-Methode, so dass die GetCard-Methode eigentlich überflüssig ist. Das Interface der Klasse Player ist also höchst wahrscheinlich zu breit. Es sollte nicht so breit wie möglich, sondern nur so breit wie nötig sein.
-
Wenn Dein Code langweilig ist, ist das kein Problem, sondern eine Ehrung.
Es ist kein doppelter Code, sondern Du hast Dich bewußt entschieden, daß dein Player so trivial ist. Da Du andererseits nicht sagen darfst, "Ein Player ist ein Kartenstapel.", kannste auch nicht mit Vererbungstricks das Schreiben dieser drei Zeilen einsparen.
Card* Player::GetCard(int index) { if(niemdSiehts() && time()-lastSchummelTime<300+rand()%600){ lastSchummelTime=time(); ist best=getBestAermelCardIndex(); swap(m_aermel[best],m_hand[index]); } return m_hand.GetCard(index); }
-
ups, ja das ist bisher nur der Funktionsprototyp, die Methode selbst gibts noch nicht.
Also wäre es sinvoller an die Hand zu kommen (es gibt später 2 hände wenn man splittet)?
Ist jetzt mein Gedanke...
MfG
-
volkard schrieb:
Wenn Dein Code langweilig ist, ist das kein Problem, sondern eine Ehrung.
Es ist kein doppelter Code, sondern Du hast Dich bewußt entschieden, daß dein Player so trivial ist. Da Du andererseits nicht sagen darfst, "Ein Player ist ein Kartenstapel.", kannste auch nicht mit Vererbungstricks das Schreiben dieser drei Zeilen einsparen.
Ich habe mich dafür bewusst entschieden, weil ich keinen sinvolleren Weg kenne, im nachhinein hätte ich es wohl doch anders gemacht (wenns sinvoller wäre).
MfG
PS: Dein Code lustig aber sinnlos, bei Black Jack verwaltet der Croupier die gesamten Karten, würde auffallen
-
Ich glaube, ich würde Deck und Stack zu reinen Kartenstapeln degradieren, den Player zum reinen Entscheider und einen Dealer bauen, der die Karten umherreicht und immer den Player fragt, was zu tun ist.
-
oop-greenhorn schrieb:
PS: Dein Code lustig aber sinnlos, bei Black Jack verwaltet der Croupier die gesamten Karten, würde auffallen
void PullFirstCards(Stack&) sagt aber, daß der Player das selber macht, oder?
Würde der Croupier die Karten verwalten, müßte er den Spieler gar nicht mehr danach fragen und fragliche Durchreichefunktion wäre weg. Und der Spieler könnte nicht schummeln.Zug Player::wasMachen(Stack const* offeneKarten,Stack const* deineHand,Stack const* deineAndereHand=0); enum Zug{KARTENEHMEN,SPLITTEN,AUFGEBEN,WASWEISSICHICHKENNEDASSPIELJAGARNICHT,}
Beim 4-Gewinnt-Spiel fühlt sich das sorum richtig gut an.
-
volkard schrieb:
Ich glaube, ich würde Deck und Stack zu reinen Kartenstapeln degradieren, den Player zum reinen Entscheider und einen Dealer bauen, der die Karten umherreicht und immer den Player fragt, was zu tun ist.
Bei mir ist es halt so: Deck ist der Kartenstapel mit den realen Karten.
Stack ist der Stapel mit den Zeigern zu den ganzen Karten des Decks.
So brauche ich nurnoch für das Mischen ein paar Zeiger mischen lassen.Das ist irgendwie mein Problem es gibt x-verschiedene Lösungsmöglichkeiten des Problems und ich suche das Optimalste.
volkard schrieb:
void PullFirstCards(Stack&) sagt aber, daß der Player das selber macht, oder?
Ja
Da frag ich mich wenn der Croupier alles machen und fragen soll, wie der mit dem Player interagieren soll.
Aber bisher hat mich das schonmal zum weiterdenken angeregt
Mfg
-
oop-greenhorn schrieb:
Da frag ich mich wenn der Croupier alles machen und fragen soll, wie der mit dem Player interagieren soll.
Er fragt ihn folgendermaßen:
Er zeigt auf den Speiler, den offenen Kartenstapel und die Hände des Spielers und sagt "wasDuMacheWolle?".Zug Player::wasMachen(Stack const* offeneKarten,Stack const* deineHand,Stack const* deineAndereHand=0);
Der Spieler sagt daraufhin eines der vier oder so vereinbarten Zauberwörter, was er machen will.
if.... return KARTENEHMEN;
Darufhin ist der Croupier wieder dran. Er kann dem Spieler zum Beispiel sagen
void Player::duHastVerloren();
oder daß er gewonnen hat, oder ihn nach einem weiteren Zug fragen.
Das ist irgendwie mein Problem es gibt x-verschiedene Lösungsmöglichkeiten des Problems und ich suche das Optimalste.
Die Optimalste kannste eh erst finden, nachdem Du die zweitoptimalste gebaut hast. Aber mit tollen Vorüberlegungen beschleunigst Du die Suche und das Ausprobieren ungemein.