Question: *** A4.cxx *************** #include #include #include #include #include #include card.hxx using namespace std; using cards = std::deque ; ostream& operator it(ostream, ); copy(c.begin(), c.end(),

 *** A4.cxx *************** #include #include #include #include #include #include "card.hxx" usingnamespace std; using cards = std::deque; ostream& operator it(ostream, " "); copy(c.begin(),

*** A4.cxx ***************

#include #include #include #include #include

#include "card.hxx"

using namespace std; using cards = std::deque;

ostream& operator it(ostream, " "); copy(c.begin(), c.end(), it); return os;

}

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; }

void shuffle_cards(cards& cs) { random_device rd; mt19937 gen(rd()); shuffle(cs.begin(), cs.end(), gen); }

cards draw(size_t num, cards& desk) { auto pos = desk.begin(); if (num

cards cd(desk.begin(), pos);

desk.erase(desk.begin(), pos);

return cd; }

auto calc_score(cards const& hand)->std::pair<:size_t std::size_t> { size_t low = accumulate(hand.begin(), hand.end(), size_t{}, LOW_SUM_OP); // Add Lambda function here size_t high = accumulate(hand.begin(), hand.end(), size_t{}, HIGH_SUM_OP); return{ low, high }; }

int main() { cards deck = gen_deck_of_cards(); shuffle_cards(deck); cout

auto result = calc_score(hand);

if (get(result) == get(result) ) { cout (result) (result) (result)

*************************************************************************************************************************************************************************************

*************** card.hxx ****************************

#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 (c.face_); break; }

// output suit... switch (c.suit_) { case card::club: os

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

#endif // #ifndef card_hxx_

*************************************************************************************************************************************************************************************

Calculating the Score of a "Hand" C++'s algorithms work on iterators and/or iterator ranges. There are many algorithms in and in C++. Calculating the score of cards in a container amounts to iterating from the beginning to the "end" of the container summing up their score. (NOTE: In this assignment that each card contributes to the score only on its own.) While this can be manually done with a for loop, there is an algorithm, std::accumulate(), capable of "adding" up elements in an iterator range (first,last). The score of a container cards, i.e., a "hand", is to be calculated as follows: . . aces are worth 1 or 11, jacks, queens, and kings are worth 10, card::invalid is worth 0 (obviously and such should never be in a deck or hand), otherwise the card is worth its face value (i.e., 2 to 10). (Some might recognize that these are the values of cards in the game of Blackjack.) Since aces can be worth 1 or 11, in this assignment you are to compute the score: by computing the lowest possible score, by computing the highest possible score, and, returning both from this function. Thus, to calculate the score, you want to return two values from a function. You are not permitted to do this indirectly by passing arguments by reference to the function. Instead you will return the results in a single object from the function. This means your calc_score() function could be prototyped a one of: 1. auto calc score (cards const& cs) -> std::pair<:size_t std::size_t>; or as: 1. auto calc_score (cards const& hand) -> cards; (These prototypes are using C++11's function suffix notation.) Returning cards in a type cards value would work as there can be 0 or more elements in the container -- the caller can check how many results there are. However, in this assignment you will return a std::pair object for these reasons: all of C++'s associative "map" containers store their elements as std::pair where Key and Value are the types of those objects (so it is good to know how to use std::pair), using std::pair demonstrates how to store two values in a single object, and, using std::pair allows one to learn how to access the elements in std::pair. (ASIDE: std::pair is legacy (but will remain in the language) and has been made to be essentially compatible with std::tuple, i.e., a tuple containing two elements of types A and B. Tuples are more general however supporting 0 to N elements of distinct types.) Write the code in calc_score() as follows: 1. size_t low = accumulate(hand.begin(), hand.end(), size_t{}, LOW_SUM_OP); 2. size_t high = accumulate(hand.begin(), hand.end(), size_t{}, HIGH_SUM_OP); 3. return { low, high }; where LOW_SUM_OP and HIGH_SUM_OP are functions, lambda functions, or function objects of your choosing) to calculate the low and high score in a hand respectively. (Try using lambda functions here!) The signature of LOW_SUM_OP and HIGH_SUM_OP are what std::accumulate requires when a binary operator is passed in. The first argument is the current sum, and, the second argument is the next element in the container to add to the current sum. Thus, the return value of both LOW_SUM_OP and HIGH_SUM_OP is the first argument + whatever score the current card is. This also means the first argument will be std::size_t const& and the second argument is card const&. Tip: Check that this function works before continuing further. Calculating the Score of a "Hand" C++'s algorithms work on iterators and/or iterator ranges. There are many algorithms in and in C++. Calculating the score of cards in a container amounts to iterating from the beginning to the "end" of the container summing up their score. (NOTE: In this assignment that each card contributes to the score only on its own.) While this can be manually done with a for loop, there is an algorithm, std::accumulate(), capable of "adding" up elements in an iterator range (first,last). The score of a container cards, i.e., a "hand", is to be calculated as follows: . . aces are worth 1 or 11, jacks, queens, and kings are worth 10, card::invalid is worth 0 (obviously and such should never be in a deck or hand), otherwise the card is worth its face value (i.e., 2 to 10). (Some might recognize that these are the values of cards in the game of Blackjack.) Since aces can be worth 1 or 11, in this assignment you are to compute the score: by computing the lowest possible score, by computing the highest possible score, and, returning both from this function. Thus, to calculate the score, you want to return two values from a function. You are not permitted to do this indirectly by passing arguments by reference to the function. Instead you will return the results in a single object from the function. This means your calc_score() function could be prototyped a one of: 1. auto calc score (cards const& cs) -> std::pair<:size_t std::size_t>; or as: 1. auto calc_score (cards const& hand) -> cards; (These prototypes are using C++11's function suffix notation.) Returning cards in a type cards value would work as there can be 0 or more elements in the container -- the caller can check how many results there are. However, in this assignment you will return a std::pair object for these reasons: all of C++'s associative "map" containers store their elements as std::pair where Key and Value are the types of those objects (so it is good to know how to use std::pair), using std::pair demonstrates how to store two values in a single object, and, using std::pair allows one to learn how to access the elements in std::pair. (ASIDE: std::pair is legacy (but will remain in the language) and has been made to be essentially compatible with std::tuple, i.e., a tuple containing two elements of types A and B. Tuples are more general however supporting 0 to N elements of distinct types.) Write the code in calc_score() as follows: 1. size_t low = accumulate(hand.begin(), hand.end(), size_t{}, LOW_SUM_OP); 2. size_t high = accumulate(hand.begin(), hand.end(), size_t{}, HIGH_SUM_OP); 3. return { low, high }; where LOW_SUM_OP and HIGH_SUM_OP are functions, lambda functions, or function objects of your choosing) to calculate the low and high score in a hand respectively. (Try using lambda functions here!) The signature of LOW_SUM_OP and HIGH_SUM_OP are what std::accumulate requires when a binary operator is passed in. The first argument is the current sum, and, the second argument is the next element in the container to add to the current sum. Thus, the return value of both LOW_SUM_OP and HIGH_SUM_OP is the first argument + whatever score the current card is. This also means the first argument will be std::size_t const& and the second argument is card const&. Tip: Check that this function works before continuing further

Step by Step Solution

There are 3 Steps involved in it

1 Expert Approved Answer
Step: 1 Unlock blur-text-image
Question Has Been Solved by an Expert!

Get step-by-step solutions from verified subject matter experts

Step: 2 Unlock
Step: 3 Unlock

Students Have Also Explored These Related Databases Questions!