Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

*************** Given card.hxx ******************************* #ifndef card_hxx_ #define card_hxx_ //=========================================================================== #include #include #include #include #include //=========================================================================== class card { public: using face_type = char; enum {

image text in transcribedimage text in transcribedimage text in transcribedimage text in transcribedimage text in transcribedimage text in transcribedimage text in transcribedimage text in transcribed

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

#ifndef card_hxx_ #define card_hxx_

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

#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_

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

Assignment 4 Overview There are many card games. Typically each card game starts with a deck of cards, they are randomly shuffled, and then cards are drawn from the deck. Often card games calculate a score based on the cards one has in his/her hand. This assignment explores using C++ to perform some of these operations. Task You task is to use the provided card.hxx (scroll down to closer to the bottom of this page to access such) header file to write code in a a4.cxx (or use a .cpp extension if you prefer) as follows (high-level): 1. Generate a full deck of cards in the container std::deque 2. Randomly shuffle the deck of cards. 3. Draw 3 cards from the deck and store in a hand. 4. Calculate the possible low and high score of the cards in the hand. These steps and what needs to be output are described below. NOTE: Compile your code as C++20 as the header file uses a feature from C++ 20, e.g., 1. | g++-10.2.0 -std=c++20 -Wall -Wextra -Werror -o a4.exe a4.cxx Starting This Assignment You are not permitted to modify card.hxx. Do not copy code from other cards programs in this course --concentrate on writing the code in this assignment in a4.cxx as described below. At the top of your a4.cxx, start by writing the following include directives: 1. 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 (i) the ostream and (ii) a""(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 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. cards gen_deck_of_cards () 2. 3. 4. 5. cards retval; for (card_faces f(card_faces_begin), fEnd; f != [End; ++f) for (card_suits s(card_suits_begin), SEnd; s != SEnd; ++5) retval.push_back(card{*f, *5}); return retval; 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. Randomly Shuffling the Deck of Cards Once one has some cards, the next step would be to randomly shuffle them. The C++ standard defines: std::shuffle in which will randomly shuffle a random-access iterator range (first,last) according to a random number generator, std::random_device in is a special uniformly-distributed integer random number generator that produces non-deterministic numbers using special hardware std::mt19937 in is a Mersenne Twister that generates 32-bit random numbers. 1 It is best to always put "single" operations in their own functions instead of adding a lot of code to one function / main(). thus, start by writing the function to shuffle cards as follows: 1. 2. 3. void shuffle_cards (cards & cs) { } Notice the cards function parameter is passed by reference --you will be modifying the cards passed in (obviously!). :-) To shuffle the cards, there are three steps required: 1. Declare a variable of type std::random_device called rd. 2. Construct a variable of type std:: mt19937 called gen passing in to its constructor rd(). 3. Call std::shuffle passing in cs.begin(), cs.end(), and gen. Random number generation in C++ involves the use of types that behave as function objects, i.e., classes which overload operator(). This is why "rd" has parentheses after it in step 2. Inside the std::shuffle() code, the equivalent of gen() is used to generate the next random number. NOTE: See $17.1: Random Numbers and Distributions in TCPPSL for more detail on C++ random number generation. :-) Tip: It is a good idea before proceeding further to hack a but of code in main() to check if your cards are being properly shuffled. Drawing N Cards From the Deck Given some cards, one may want to request drawing N cards from those cards. In this function, you will draw (i.e., take) at most N cards from the front of the deck, remove those cards from the deck, and return the drawn cards in a cards object. First, start by writing: 1. 2. cards draw(std::size_t num, Cards & deck) { } 3. You are to determine the N cards to draw using iterators. Since it is possible that num > deck.size(), one cannot unconditionally start at the beginning and then ++ five times to get the five cards --the deck might not have enough (or any!) cards. Instead these are the steps you want to perform: 1. In a single line of code, declare a variable called pos with its constructed value set to the result of deck.begin(). (Tip: Use auto to declare this variable.) 2. If num 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: O 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&. 1 Tip: Check that this function works before continuing further. Writing main() Your main() function should now be easy to write if you wrote test code for the above! The code in main() is to do the following in the order listed: 1. In a single line of code, construct a local variable called deck of type cards passing the result of gen_deck_of_cards() to it. 2. In a single line of code, call shuffle_cards() using deck from step 1. 3. Output "Deck: " followed by all cards in deck (each card is separated by a space) followed by a newline char. 4. Output an empty line. 5. Output "Drawing 3 cards... ". 6. In a single line of code, construct a local variable called hand passing the result of draw(3,deck) to it. 7. Output "Deck: " followed by all cards currently in deck (each card is separated by a space) followed by a newline char. 8. Output "Hand: " followed by all cards in hand (each card is separated by a space) followed by a newline char. 9. In a single line of code, construct a local variable with the result returned by calc_score(hand). 10. If the first and second score results are the same, then output "Score: " followed by the score and then a newline char. 11. Otherwise output "Possible Score: " followed by the low and high scores and then a newline char. Tip Don't write the entire program before you test things! Instead write smaller chunks of code that are made of short functions (say 3 to 10 lines long) and check that each function is correct. This will make it a lot easier to write correct code that uses those functions --in any programming language! :-) Sample Program Runs Since the program output is random, you will need to run your program multiple times to see the one and two score output variants. Here are two sample runs: 1. 2. $ ./a4.exe Deck: QH 1C 4D JS 8D 8C 1S JD 7D KD 5H QC 4H KC AS 8S 3S 3H 5S AC 7C 8H 6D 2C AD 9S KH 6C 2D 4C KS 9C QS 3D 2S 5D 3C 5C AH 7H 9D 9H QD JC 4S 78 6S JH 6H 1H 1D 2H 3. 5. 6. Drawing 3 cards... Deck: JS 8D 8C 1S JD 7D KD 5H QC 4H KC AS 8S 3S 3H 5S AC 7C 8H 6D 2C AD 9S KH 6C 2D 4C KS 90 QS 3D 2S 5D 3C 5C AH 7H 9D 9H QD JC 4S 7S 6S JH 6H 1H 1D 2H Hand: QH 1C 4D Score: 24 $ ./a4.exe Deck: 7D 8S AH 1S 9H 9S JS 5D KC 4D QS JH 5C AC 6D QH 3S 6S QD 1H JD 6C 1D 9C 7H 4C KD 5S 8H 8D AS 1C 8C KS 7C 2D 2S AD 3C 4H QC 5H 4S 3D KH 7S 2C 9D 2H 3H JC 6H 7. 8. 9 10. 11. 12. Drawing 3 cards... Deck: 1S 9H 9S JS 5D KC 4D QS JH 5C AC 6D QH 3S 6S QD 1H JD 6C 1D 9C 7H 4C KD 5S 8H 8D AS 1C 8C KS 7C 2D 2S AD 3C 4H QC 5H 4S 3D KH 7S 2C 9D 2H 3H JC 6H Hand: 7D 8S AH Possible Score: 16 26 $ 13. 14. 15. Submission When submitting your assignment only submit your .cxx / .cpp file, i.e., --do not submit the card.hxx file. :-) card.hxx 7 February 2021, 12:54 PM Assignment 4 Overview There are many card games. Typically each card game starts with a deck of cards, they are randomly shuffled, and then cards are drawn from the deck. Often card games calculate a score based on the cards one has in his/her hand. This assignment explores using C++ to perform some of these operations. Task You task is to use the provided card.hxx (scroll down to closer to the bottom of this page to access such) header file to write code in a a4.cxx (or use a .cpp extension if you prefer) as follows (high-level): 1. Generate a full deck of cards in the container std::deque 2. Randomly shuffle the deck of cards. 3. Draw 3 cards from the deck and store in a hand. 4. Calculate the possible low and high score of the cards in the hand. These steps and what needs to be output are described below. NOTE: Compile your code as C++20 as the header file uses a feature from C++ 20, e.g., 1. | g++-10.2.0 -std=c++20 -Wall -Wextra -Werror -o a4.exe a4.cxx Starting This Assignment You are not permitted to modify card.hxx. Do not copy code from other cards programs in this course --concentrate on writing the code in this assignment in a4.cxx as described below. At the top of your a4.cxx, start by writing the following include directives: 1. 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 (i) the ostream and (ii) a""(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 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. cards gen_deck_of_cards () 2. 3. 4. 5. cards retval; for (card_faces f(card_faces_begin), fEnd; f != [End; ++f) for (card_suits s(card_suits_begin), SEnd; s != SEnd; ++5) retval.push_back(card{*f, *5}); return retval; 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. Randomly Shuffling the Deck of Cards Once one has some cards, the next step would be to randomly shuffle them. The C++ standard defines: std::shuffle in which will randomly shuffle a random-access iterator range (first,last) according to a random number generator, std::random_device in is a special uniformly-distributed integer random number generator that produces non-deterministic numbers using special hardware std::mt19937 in is a Mersenne Twister that generates 32-bit random numbers. 1 It is best to always put "single" operations in their own functions instead of adding a lot of code to one function / main(). thus, start by writing the function to shuffle cards as follows: 1. 2. 3. void shuffle_cards (cards & cs) { } Notice the cards function parameter is passed by reference --you will be modifying the cards passed in (obviously!). :-) To shuffle the cards, there are three steps required: 1. Declare a variable of type std::random_device called rd. 2. Construct a variable of type std:: mt19937 called gen passing in to its constructor rd(). 3. Call std::shuffle passing in cs.begin(), cs.end(), and gen. Random number generation in C++ involves the use of types that behave as function objects, i.e., classes which overload operator(). This is why "rd" has parentheses after it in step 2. Inside the std::shuffle() code, the equivalent of gen() is used to generate the next random number. NOTE: See $17.1: Random Numbers and Distributions in TCPPSL for more detail on C++ random number generation. :-) Tip: It is a good idea before proceeding further to hack a but of code in main() to check if your cards are being properly shuffled. Drawing N Cards From the Deck Given some cards, one may want to request drawing N cards from those cards. In this function, you will draw (i.e., take) at most N cards from the front of the deck, remove those cards from the deck, and return the drawn cards in a cards object. First, start by writing: 1. 2. cards draw(std::size_t num, Cards & deck) { } 3. You are to determine the N cards to draw using iterators. Since it is possible that num > deck.size(), one cannot unconditionally start at the beginning and then ++ five times to get the five cards --the deck might not have enough (or any!) cards. Instead these are the steps you want to perform: 1. In a single line of code, declare a variable called pos with its constructed value set to the result of deck.begin(). (Tip: Use auto to declare this variable.) 2. If num 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: O 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&. 1 Tip: Check that this function works before continuing further. Writing main() Your main() function should now be easy to write if you wrote test code for the above! The code in main() is to do the following in the order listed: 1. In a single line of code, construct a local variable called deck of type cards passing the result of gen_deck_of_cards() to it. 2. In a single line of code, call shuffle_cards() using deck from step 1. 3. Output "Deck: " followed by all cards in deck (each card is separated by a space) followed by a newline char. 4. Output an empty line. 5. Output "Drawing 3 cards... ". 6. In a single line of code, construct a local variable called hand passing the result of draw(3,deck) to it. 7. Output "Deck: " followed by all cards currently in deck (each card is separated by a space) followed by a newline char. 8. Output "Hand: " followed by all cards in hand (each card is separated by a space) followed by a newline char. 9. In a single line of code, construct a local variable with the result returned by calc_score(hand). 10. If the first and second score results are the same, then output "Score: " followed by the score and then a newline char. 11. Otherwise output "Possible Score: " followed by the low and high scores and then a newline char. Tip Don't write the entire program before you test things! Instead write smaller chunks of code that are made of short functions (say 3 to 10 lines long) and check that each function is correct. This will make it a lot easier to write correct code that uses those functions --in any programming language! :-) Sample Program Runs Since the program output is random, you will need to run your program multiple times to see the one and two score output variants. Here are two sample runs: 1. 2. $ ./a4.exe Deck: QH 1C 4D JS 8D 8C 1S JD 7D KD 5H QC 4H KC AS 8S 3S 3H 5S AC 7C 8H 6D 2C AD 9S KH 6C 2D 4C KS 9C QS 3D 2S 5D 3C 5C AH 7H 9D 9H QD JC 4S 78 6S JH 6H 1H 1D 2H 3. 5. 6. Drawing 3 cards... Deck: JS 8D 8C 1S JD 7D KD 5H QC 4H KC AS 8S 3S 3H 5S AC 7C 8H 6D 2C AD 9S KH 6C 2D 4C KS 90 QS 3D 2S 5D 3C 5C AH 7H 9D 9H QD JC 4S 7S 6S JH 6H 1H 1D 2H Hand: QH 1C 4D Score: 24 $ ./a4.exe Deck: 7D 8S AH 1S 9H 9S JS 5D KC 4D QS JH 5C AC 6D QH 3S 6S QD 1H JD 6C 1D 9C 7H 4C KD 5S 8H 8D AS 1C 8C KS 7C 2D 2S AD 3C 4H QC 5H 4S 3D KH 7S 2C 9D 2H 3H JC 6H 7. 8. 9 10. 11. 12. Drawing 3 cards... Deck: 1S 9H 9S JS 5D KC 4D QS JH 5C AC 6D QH 3S 6S QD 1H JD 6C 1D 9C 7H 4C KD 5S 8H 8D AS 1C 8C KS 7C 2D 2S AD 3C 4H QC 5H 4S 3D KH 7S 2C 9D 2H 3H JC 6H Hand: 7D 8S AH Possible Score: 16 26 $ 13. 14. 15. Submission When submitting your assignment only submit your .cxx / .cpp file, i.e., --do not submit the card.hxx file. :-) card.hxx 7 February 2021, 12:54 PM

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

Students also viewed these Databases questions