Previous review of this project:
Deck of cards program using a card value map
Based on the previous feedback I've received, my program could become more flexible (it formerly created a standard 52-card deck by itself). Now, the user can add Cards to a Deck, and Card is no longer hidden. I like this approach better (also easier to work with), but I'm sure it can still be improved. Regarding its use, I have a few questions:
Although accessors aren't always recommended, would they still be necessary for allowing the driver to know each
Cardvalue/rank/suit (unless they're maintained elsewhere)? For instance, Blackjack requires card numerical values for determining a bust.Is the exception-handling in
deal()effective (when called on an emptyDeck), although it'll still need to return aCard? This is assuming that the user will not always callempty()before callingdeal().Is this particular approach too flexible? If so, what could be done instead?
Deck.h
#ifndef DECK_H
#define DECK_H
#include <iostream>
#include <cstdint>
#include <vector>
class Card
{
private:
unsigned value;
char rank;
char suit;
public:
Card(unsigned v, char r, char s) : value(v), rank(r), suit(s) {}
friend std::ostream& operator<<(std::ostream &out, const Card &card)
{return out << '[' << card.rank << card.suit << ']';}
};
class Deck
{
private:
std::vector<Card> cards;
int topCardPos;
public:
Deck();
void addCard(unsigned value, char rank, char suit);
void shuffle();
Card deal();
std::size_t size() const {return topCardPos+1;}
bool empty() const {return topCardPos == -1;}
friend std::ostream& operator<<(std::ostream &out, const Deck &deck);
};
#endif
Deck.cpp
#include "Deck.h"
#include <algorithm>
#include <stdexcept>
Deck::Deck() : topCardPos(-1) {}
void Deck::shuffle()
{
topCardPos = cards.size()-1;
std::random_shuffle(cards.begin(), cards.end());
}
void Deck::addCard(unsigned value, char rank, char suit)
{
cards.push_back(Card(value, rank, suit));
topCardPos++;
}
Card Deck::deal()
{
try
{
topCardPos--;
return cards.at(topCardPos+1);
}
catch (const std::out_of_range &oor)
{
std::cerr << "\nDECK DEAL ERROR: " << oor.what() << "\n";
Card blankCard(0, '*', '*');
return blankCard;
}
}
std::ostream& operator<<(std::ostream &out, const Deck &deck)
{
for (unsigned i = 0; i < deck.size(); ++i)
{
out << "\n" << deck.cards[i];
}
return out;
}
(Possible driver)
Deck deck;
std::array<char, 13> RANKS = {'A','2','3','4','5','6','7','8','9','T','J','Q','K'};
std::array<char, 4> SUITS = {'H','D','C','S'};
for (unsigned rank = 0; rank < RANKS.size(); ++rank)
{
unsigned value = (rank < 10) ? rank+1 : 10;
for (unsigned suit = 0; suit < SUITS.size(); ++suit)
{
deck.addCard(value, RANKS[rank], SUITS[suit]);
}
}