Hi Mr. Greenstein,
I have 2 separate fixes to your "dealacard" function. The first fix has
fewer changes and keeps with the main idea of your code, but is probably
impossible for most people to really understand.
Note, I needed to make one other change to your code not related to the
fix. Even though the comment on "#include <stdlib.h>" says "includes
definition of the random() function", I have only found documentation
that describes the "rand()" function in stdlib.h.
Fix 1:
Code:
int dealacard(int dealtcards[]){
int i, j;
int taken = 0; // used to count how many cards
are out of deck
for (taken = 0; dealtcards[taken] >= 0; taken++);
int cardnum = rand() %(52 - taken); // randomly choose a card left
in the deck
// this is the relative location
in the cards that have not been dealt
for (i = 0; i < taken; i++){ // see which cards are lower
than cardnum
if (dealtcards[i] <= cardnum){
cardnum++; // card value needs to be one
more
bool keepgoing = true;
while (keepgoing) {
keepgoing = false;
for (j = 0; j < i; j++){ // backtrack and see if we
passed a value
// that should now be
skipped
if (dealtcards[j] == cardnum){
cardnum++; // increase actual card
value
keepgoing = true;
}
}
}
}
}
dealtcards[taken] = cardnum; // this card is now taken
dealtcards[taken + 1] = -1; // indicate new end of list
return cardnum; // this is the next randomly dealt card
}
The second fix (which I actually developed first) has more changes to
your code and introduces another array, but is orders of magnitude
easier to understand as it follows a more humanistic approach to the
problem: "I have a list of ordered numbers and some of them are crossed
out. Find me the n-th smallest one in the remaining list."
Fix 2:
Change parameters for dealacard:
Code:
int dealacard(int [], bool []); // this function will deal a random
card from a depleted deck
Define an array in main():
Initialze deck[] at start of each hand:
Code:
for (i=0; i<52; i++){ // start each deal with a fresh deck
deck[i] = false;
};
Change the callers to dealacard:
Code:
firstcard = dealacard(cardstaken, deck); // first card
of next player's hand
secondcard = dealacard(cardstaken, deck); // second card
of next player's hand
Change dealacard:
Code:
int dealacard(int dealtcards[], bool deck[]){
int i;
int cardnum;
int taken = 0; // used to count how many cards are out of deck
for (taken = 0; dealtcards[taken] >= 0; taken++);
i = rand() % (52 - taken); // randomly choose a card left in
the deck
// this is the
relative location in the cards that have not been dealt
cardnum = 0;
while (deck[cardnum]){ // find first undealt card
cardnum++;
}
while (i > 0){ // move through deck until 'i' undealt cards have been skipped
cardnum++;
while (deck[cardnum]){ // skip over cards that have already been dealt
cardnum++;
}
i--;
}
deck[cardnum] = true;
dealtcards[taken] = cardnum; // this card is now taken
dealtcards[taken + 1] = -1; // indicate new end of list
return cardnum; // this is the next randomly dealt
card
}
For the curious, I will attempt to explain the problem with BG's
original code. (It ain't easy to explain.)
Function "dealacard" sometimes deals duplicate cards from the deck.
This happens in the following circumstances:
1. Two consecutive cards are dealt from the deck in reverse numerical
order. The deck is numerically ordered from 0 to 51.
2. At least one more card smaller than the first two is now dealt.
3. A random number is generated for the fourth card. This number is
relative to the remaining cards in the deck. It happens to be
numerically one less than the smaller one dealt in step 1. (The
problem can also occur when this number is 2 or more less than those
from step 1.)
The code detects that this number needs to be incremented because it is
greater than (or equal to) the card from step 2. After incrementing, it
checks to see if this card has already been dealt. The code finds that
this card was already dealt in step 1, so it needs to increment to the
next card.
But this is where the error is because if this new card was already
"passed over" while checking the cards that have been dealt, then it
doesn't get incremented again, but is returned as the card dealt.
Kind Regards,
TommyPR