(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.