Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

C++ card.hxx code: #ifndef card_hxx_ #define card_hxx_ //=========================================================================== #include #include #include #include #include #include #include //=========================================================================== class card { public: using face_type = char; enum

C++

image text in transcribed

image text in transcribed

card.hxx code:

#ifndef card_hxx_

#define card_hxx_

//===========================================================================

#include

#include

#include

#include

#include

#include

#include

//===========================================================================

class card

{

public:

using face_type = char;

enum { invalid=0, ace=1, jack=11, queen=12, king=13 };

enum suit_type : char { club, spade, diamond, heart };

private:

face_type face_;

suit_type suit_;

public:

// default construct invalid card value when face_ == 0...

constexpr card() : face_{} { };

constexpr card(card const&) = default;

constexpr card(card&&) = default;

constexpr card& operator =(card const&) = default;

constexpr card& operator =(card&&) = default;

constexpr card(face_type const& f, suit_type const& s) :

face_{f},

suit_{s}

{

if (!valid())

throw std::domain_error("Invalid card.");

}

constexpr auto operator (card const&) const noexcept = default;

constexpr operator bool() const noexcept

{

return valid();

}

constexpr bool valid() const noexcept

{

return face_

}

constexpr face_type face() const noexcept { return face_; }

constexpr suit_type suit() const noexcept { return suit_; }

constexpr void invalidate() noexcept

{

face_ = invalid;

}

constexpr void set(face_type const& f, suit_type const& s)

{

card tmp(f,s);

swap(tmp);

}

constexpr void swap(card& b) noexcept

{

using std::swap;

swap(face_, b.face_);

swap(suit_, b.suit_);

}

friend std::istream& operator >>(std::istream&, card&);

friend std::ostream& operator

};

inline constexpr auto operator (

card::suit_type const& a,

card::suit_type const& b

) noexcept

{

return

static_cast<:underlying_type_t>>(a)

static_cast<:underlying_type_t>>(b)

;

}

inline constexpr void swap(card& a, card& b) noexcept

{

a.swap(b);

}

//===========================================================================

struct card_faces_begin_t final { };

constexpr card_faces_begin_t card_faces_begin{};

class card_faces

{

private:

card::face_type face_;

public:

constexpr card_faces(card_faces_begin_t const&) noexcept :

face_{card::ace}

{

}

constexpr card_faces(card::face_type const& f = card::king+1) :

face_{f}

{

}

constexpr card_faces(card_faces const&)

noexcept = default;

constexpr card_faces& operator =(

card_faces const&) noexcept = default;

constexpr bool operator ==(card_faces const& b) const

noexcept = default;

constexpr card::face_type const& operator *() const noexcept

{

return face_;

}

// prefix ++

constexpr card_faces& operator ++() noexcept

{

++face_;

return *this;

}

// postfix ++

constexpr card_faces operator ++(int) noexcept

{

card_faces retval(*this);

this->operator ++();

return retval;

}

};

//===========================================================================

struct card_suits_begin_t final { };

constexpr card_suits_begin_t card_suits_begin{};

class card_suits

{

private:

std::optional<:suit_type> suit_;

public:

// default constructor constructs invalid suit...

constexpr card_suits() noexcept :

suit_{}

{

}

constexpr card_suits(card_suits_begin_t const&) noexcept :

suit_{card::club}

{

}

constexpr card_suits(card::suit_type const& s) :

suit_{s}

{

}

constexpr card_suits(card_suits const&) noexcept = default;

constexpr card_suits& operator =(card_suits const&) noexcept = default;

constexpr bool operator ==(card_suits const& b) const

noexcept = default;

constexpr card::suit_type const& operator *() const noexcept

{

return *suit_;

}

// prefix ++

constexpr card_suits& operator ++() noexcept

{

if (suit_)

{

switch (*suit_)

{

case card::club: suit_ = card::spade; break;

case card::spade: suit_ = card::diamond; break;

case card::diamond: suit_ = card::heart; break;

default:

case card::heart: suit_.reset(); break;

}

}

return *this;

}

// postfix ++

constexpr card_suits operator ++(int) noexcept

{

card_suits retval(*this);

this->operator ++();

return retval;

}

};

