View Single Post
  #54 (permalink)  
Old 08-28-2009, 02:46 PM
TommyPR TommyPR is offline
Beginning Poster
 
Join Date: Aug 2009
Posts: 3
Default

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():

Code:
 
bool deck[52]; 
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