Skip to content

Instantly share code, notes, and snippets.

@michaelsafyan
Last active June 5, 2022 01:14
Show Gist options
  • Save michaelsafyan/0a62e42aa50be661430b to your computer and use it in GitHub Desktop.
Save michaelsafyan/0a62e42aa50be661430b to your computer and use it in GitHub Desktop.
C++ Playing Cards
#include "card.h"
#include <sstream>
namespace playing_cards {
Card::Card(int value, Suit suit) : value_(value), suit_(suit) {}
Card::Card(const Card& o) : value_(o.value_), suit_(o.suit_) {}
Card::~Card() {}
bool Card::IsValid() const { return (value_ >= ACE) && (value <= KING); }
std::string Card::ToString() const {
std::ostringstream out;
out << *this;
return out.str();
}
bool Card::operator==(const Card& o) const {
return ((value_ == o.value_) && (suit_ == o.suit_));
}
Card::bool color() const { return ((suit_ == SPADES) || (suit_ == CLUBS)); }
int Card::value() const { return value_; }
Suit Card::suit() const { return suit_; }
} // namespace playing_cards
std::ostream& operator<<(std::ostream& out, const Card& card) {
if (!card.IsValid()) {
out << "<Invalid>";
return out;
}
int value = card.value();
switch (card.value()) {
case Card::ACE: out << "Ace"; break;
case Card::JACK: out << "Jack"; break;
case Card::QUEEN: out << "Queen"; break;
case Card::KING: out << "King"; break;
default: out << value; break;
}
out << " of ";
switch (card.suit()) {
case Card::SPADES: out << "Spades"; break;
case Card::CLUBS: out << "Clubs"; break;
case Card::HEARTS: out << "Hearts"; break;
case Card::DIAMONDS: out << "Diamonds"; break;
}
return out;
}
// An illustrative example of how one might define a playing card in C++
// Intended to illustrate some commments in response to StackOverflow question:
// http://stackoverflow.com/questions/28599150/pass-vector-of-card-into-function-to-print-and-use
#ifndef __CARD__
#define __CARD__
#include <string>
#include <iostream>>
// We always want libraries to go in an appropriate namespace to avoid collisions.
namespace playing_cards {
class Card {
public:
// These could also be declared using "const static" instead of "constexpr" for pre-C++11.
// Using "constexpr" increases the ways in which these can be used, though, and also avoids
// needing to declare these variables in the *.cpp file, which is handy.
//
// Defining these improves the API by making code referencing these values clearer than if
// they simply used the numeric value (especially since Ace is sometimes higher valued than King).
constexpr int ACE = 1;
constexpr int JACK = 11;
constexpr int QUEEN = 12;
constexpr int KING = 13;
// Defining these as an enum ensures that an invalid value cannot be supplied. Putting these
// inside the outer "Card" class ensures that the values are well scoped (alternatively,
// one could use an enum class in C++11 outside of Card to keep the values scoped that way).
enum Suit {
SPADES,
CLUBS,
HEARTS,
DIAMONDS
};
// Constructor with the value and suit. A problem with this particular declaration, though,
// is that it makes it trivial to construct an invalid instance of this object. That could
// be resolved by throwing an exception in the event of invalid values, allowing invalid
// states and providing a way to detect them (what we do here), or making this constructor
// private and requiring that this object be instantiated through a factory method that can
// fail and return null. The factory approach is typically my preference, but this is a very
// small object that we expect to be copyable, and so that is a little bit heavy-handed.
// Second to that, I generally prefer objects always be valid and throw an exception if given
// invalid values; however, invalid values may be handy in the case of a card to indicate
// additional, non-standard cards (or perhaps to indicate a Joker?), so in this specific
// case, it is reasonable to defer error handling to the deck or application.
Card(int value, Suit suit);
Card(const Card& o);
~Card();
bool IsValid() const;
std::string ToString() const;
// Technically not necessary (the builtin implementation works just fine), but can be illustrative.
bool operator==(const Card& o) const;
bool color() const;
int value() const;
Suit suit() const;
private:
int value_;
Suit suit_;
};
} // namespace playing_cards
std::ostream& operator<<(std::ostream& out, const playing_cards::Card& card);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment