(Latest Revision: 02/22/2000)
02/22/2000: minor revisions

Evaluating Bridge Hands

after carefully reading assignment #2 on page 47, we see that the program desired is supposed to be able to read some number of lines (0 or more) from standard input and produce a little report corresponding to each line.

For example, if the input is:

2C QD TC AD 6C 3D TD 3H 5H 7H AS JH KH
2C 3C 4C 5C 8C AH AS AD KS JS 9D KD KH
the the output will be:

CLUBS           10       6       2
DIAMONDS         A       Q      10       3
HEARTS           K       J       7       5       3
SPADES           A


CLUBS            8       5       4       3       2
DIAMONDS         A       K       9
HEARTS           A       K
SPADES           A       K       J
In the output, the suits come in order of increasing value and the cards in each row appear in order of decreasing value.

It seems clear that all outputs are supposed to be arranged this way.

When we solve this program, we should try to do it by writing a program that does what is required and costs as little as possible. For one thing, that means that when we make the program, we should work only as hard as we must and no harder.

What is the easiest way to solve this programming problem?

The program is required to write the cards in a particular order, so that probably means that it must read the cards, remember them, sort them into the proper order, and write them out in the proper order.

I think remembering and sorting sound like the hardest things the program will have to do.

How can we do these complicated-sounding jobs using just the knowledge about programming that we got last semester in programming I?

Well, there is a simple kind of remembering and sorting that we can do just by using an array of simple variables. Suppose we have an array with four rows and 13 columns, and that initially we store a zero in each array slot. We can think of the array as looking like this:


0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0
Now suppose that our program starts reading a "hand" like the assignment describes -- say the first hand it reads is:


2C 3C 4C 5C 8C AH AS AD KS JS 9D KD KH
After reading the "2C" the program can change one of the 0's in the array to a 1, in order to remember that the two of clubs has been seen in the hand. The four rows of the matrix can stand for the four suits and the 13 columns can stand for the 13 cards in a suit. The 2 of clubs is the lowest card in the lowest suit, so the program might do this:


1  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0
Afterwards, upon reading 3C then 4C, 5C, 8C, and AH, the array might look like this:


1  1  1  1  0  0  1  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  1
0  0  0  0  0  0  0  0  0  0  0  0  0
This assumes that the rows represent clubs, diamonds, hearts and spades, in that order, and that the columns represent 2, 3, 4, ... T, J, Q, K, A going from left to right.

After the program reads in the entire hand, what it has in the array can be thought of as looking like this:


1  1  1  1  0  0  1  0  0  0  0  0  0
0  0  0  0  0  0  0  1  0  0  0  1  1
0  0  0  0  0  0  0  0  0  0  0  1  1
0  0  0  0  0  0  0  0  0  1  0  1  1
Notice that this simple method of marking each card present in the array by changing a 0 to a 1 has taken care of the remembering and sorting that is needed. In effect the array is now a memory of the hand, arranged in order.

Notice that a simple program can use an array like this one to generate the desired kind of report.

The program would make the report by looking at each element of the array, going from right to left (not left to right) and top to bottom. Each time it begins working on a new row, it prints the name of the suit the row corresponds to. For example, the program prints "CLUBS" before starting to look at the first row. Each time the program finds a 1 in the array, it prints out the rank of a card. It figures out which card to write by noticing what the current column number is. For example, if a 1 is found in the second-to-last column then the program prints out K. If a 1 is found in the fourth column from the left then the program prints out 5.

The discussion above represents the kind of stuff a programmer has to think about before writing the program. It is the kind of brainstorming design work that has to occur.

The programmer has to read the specifications carefully, spend a lot of time thinking and probably day-dreaming about the requirements.

Eventually, the creative mind of the programmer may produce a plausible concept of how the required task can be done. With this concept in hand, the programmer can then go on to the next step: write a simple one-two-three kind of main module that describes the complete solution of the problem with the steps correctly ordered.

In real life the programmer may not think of a solution, or may not think of one for a very long time. The programmer may seek advice and help from other programmers. After getting a little help, the programmer may then be able to produce the rest of the solution without more help.

So here is a summary of what the level one program might do:

Declare 2D array 4X13 ... {clubs, diamonds, hearts, spades} by {2 through Ace} (remember that C++ arrays are indexed starting from 0, so the programmer will need to remember that s/he has to pay some special attention to how the program will keep track of which card is represented by which slot in the array.)


/* Basic idea of a loop to process the input */
For each hand
begin
  Zero out the array
  For each card in the hand
  begin
    Get the two-letter code
    Mark the card as present
  end
    PrettyPrint the hand by using the array
