#include <string>
#include <array>
#include <algorithm>
#include <ostream>
#include <iostream>
#include <random>
namespace constants
{
static constexpr const size_t num_values = 13;
static constexpr const size_t num_suits = 4;
static constexpr const size_t num_cards = num_values * num_suits;
}
enum class Value : int8_t
{
None = -1,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace
};
enum class Suit : int8_t
{
None = -1,
Heart,
Diamond,
Spade,
Club
};
template<typename T>
std::string to_string(const T&);
template<>
std::string to_string<Value>(const Value& value)
{
std::string str;
switch(value)
{
case Value::None: str = "None"; break;
case Value::Two: str = "2"; break;
case Value::Three: str = "3"; break;
case Value::Four: str = "4"; break;
case Value::Five: str = "5"; break;
case Value::Six: str = "6"; break;
case Value::Seven: str = "7"; break;
case Value::Eight: str = "8"; break;
case Value::Nine: str = "9"; break;
case Value::Ten: str = "T"; break;
case Value::Jack: str = "J"; break;
case Value::Queen: str = "Q"; break;
case Value::King: str = "K"; break;
case Value::Ace: str = "A"; break;
default: break;
}
return str;
}
template<>
std::string to_string<Suit>(const Suit& suit)
{
std::string str;
switch(suit)
{
case Suit::None: str = "None"; break;
case Suit::Heart: str = "h"; break;
case Suit::Diamond: str = "d"; break;
case Suit::Spade: str = "s"; break;
case Suit::Club: str = "c"; break;
default: break;
}
return str;
}
class Card
{
public:
constexpr Card() = default;
constexpr Card(Value value, Suit suit) : m_value(value), m_suit(suit) {}
Value value() const noexcept { return m_value; }
Suit suit() const noexcept { return m_suit; }
Card& operator++()
{
if(m_value == Value::Ace)
m_suit = static_cast<Suit>((static_cast<int8_t>(m_suit) + 1) % constants::num_suits);
m_value = static_cast<Value>((static_cast<int8_t>(m_value) + 1) % constants::num_values);
return *this;
}
Card operator++(int)
{
Card result(*this);
++(*this);
return result;
}
private:
Value m_value{};
Suit m_suit{};
};
std::ostream& operator<<(std::ostream& os, const Card& card)
{
os << to_string(card.value()) << to_string(card.suit());
return os;
}
class Deck
{
public:
using Type = std::array<Card, constants::num_cards>;
using iterator = Type::iterator;
using const_iterator = Type::const_iterator;
iterator begin() noexcept { return m_deck.begin(); }
const_iterator begin() const noexcept { return m_deck.begin(); }
iterator end() noexcept { return m_deck.end(); }
const_iterator end() const noexcept { return m_deck.end(); }
void init()
{
std::iota(m_deck.begin(), m_deck.end(), Card(Value::Two, Suit::Heart));
}
void randomInit()
{
init();
std::shuffle(m_deck.begin(), m_deck.end(), m_g);
}
private:
Type m_deck;
std::random_device m_rd;
std::mt19937 m_g{m_rd()};
};
std::ostream& operator<<(std::ostream& os, const Deck& deck)
{
for(const auto& card : deck)
os << card << ' ';
return os;
}
int main(int argc, char** argv)
{
Deck deck;
deck.randomInit();
std::cout << deck << '\n';
return 0;
}