3
\$\begingroup\$

In my Blackjack game so far, I have multiple classes that access each other frequently. For example, this is my hit() function for the Game class:

void Game::hit(unsigned playerNum)
{
    Card newCard = deck.deal();
    players[playerNum].getPlayerHand()[0].getHandCards().push_back(newCard);
}

First, a new Card object is assigned a new card from the Deck object. However, the next line gets more complicated. Essentially:

  1. The specified player's Hand object vector is accessed. As such, it needs an index. I'm doing this so that I can easily destroy hands without looping.

    players[playerNum].getPlayerHand()[0]
    
  2. In that one Hand object in the vector, its card vector is accessed.

    players[playerNum].getPlayerHand()[0].getHandCards()
    
  3. That aforementioned card is pushed onto the player's hand card vector.

    players[playerNum].getPlayerHand()[0].getHandCards().push_back(newCard);
    

Again, I'm using a Hand object so that I can easily destroy a player's cards at the end of each turn. In the game, different players can end up with a different number of cards at the end of each turn. If I assign each player a vector of cards instead, I would have to loop through the vector and pop each card. With a Hand, I can just pop the Hand and push a new one. However, using a Hand class here means more accessing, which complicates the code's flow.

What would be a good solution to this? I'm okay with either method (preferably the one with Hand), but they do have their pros and cons. If there is a better solution, I'd like to know about it.

Here are snippets of the relevant class' headers:

Game.h

class Game
{
private:
    std::vector<Player> players;
    Deck deck;

public:
    Game();
    ~Game();
};

Player.h

class Player
{
private:
    std::vector<Hand> playerHand;

public:
    Player();
    ~Player();
    std::vector<Hand>& getPlayerHand() {return playerHand;}
};

Hand.h

class Hand
{
private:
    std::vector<Card> cards;

public:
    Hand();
    ~Hand();
    std::vector<Card>& getHandCards() {return cards;}
};

Card.h

class Card
{
private:
    int rankValue;
    char rank;
    char suit;
    std::string card;

public:
    Card();
    Card(char, char);
    ~Card();
};
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

This code:

void Game::hit(unsigned playerNum)
{
    Card newCard = deck.deal();
    players[playerNum].getPlayerHand()[0].getHandCards().push_back(newCard);
}

should read:

void Game::hit(unsigned playerNum)
{
    Card newCard = deck.deal();
    players[playerNum].hit(newCard);
}

The thing is, your classes shouldn't access each other like that. You shouldn't have getter methods that return the internal vectors. You should have methods that perform operations. If you do that, I think your question won't even come up.

\$\endgroup\$
4
  • \$\begingroup\$ @JamalA, huh? Nothing I changed should be related to whether or not Game::hit is public. \$\endgroup\$ Apr 4, 2013 at 22:35
  • \$\begingroup\$ Sorry, that comment was submitted early on accident. Anyway, I'll take a look at how this could be changed since it doesn't work as it is. \$\endgroup\$
    – Jamal
    Apr 4, 2013 at 22:36
  • \$\begingroup\$ @JamalA, right, I'm assuming that you'll add a Player::hit function. \$\endgroup\$ Apr 4, 2013 at 22:37
  • \$\begingroup\$ Yes, I can do that. Regarding that, I'm not exactly sure how to "distribute" my functions among classes. I'll go ahead and post all the functions for Game and Player that I have so far. \$\endgroup\$
    – Jamal
    Apr 4, 2013 at 22:38
2
\$\begingroup\$

There appears to be some verbosity in these classes:

  • The default constructor and destructor declarations are unneeded as the compiler will generate default ones automatically, which are still suitable for this use.

  • The rankVal member doesn't quite belong to Card. The implementation will need to provide this value since it can vary among different games.

  • Card doesn't need a card member. It only needs rank and suit since they both help define the properties of a Card. Any member function that will return the value or display a Card should simply put these two data members together in some way.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.