CS 340 - Software Design

Machine Problem 2, Fall 2001

Gin Rummy

Due: Thursday, September 20, 2001 at 11:59 pm

For this program, you will write a program that will allow the user to play the game of Gin Rummy against a computer opponent. We will use the rules as written in this link as the official rules to be followed with one expection. The expection will be that we will use the variation to starting the game (i.e. the first card drawn) as described in the first paragraph of the variations section instead of what is described in the last paragraph in the Play section. This change should allow for simpler agorithms to be used.

In this program, you must use multiple source code files and you may not use a C style struct in your code. A good way to divide your program into multiple source code files is according to the logical use of the code. One way to divide the code for this program could be into three source code files. The first source code file could contain the main() function and all functions relating to input and output (i.e. the user commands). The second source code file could contain the code for keeping track of the cards, sets and hands used by the players. The third source code file could contain the code to evalaute the hands, determine the scoring and the algorithm used by the computer player to decide what it should do. With regard to the restriction on C style stucts, the following C++ class is acceptable, even though it is semantically the same as a C style struct:

     class MyClass
       {
        public:
          //  list of all needed fields

       };

In playing gin rummy, there are multiple parts. The first part is the game. The second part is the hand. One or more hands make up a game. The third part is the turn. One or more turns make up a hand. These three parts will of concern in our program. Addition parts in gin rummy consist of tournaments, which is made up of one or more games, will not be a part of this program.

Your program will have three different set of user commands. One set of commands that are valid between the playing of the hands in a game (inter-hand commands) and other sets of commands that are valid during the playing of the hands (intra-hand commands). One set of these intra-hand commands will deal with commands used when drawing a card during a turn. The other set of these intra-hand commands will deal with the commands used when discarding a card during a turn. Note that the three sets of commands are not disjoint sets, about 75% of the intra-hand commands will be in both sets. Your program must prompt for the user commands and the prompt must include something that informs the user which set of commands are currently valid. All commands will be the first non-white space character on a line and can be given in either upper or lower case. If an unrecognized command is given or a command that is not properly formatted, an error message must be printed and the command is ignored and your program is to prompt for the next command.

The following commands are available at all times in the program. These commands belong to all three sets of commands.

Q
Quit the program. If you are in the middle of a hand or a game, prompt the user with this information and have them comfirm whether they still wish to quit.
H
Display help about the program. This help should include information about the three sets of commands and which set is the current set of commands.
P
Display points scored by each player. Refer to the scoring section to determine the points scored. This command should list the total points for each player and the number of points needed to win the game. Note that gin rummy has a wierd scoring technique that awards a 20 point bonus for each hand won, but these bonus points do not count toward the winning of the game. Thus the game can be won by the player who does not have the most points.
The following commands are only valid in between hands being played. These are the inter-hand commands.
S
Start a new game This command resets all of the scoring information to zero and randomly determines which player will deal first. When the program initially starts, this should be automatically done by the program without having to enter the S command. This commands allows more hands to be played after a game has been won where the points are added to the existing points of the already finished game. This is useful it a player decides to play to some other point value other than 100.
D
Deal a new hand This command starts a new hand and initial deals out the cards. This program is to use the variation in dealing as stated in the first paragraph in the variations section. So the dealer is to deal 11 cards to the non-dealer and the non-dealer just has to discard (or knock). The dealer is randomly determined for the first hand in a game (see the S command) and alternates during the game. After this command the intra-hand set of commands are used until a player knocks or the stock pile is reduced to two cards.
The following commands are valid at any time during intra-hand play.
C
List the user's cards. The cards are to be listed using a two character sequence for each card. The first character is to specify the rank of the card and the second character is to specify the suit. The ranks and suits with the associated characters are given in the table below. Use upper case letters when specifying cards.
Rank Characters Suit Characters
  • A - Ace
  • 2 - Two
  • 3 - Three
  • 4 - Four
  • 5 - Five
  • 6 - Six
  • 7 - Seven
  • 8 - Eight
  • 9 - Nine
  • T - Ten
  • J - Jack
  • Q - Queen
  • K - King
  • C - Clubs
  • D - Diamonds
  • H - Hearts
  • S - Spades
Note that the ranks and suits are listed in order with Ace being the low rank, King being the high rank, Clubs being the low suit and Spades being the high suit.

The cards are to be listed by default in suit-major/rank-minor sorted order from lowest to highest. This means that all clubs are list first, then all diamonds, then all hearts and finally all spades. Each suit is to have its cards listed in rank order with the ace first and the king last. The cards can be arranged by the user into sets using the O and A commands (see below). In this case, list the sets in order indicated by the user with the cards in each set being listed in suit-major/rank-minor order.

When the cards are listed there may be either 10 or 11 cards. There will be 11 cards if the player has drawn a card during a turn but not yet discarded a card. As the cards are listed, each cards is associated with a number (from 1 to 10 or from 1 to 11 depending on the number of cards currently being held by the player) and a letter (from a to z). The number is used to sequentially number the cards as they are listed. The first card list will have number 1, the second card listed will have number 2, etc. This number is used specify individual cards for other commands. The letters are used to specify sets of cards as described in the Object of the Game section. The cards with the lowest set letter are listed first, followed in order by the next lowest set letter. The default ordering assumes that all cards are in the same "set" with the set letter of a.