//===========================================================================

//

// For I/O purposes:

// * a "0" face is an invalid card.

// * a "1" face is a 10.

// * a "A", "J", "Q", or "K" face is the same.

// * otherwise the face is a number between 2 and 9.

// * the suit is one of "H", "D", "C", or "S" representing

// hearts, diamonds, clubs, and spades respectively

// * when read in, the suit or face can be in lower case

// * when written out, the suit or face will always be upper case

//

inline std::istream& operator >>(std::istream& is, card& c)

{

std::istream::sentry s(is);

if (s)

{

// read in card "number"...

char ch;

if (is >> ch) // this can skip whitespace

{

switch (ch)

{

case '0': c.face_ = card::invalid; break;

case 'a':

case 'A': c.face_ = card::ace; break;

case '2': c.face_ = 2; break;

case '3': c.face_ = 3; break;

case '4': c.face_ = 4; break;

case '5': c.face_ = 5; break;

case '6': c.face_ = 6; break;

case '7': c.face_ = 7; break;

case '8': c.face_ = 8; break;

case '9': c.face_ = 9; break;

case '1': c.face_ = 10; break;

case 'j':

case 'J': c.face_ = card::jack; break;

case 'q':

case 'Q': c.face_ = card::queen; break;

case 'k':

case 'K': c.face_ = card::king; break;

default:

is.setstate(std::ios::failbit);

is.unget();

return is;

}

}

// read in card suit...

auto ch2 = is.get();

// i.e., unformatted call to get char so no whitespace is skipped

if (ch2 == std::istream::traits_type::eof())

{

// NOTE: unformatted calls return traits_type::eof() to indicate

// an error. This is like checking for a EOF or -1 error when

// doing file I/O in C.

is.setstate(std::ios::badbit);

return is;

}

switch (static_cast(ch2)) // all is okay... cast to char

{

case 'C': c.suit_ = card::club; break;

case 'S': c.suit_ = card::spade; break;

case 'H': c.suit_ = card::heart; break;

case 'D': c.suit_ = card::diamond; break;

default:

is.setstate(std::ios::badbit); // invalid suit

break;

}

}

return is;

}

inline std::ostream& operator

{

std::ostream::sentry s(os);

if (s)

{

// output number/face...

switch (c.face_)

{

case card::invalid: os

case card::ace: os

case card::jack: os

case card::queen: os

case card::king: os

case 10: os

default: os (c.face_); break;

}

// output suit...

switch (c.suit_)

{

case card::club: os

case card::spade: os

case card::diamond: os

case card::heart: os

}

}

return os;

}

//===========================================================================

#endif // #ifndef card_hxx_

At the top of your a4.cxx, start by writing the following include directives: 1. GE 2 3. #include #include #include #include #include 4. 5. 7. #include "card. hxx" Note, by convention, include files enclosed within are searched for in the compiler's "include" search paths and files enclosed within double quotation marks are searched for relative to the current directory. Although using such won't be leveraged in this assignment, you are to store the deck of cards as well as a "hand" in double-ended queues, i.e., in std::deque variables. Rather than writing std::deque each time you want to say "cards", define a type alias called "cards" that is a synonym for std::deque as follows: 1. using cards = std::deque; (Type aliases and typedefs are the same: both define a name as a synonym for another type. Unlike typedef, however, type aliases (i) can be templated and (ii) are easier to read and write due to their assignment-like syntax.) Outputting cards to std::ostream Given previous assignments and the lectures, by now you should be good at writing std::ostream operator whose constructor arguments are, the ostream and (ii) "" (i.e., a space). Remember to return the std::ostream parameter at the end of the function. While one can use loops, etc. to process each element of a container, simpler code (without any loss of efficiency) can be written by calling the appropriate algorithms. Clearly it is easier to understand and maintain one line of code (i.e., the std::copy() call is one line of code) than multiple lines with variables, test conditions, etc. Generating the Deck of Cards In card.hxx, there are two special classes provided called card_faces and card_suits. The purposes of these classes are to provide an easy way to iterate through all possible card faces and all possible card suits. These two classes are very similar to iterators but since understanding such syntax and operator overloads are new to you, the code for generating a deck of cards is given: 1. 2. 3 cards gen_deck_of_cards () { cards retval; for (card_faces f(card_faces_begin), fEnd; f != fEnd; ++f) for (card_suits s (card_suits_begin), sEnd; s != sEnd; ++s) retval.push_back (card( *f, *s}); return retval; } 5. 6 7. 8. (Place this code in your a4.cxx file.) NOTE: While one could have written the for loops to directly use the "face" values, this would have required hard-coding values in the for loop. Since the suit values are part of an enumeration, the for loop code to loop through all possible suits would have been more complicated. By defining two special "iterator-styled" classes, one can easily obtain all possible values of faces and suits in a way that results is clean, easy-to- understand-and-maintain code. Tip: It is a good idea before proceeding further to add a main(), call this function, and output the cards to verify things are working. At the top of your a4.cxx, start by writing the following include directives: 1. GE 2 3. #include #include #include #include #include 4. 5. 7. #include "card. hxx" Note, by convention, include files enclosed within are searched for in the compiler's "include" search paths and files enclosed within double quotation marks are searched for relative to the current directory. Although using such won't be leveraged in this assignment, you are to store the deck of cards as well as a "hand" in double-ended queues, i.e., in std::deque variables. Rather than writing std::deque each time you want to say "cards", define a type alias called "cards" that is a synonym for std::deque as follows: 1. using cards = std::deque; (Type aliases and typedefs are the same: both define a name as a synonym for another type. Unlike typedef, however, type aliases (i) can be templated and (ii) are easier to read and write due to their assignment-like syntax.) Outputting cards to std::ostream Given previous assignments and the lectures, by now you should be good at writing std::ostream operator whose constructor arguments are, the ostream and (ii) "" (i.e., a space). Remember to return the std::ostream parameter at the end of the function. While one can use loops, etc. to process each element of a container, simpler code (without any loss of efficiency) can be written by calling the appropriate algorithms. Clearly it is easier to understand and maintain one line of code (i.e., the std::copy() call is one line of code) than multiple lines with variables, test conditions, etc. Generating the Deck of Cards In card.hxx, there are two special classes provided called card_faces and card_suits. The purposes of these classes are to provide an easy way to iterate through all possible card faces and all possible card suits. These two classes are very similar to iterators but since understanding such syntax and operator overloads are new to you, the code for generating a deck of cards is given: 1. 2. 3 cards gen_deck_of_cards () { cards retval; for (card_faces f(card_faces_begin), fEnd; f != fEnd; ++f) for (card_suits s (card_suits_begin), sEnd; s != sEnd; ++s) retval.push_back (card( *f, *s}); return retval; } 5. 6 7. 8. (Place this code in your a4.cxx file.) NOTE: While one could have written the for loops to directly use the "face" values, this would have required hard-coding values in the for loop. Since the suit values are part of an enumeration, the for loop code to loop through all possible suits would have been more complicated. By defining two special "iterator-styled" classes, one can easily obtain all possible values of faces and suits in a way that results is clean, easy-to- understand-and-maintain code. Tip: It is a good idea before proceeding further to add a main(), call this function, and output the cards to verify things are working

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

MongoDB Applied Design Patterns Practical Use Cases With The Leading NoSQL Database

Authors: Rick Copeland

1st Edition

1449340040, 978-1449340049

More Books

Students also viewed these Databases questions

Question

What are Decision Trees?

Answered: 1 week ago

Question

What is meant by the Term Glass Ceiling?

Answered: 1 week ago