end 
NOTE: The "code" given above and below is "pseudo-code." It is not intended to be working code -- it is intended to be sufficiently like real C++ code so that it gives you an adequate idea of what you need to make the program do. Instructors have to give you pseudo-code in situations where they want to give you a hint, but do not want to write the program for you. Your job is to take the definitions here as hints and then write a program in real C++. The hints should give you some good ideas about what you need to write, but a lot of judgement is still needed on your part to put it all together and make it work. In particular, you always have to be on guard not to take hints and helpful remarks too literally.

Question: The basic idea of the loop above is sound, but how shall we make the loop "work?" What shall be the test that determines if there are any more hands left to look at, or any more cards left to look at in the current hand?

One easy thing to do is to write code like this:


char rankChar, suitChar ;
     /* test by attempting to get the first part of the first card */
while (cin >> rankChar)  
   /* the input command returns  a value of true 
      or false -- the test we need.  This loop is a big
      part of the solution we need.  It takes care of starting right
      and stopping right.  */
{
    /* get the rest of the first card */
  cin >> suitChar;
  Zero out the array ;
  Mark the first card as present
    /* the next step involves reading the info about the next 12 cards */
  Mark the rest of the hand as present  
  PrettyPrint the hand
}
C code like that above can actually achieve the desired control of the loop.


To write "Zero out the array" as a function:

Use nested for-loops that go through the array.


The rank and suit of a card are input as characters. The program can translate these characters into numerical codes any time after reading them by using switch statements like:


    switch (rankChar)
    {
       case '2' : rankNum = 0 ; break ;
       case '3' : rankNum = 1 ; break ;
       case '4' : rankNum = 2 ; break ;
       case '5' : rankNum = 3 ; break ;
       case '6' : rankNum = 4 ; break ;
       case '7' : rankNum = 5 ; break ;
       case '8' : rankNum = 6 ; break ;
       case '9' : rankNum = 7 ; break ;
       case 'T' : rankNum = 8 ; break ;
       case 'J' : rankNum = 9 ; break ;
       case 'Q' : rankNum = 10 ; break ;
       case 'K' : rankNum = 11 ; break ;
       case 'A' : rankNum = 12 ; break ;
(In this example rankChar is the rank read as a character variable, and the variable called rankNum is an integer variable.)

This same job could also be done with a series of if statements like this:


if (rankChar == '2') rankNum = 0 ;
if (rankChar == '3') rankNum = 1 ;
if (rankChar == '4') rankNum = 2 ;
if (rankChar == '5') rankNum = 3 ;
if (rankChar == '6') rankNum = 4 ;
if (rankChar == '7') rankNum = 5 ;
if (rankChar == '8') rankNum = 6 ;
if (rankChar == '9') rankNum = 7 ;
if (rankChar == 'T') rankNum = 8 ;
if (rankChar == 'J') rankNum = 9 ;
if (rankChar == 'Q') rankNum = 10 ;
if (rankChar == 'K') rankNum = 11 ;
if (rankChar == 'A') rankNum = 12 ;
Note that this translation maps the input characters into the range 0 to 12, which is exactly the range of column numbers.

We can also write similar code to map (translate) the character code for card suits (C, D, H, and S) into the array row indices 0, 1, 2, and 3.


To write "Mark card present" as a function:

Assuming that the rank and suit have already been translated into integer array indices, a simple C statement such as deckFlags[suitNum][rankNum] = 1 can mark the card present.


To input the rank and suit as characters and translate them into integers:

We were told that hands come as groups of 13 cards. Therefore, if the main program reads the first character on the line to do its test, and then it reads the second character in the way the example does, then after that the program will need to read exactly 12 more pairs of characters in order to find out what the rest of the cards in the hand are. It will then have to move past the end-of-line to get set-up for the next test for more input.


A function that marks the rest of the hand as present could do this:


int count ;
for (count=2; count <= 13; count++)
{
  cin >> rankChar ; 
  translate rankChar to rankNum ;
  cin >> suitChar ;
  translate suitChar to suitNum ;
  Mark the card as present (rankNum, suitNum, deckOfFlags)
}

A function that prints out a report on a hand could look like this:


     /* go over the array and print out the cards that are present */
clubNum = 0;
spadeNum = 3;
for (suitNum=clubNum; suitNum <= spadeNum; suitNum++)
{
   /* make the row label */
  writeSuitString(suitNum) ;
    /* run down the list of cards in the suit and print the ones
       that are present.  Go backwards through the array to get
       the printout to go from high to low. */
  for (rankNum=13; rankNum >= 0; rankNum--)
  {
     if present(suitNum, rankNum)
     {
       tab over ;      
       writeCard(rankNum);
     }
  }
  move to new line ;
}
move to a new line again to separate output for the next hand.