E
Peek at the Computer Player's Hand This command is to display the computer players cards according to the same rules as described in the C command.

This command is used to debug your program and allow the TA to check if your algorithm for the computer player is functioning correctly. The algorithm for the computer player is as follows. The algorithm breaks down the cards into five categories:

  1. Complete Sequences - 3 or more cards of the same suit in consecutive rank. Remember that the Ace is always low and the King is always high and that sequences cannot "wrap-around". The following sequences are illegal.
    • QD KD AD
    • KS AS 2S
  2. Complete Groups - 3 or more cards of the same rank (Obviously from different suits since each of the 52 cards only appears once).
  3. Partial Groups - 2 cards of the same rank.
  4. Partial Sequences - 2 cards of the same suit in cosecutive rank.
  5. Deadwood - any cards that do not meet one of the first 4 categories.
The unmatched cards in a hand are all of the cards are in the last 3 categories (Partial Groups, Partial Sequences and Deadwood). The value of the hand is the value of all of the unmatched cards in the hand. Each card has a value as described in the Deck section.

To arrange the computer player's hand into sets use the following algorithm. Note this algorithm may not work 100% correctly in all circumstances, but it works pretty well in most circumstances. Your program MUST use this algorithm. Any program not using this algorithm will be considered as not functioning correctly.

  1. Find all complete sequences in the hand. Give each complete sequence a different set letter. The set letters should have the first set found be given the lowest set letter (i.e. a).
  2. Find all complete groups from the remaining cards in the hand. Give each complete group a different set letter.
  3. Find all partial groups. Give each partial group its own set letter. For each partial group starting with the partial group with the highest rank, check if a complete sequence exists that uses the rank of the partial group. If such a sequence exists, detemine if "breaking the sequence" will result in a lower value of unmatched cards than the value of the two cards in the partial group. Remember that a complete sequence of 4 or more cards could be "broken" and still result in a complete sequence. Also a sequence of 7 or more cards could be broken and result in two complete sequences.
    • Example One: Assume the complete sequence of 4C 5C 6C exists and the partial group of 6H 6S is found. The value of the partial group is 12 (6+6). If the 6C is broken from the sequence, the value of the "broken sequence" is 9 (4+5). Since 9 is less than 12, the sequence should be broken.
    • Example Two: Assume the complete sequence of 4C 5C 6C exists and the partial group of 4H 4S is found. The value of the partial group is 8 (4+4). If the 4C is broken from the sequence, the value of the "broken sequence" is 11 (5+6). Since 11 is not less than 8, the sequence should not be broken.
    • Example Three: Assume the complete sequence of 4C 5C 6C exists and the partial group of 5H 5S is found. The value of the partial group is 10 (5+5). If the 5C is broken from the sequence, the value of the "broken sequence" is 10 (4+6). Since 10 is equal to 10, the sequence could be broken or not, this is up to you. You could always break the sequence, never break the sequence or randomlly decide to break it or not (I assume the easiest is not to break the sequence).
    • Example Four: Assume the complete sequence of 3C 4C 5C 6C exists and the partial group of 6H 6S is found. The "broken sequence" still results in complete sequence of 3C 4C 5C. So the value of the "broken sequence" is 0. Since 0 is less than 12, the sequence should be broken.
    • Example Five: Assume the complete sequence of 3C 4C 5C 6C 7C 8C 9C exists and the partial group of 6H 6S is found. The "broken sequence" results in two complete sequences of 3C 4C 5C and 7C 8C 9C. So the value of the "broken sequence" is 0. Since 0 is less than 12, the sequence should be broken.
    • Example Six: Assume the complete sequence of 3C 4C 5C 6C 7C exists and the partial group of 6H 6S is found. The "broken sequence" results in one complete sequence of 3C 4C 5C and the unmatched card of 7C. So the value of the "broken sequence" is 7. Since 7 is less than 12, the sequence should be broken.
    • Example Seven: Assume the complete sequence of 3C 4C 5C 6C 7C 8C exists and the partial group of 6H 6S is found. The "broken sequence" results in one complete sequence of 3C 4C 5C and the unmatched cards of 7C and 8C. So the value of the "broken sequence" is 15. Since 15 is not less than 12, the sequence should not be broken.
    Note: the set letters may have to be modified to deal with the broken sequences.
  4. Find all partial sequences. Give each partial sequence its own set letter. Since all complete sequences were found before any complete groups, we will not have to worry about breaking any complete groups.
  5. Find all deadwood cards. Any card that is not in one of the first four categories is a deadwork card. The deadwoods can be combined into one set with a single set letter or each deadwood card can be given its own set letter.

To determine the value of the computer player's hand, sum the value of all unmatched cards.

