To do this, you will implement basic abstractions in C++ for decks and cards in two games that have different rules for the ranks, multiplicity, and ordering relations of the cards that constitute a standard deck used in each game. Specifically, you will use procedural, functional, object-oriented, and generic programming paradigms in the C++ language and libraries (as of the C++17 standard) to provide common abstractions and game-specific ones, for both (Partnership Auction) Pinochle and (Texas hold 'em) Poker.
You will then write a simple C++ program that constructs decks of cards for each of those games, and prints out the contents of the deck for each game so that you can can check easily that everything worked correctly.
In subsequent lab assignments you will use these abstractions to implement game-specific features like generating sets of cards, examining different combinations of the cards in a set, and ordering cards and different combinations of cards, according to various scoring functions. As you develop your code, please use good modularity: for example, if a function's logic has several separable parts (or is long enough to fill the editor's window) you may want to break it up into other smaller functions.
Note: even at this early stage some details of the assignment are intentionally slightly under-specified, leaving you some room to choose what you think is the best way to implement them, as long as what you do is reasonable and you explain your design decisions in comments in the code and in your readme file.
qlogin
, and (as you did in Studio 0)
confirm that the correct version (8.3.0
) of the g++
compiler is installed in your environment there.
cd
into it.
readme.txt
),
in which you will record your observations, design decisions, and other information
pertaining to the lab assignment as you develop your solution.
Makefile
into
that directory - you will use it to build your code into an executable program.
Note that the provided Makefile
assumes specific names for
all the files that you will develop as part of your solution, so you may want to
change those names, and (in the interest of working incrementally) you also may
want to comment out some of the details in it initally,
and then add them back in as you go.
.h
) file and a new C++ source
(.cpp
) file to your lab directory. These will hold declarations and
definitions (respectively) related to (1) the suits that cards may have in Pinochle
or in Texas hold 'em poker, and to (2) operators involving those suits.
In the header file, declare an enumerated type for the different suits a
playing card may have:
clubs
,
diamonds
, hearts
, and spades
.
Note that using an
enum class
style declaration and giving the enumerated type a
distinct name (like Suit
for example) can be helpful for
readability because scoping is explicit.
The values of the enumeration labels should be monotonically increasing (e.g.,
clubs
should have the lowest value, diamonds
should
have a value that is greater, and so forth) which is what you get if you simply
declare the enumaration labels in that order. Also add a highest-valued label
to the enumeration, for an undefined
suit, which will be useful
for the purpose of iteration over those values (and also presumably could
be useful for additional games in which some cards, like jokers, may not have
a suit).
In that same header and source file, declare and define (respectively) a "shift"
operator (operator<<
) that takes a reference to an
ostream
and a const
reference to a variable of
that enumerated type, and returns a reference to an ostream
. That
shift operator should insert a string corresponding to the suit ("C"
for clubs
, "D"
for diamonds
,
"H"
for hearts
, "S"
spades
,
or "?"
for undefined
) into the ostream
and then return a reference to that same ostream
.
In that same header and source file, also declare and define (respectively) a
prefix increment operator (operator++
) that takes a reference to a
variable of that same enumerated type, increments the variable's value to the
next one (unless its value is already undefined
in which case it
should remain the same) and then returns a reference to that variable.
.h
) file and a new C++
source (.cpp
) file to your lab directory and in them
declare and define (respectively) a struct template to represent a
"playing card" type (e.g., named Card
) that is parameterized by
two other types (e.g., rank and suit enumerations) and has member
variables of those types (for the card's rank and suit).
Please make sure that (1) at the bottom of the header
(.h
) file for the Card
struct template (within an
inclusion guard that begins with
#ifdef TEMPLATE_HEADERS_INCLUDE_SOURCE
and ends with
#endif
)
it includes the source (.cpp
) file for the Card
struct template, (2) that your Makefile
provides the
-DTEMPLATE_HEADERS_INCLUDE_SOURCE
flag to g++
The Card
struct template should have a public constructor that
takes arguments of the parameterized types for the rank and suit,
and (in the type parameterized template definition of that
constructor) uses them to initialize the member variables.
In those same header and source files, but outside of the
template declarations and definitions for the Card struct itself,
declare and define (respectively)
a template for a "shift" operator (operator<<
) that
(like the struct template) is parameterized with types for a card's rank
and suit. That operator should take a reference to an
ostream
and a const
reference to a variable of
the card type (parameterized with the rank and suit types), and return a
reference to an ostream
. That shift operator should simply insert
the card's rank and suit member variables into the ostream
, and
then return a reference to that same ostream
.
Note that each template declaration or template definition in these
files will begin with a line that looks like
which is then
followed immediately by the rest of the template declaration or template
definition.template <typename R, typename S>
.h
) file to your lab directory and in
it declare an abstract base class for a deck of cards (e.g., named
Deck
) that has a single public pure virtual print
method that takes a reference to an ostream
and has a
void
return type. Note that in this lab we will use a mainly
object-oriented approach for the classes derived from this abstract
base class, at a cost of some code duplication. In future labs we will
combine this approach with generic programmign techniques to refactor
and combine common code that differs mainly in its types, into parameterized
templates.
.h
) file
and a new C++ source (.cpp
) file to your lab directory
and in them declare and define (respectively) (1) an enumerated type for
the card ranks used in Pinochle, and operators involving that
enumerated type; and (2) a class derived (via public inheritance) from the
abstract base class described above, which implements a Pinochle deck.
Like the enumerated type for cards' suits, the enumerated type for
the different ranks a Pinochle card may have should again have
monotonically increasing values in the following order:
nine
, jack
, queen
, king
,
ten
, and ace
. Again also add a highest-valued label
to the enumeration, for an undefined
rank, for the purpose of
iteration over those values.
Note that using an enum class
style declaration and giving
the enumerated type a distinct name (like PinochleRank
for example)
can be helpful for both (1) readability and (2) disambiguating labels for
ranks that appear in both Pinochle and Texas hold 'em poker, because scoping
is explicit.
In that same header and source file, declare and define (respectively) a "shift"
operator (operator<<
) that takes a reference to an
ostream
and a const
reference to a variable of
that enumerated type, and returns a reference to an ostream
. That
shift operator should insert a string corresponding to the rank ("9"
for nine
, "J"
for jack
, "Q"
for
queen
, "K"
king
, "10"
for
ten
, "A"
for ace
, or "?"
for
undefined
) into the ostream
and then return a reference
to that same ostream
.
In that same header and source file, also declare and define (respectively) a
prefix increment operator (operator++
) that takes a reference to a
variable of that same enumerated type, increments the variable's value to the
next one (unless its value is already undefined
in which case it
should remain the same) and then returns a reference to that variable.
The derived class for the Pinochle deck should have (1) a private member variable
that is a vector
sequence container for cards parameterized with
the rank enumeration for Pinochle and the suit enumeration; (2) a public default
constructor that twice pushes back a card of each valid
suit of each valid rank (using the appropriate prefix increment operator to
traverse the values of the enumeration types but not inserting cards with
undefined rank or suit); and (3)
a public print
method that overloads the inherited pure virtual method,
taking a reference to an ostream and inserting each card in its vector
into the ostream, with spaces between the cards and line breaks at appropriate
intervals (how you design that is up to you, based largely on how you nest the
iterations - please document your design decisions for those in your readme file).
Note that when working with templates, using enough whitespace
(and especially putting whitespace between distinct types and the symbols
that surround them where necessary) is often essential in order for your code
to compile. For example, vector< Foo<T> >::iterator
may compile just fine as long as the appropriate header files are included,
while vector<Foo<T>>::iterator
may not compile because
the compiler sees >>
as a shift operator.
.h
) file
and a new C++ source (.cpp
) file to your lab directory
and in them declare and define (respectively) (1) an enumerated type for
the card ranks used in Texas hold 'em poker, and operators involving that
enumerated type; and (2) a class derived (via public inheritance) from the
abstract base class described above, which implements a standard Texas hold
'em poker deck.
The enumerated type for the different ranks of Texas hold 'em poker cards
should have monotonically increasing values in the following order:
two
, three
, four
, five
,
six
, seven
, eight
, nine
,
ten
, jack
, queen
, king
,
and ace
. Again also add a highest-valued label
to the enumeration, for an undefined
rank, for the purpose of
iteration over those values.
Note that using an enum class
style declaration and giving
the enumerated type a distinct name (like HoldEmRank
for example)
can be helpful for both (1) readability and (2) disambiguating labels for
ranks that appear in both Pinochle and Texas hold 'em poker, because scoping
is explicit.
In that same header and source file, declare and define (respectively) a "shift"
operator (operator<<
) that takes a reference to an
ostream
and a const
reference to a variable of
that enumerated type, and returns a reference to an ostream
. That
shift operator should insert a string corresponding to the rank ("2"
for
two
, "3"
for three
,"4"
for
four
, "5"
for five
, "6"
for
six
, "7"
for seven
, "8"
for
eight
, "9"
for nine
, "10"
for
ten
,"J"
for jack
, "Q"
for
queen
, "K"
king
, "A"
for
ace
, or "?"
for undefined
) into the
ostream
and then return a reference to that same ostream
.
In that same header and source file, also declare and define (respectively) a
prefix increment operator (operator++
) that takes a reference to a
variable of that same enumerated type, increments the variable's value to the
next one (unless its value is already undefined
in which case it
should remain the same) and then returns a reference to that variable.
The derived class for the Texas hold 'em poker deck should have (1) a private member
variable that is a vector
sequence container for cards parameterized with
the rank enumeration for Texas hold 'em poker and the suit enumeration; (2) a public
default constructor that (only once) pushes back a card of each valid
suit of each valid rank (using the appropriate prefix increment operator to
traverse the values of the enumeration types but not inserting cards with
undefined rank or suit); and (3)
a public print
method that overloads the inherited pure virtual method,
taking a reference to an ostream and inserting each card in its vector
into the ostream, with spaces between the cards and line breaks at appropriate
intervals (how you design that is up to you, based largely on how you nest the
iterations - please document your design decisions for those in your readme file).
.cpp
) file to your lab directory
and in it define the progam's main
function. That function should
simply declare stack variables of the Pinochle and Texas hold 'em deck types,
and pass the standard output stream (cout
) into a call to each
one's print
method (to show the cards that were put into them
by their default constructors), and then return a zero value to indicate successful
completion.
make
command to compile your
code using the Makefile
, and fix any errors or warnings that occur.
Please be sure to note the different kinds of errors or warnings you ran into
(though you don't have to list every instance of each kind) in your readme file.
If you were fortunate enough not to run into any errors or warnings,
please note that instead, where you would have listed errors or warnings in your
readme file.
Makefile
,
as well as those to your source and header files, before uploading your solution.
Makefile
you used to compile
your solution; and (3) all your header and source files for your solution.