To determine if the computer player should draw from the top card in the discard pile or draw the top card in the stock pile, use the following algorithm.

  • First check if the top card in the discard pile can be added to any partial sequence or partial group, if so take the card from the discard pile.
  • Else check if the top card in the discard pile can be added to any complete sequence or complete group, if so take the card from the discard pile.
  • Else check if the top card in the discard pile can convert a deadwood card into a partial sequence or a partial group AND there exists more than one deadwood card in the hand, if so take the card from the discard pile.
  • Else take the top card from the stock pile.

To determine the card to discard or knock with,

  • if deadwood cards exist, select the deadwood card with the highest point value.
  • else if partial sequences or partial groups exist, select the card from all of the partial sets with the highest point value.
  • else if complete sequences of 4 or more cards exist, select the card from a complete sequence with 4 or more cards with the highest point value.
  • else select a card from a complete group of 4 cards. It does not matter which card from a 4 card complete group is selected.
Once the card to discard or knock with is selected, the computer player must determine whether it will discard or knock. If the hand value (not counting of the card selected to discard) is ten points or less, the computer player will knock ending the current hand and returning the program to inter-hand commands once the points for the hand have been determined.
O
Organize the user player's hand. Use the same algorithm as described above for the computer player's hand on the user player's hand.
A <int> <letter>
Arrange the user player's hand according to the information given. The <int> in the command is used to specify which card is being "arranged". The <letter> in the command is used to specify which set letter the card is being assigned. The <int> value is to correspond to the positions used the last time the user's hand was displayed. Everytime the user's hand is displayed it MUST follow the algorithm as described in the C command.
The following commands are intra-hand commands that are used to draw a card. These commands can only be used during the playing of a hand, it is currently the user's turn and the user only has 10 cards in his/her hand.
S
Draw a card from the Stock pile The top card from the stock pile is taken and added to the user's hand.
T
Draw the top card from the Discard Pile. The top card from the discard pile is taken and added to the user's hand.
The following commands are intra-hand commands that are used to discard a card. These commands can only be used during the playing of a hand, it is currently the user's turn and the user has 11 cards in his/her hand.
D <int>
Discard the Indicated card. The <int> in the command is used to specify which command is to be discarded. The <int> value is to correspond to the positions used the last time the user's hand was displayed. Everytime the user's hand is displayed it MUST follow the algorithm as described in the C command.

Once the user has discarded, the computer player's turn immediate take place with no interaction from the user. The user will see two messages printed out during the computer player's turn. The first message is whether the computer player drew a card from the stock pile or from the discard pile. The second message is whether the computer player discarded or knocked to end it turn. If the computer player discarded, the rank and suit of the discarded card is to be shown. If the computer player knocked, the current hand is ended and the inter-hand commands will be used once the points for the hand have been determined.

K <int>
The user Knocks and ends the hand. The <int> in the command is used to specify which command is to be discarded. The <int> value is to correspond to the positions used the last time the user's hand was displayed. Everytime the user's hand is displayed it MUST follow the algorithm as described in the C command.

The user can only knock if the unmatched cards in the user's hand total ten points or less. The points in the user's hand are determined by checking the sets in the user's hand. Each set is verified to see if it contains a complete seqeunce or a complete group. The sets that do not contain complete sequences or complete groups are considered to be unmatched cards and are used for the hand value. If the hand value is more than ten points, an error message is given and the command is ignored. Otherwise the hand is over and the inter-hand commands are used once the points for the hand have been determined.

The points for a hand is determined once a player has knocked. Refer to the Knocking section and the Scoring section for how the points are determined. You are to automate the "laying off" of cards from the hand of the player that did not knock to the hand of the player that did knock. When doing this check all unmatched cards against sequences first before checking against groups. If the user has only one set and the computer player knocked, organize the user's hand as if the O command was given by the user.

This program will require the use of multiple source code files and separate compilation. The division of the subroutines between the multiple source code files must be logical. Note: a "source code file" is not the same as a "header file". Source code files will have a file extension of .c (or .cpp, .C, .CC, etc.), while a header file will have a file extension of .h. To perform separate compilation, your makefile must separately compile the source code files into ".o" files and then link the ".o" files together. Using a #include statement with a source code file will NOT satisfy a requirement of separate compilation.

In addition to using and submitting a makefile, this program will also require a 1-2 page write up of the data structures used in the program and the logical division of your program into multiple source code files (i.e. which routines are where). Remember that this write-up is to be written in ASCII format and is to be electronically turned in with your program. The name of this file should be "readme.txt". Also recall that your program will be given to another student to write a critique. Therefore, it is suggested that you do not include your Social Security Number in your program. Instead use your name and your CS User ID to identify yourself.

Your program must be written in good programming style. This includes (but is not limited to) meaningful identifier names, a file header at the beginning of each source code file, a function header at the beginning of the function, proper use of blank lines and indentation to aide in the reading of your code, explanatory "value-added" in-line comments, etc.

The work you turn in must be 100% your own. You are not allowed to share code with any other person (inside this class or not). You may discuss the project with other persons; however, you may not show any code you write to another person nor may you look at any other person's written code.

You are to submit this project using the CS Department's UNIX machine's turnin command. The project name for this assignment is mp2. Be sure to submit all source code, header files, makefile as well as your program description. Failure to turnin all required pieces will result in a lower grade for the assignment.