|Dͻ
|D |5The Happy Hacker |D
|Dͼ

^C^1SHUFFLING ALONG
^C(A Realistic Card-Shuffling Algorithm)
^Cby:  Joel Ellis Rea

   One of the most popular game categories which can easily be adapted to 
computers is the traditional card games, including solitaire and poker in all 
their various forms, not to mention gin rummy, hearts, crazy-eights and many 
others.  Most card games are based on the odds of certain cards turning up at 
certain times.  If these odds are not accurate, the computer simulation of the 
game is not accurate.  Unfortunately, in most card games I've seen to date 
(both public domain and commercial), the programmer has seen fit to simply 
generate a list of 52 numbers in a random order without any repeats, and call 
that a "shuffled deck." 

   A little thought will reveal why this isn't sufficient for many card games:  
Suppose you are playing Blackjack, and you see the dealer shuffle a fresh deck 
one time.  You can see that certain cards simply cannot follow certain other
cards, since the deck was split approximately into two decks, and cards were 
taken from the bottom of one of the two decks and added to the top of the new 
deck, repeatedly.  This is not a complete randomization of the deck.  Of 
course, a "standard" shuffle means doing three shuffles then allowing another 
player to "cut" the deck.  Rules and odds for most card games, particularly 
poker, blackjack, bridge and nearly all solitaire games, are based on a 
standard shuffle.  With a computerized random shuffle, the odds may not come 
out correctly. 

   We noticed this when writing the "Streets and Alleys" solitaire game which 
was published last issue.  With an ordinary computerized random-shuffling algo-
rithm, it was virtually impossible to win the game, or even make as many as 5 
moves successfully.  Val J. Golding, our editor in chief and resident card 
shark, realized that the shuffle algorithm was at fault.  Now the game is far 
more realistic and playable.  It is difficult to win, but now the odds against 
getting dealt a winnable hand no longer surpasses the odds against finding an 
IBM PC/AT original 20-meg hard disk still working. 

   Here is the shuffling algorithm in a "pseudo-code," easily translatable to 
most any algorithmic, procedural programming language.
|3

PROCEDURE shuffle_deck (count, start_deck(), shuffled_deck())
 
   shuffle_once (start_deck(), shuffled_deck())
   //Shuffle first time, starting with the "start_deck" as passed to us.

   IF count>2 THEN          //If shuffling more than once,
   
     FOR i:=2 TO count DO   //for each additional shuffle,
       shuffle_once (shuffled_deck(), shuffled_deck())
       //shuffle again, this time starting with the results of the LAST shuffle.
     ENDFOR i

   ENDIF

ENDPROCEDURE shuffle_deck
 
  
PROCEDURE shuffle_once (start_deck, shuffled_deck) 

  split := RND(23,30)  //Random split point roughly in middle.
  top := split         //Current start of top "half-deck."
  bottom := 1          //Current start of bottom "half-deck."
  shuffle := 1         //Current end of new shuffled deck. 
  top_half := FALSE    //Which "half-deck" to take next card from. 
  odds := 0.5          //Current odds for repeating same "half-deck." 

  REPEAT 
 
    IF bottom = split THEN   //Is bottom "half-deck" empty? 
      top_half := TRUE       //If so, take next card from top half. 
 
    ELSEIF top > 52 THEN     //Is top "half-deck" empty? 
      top_half := FALSE      //If so, take next card from bottom half. 
  
    ELSE                     //If neither half is empty, then ... 

      last_half := top_half  //remember which half we used last. 

      IF RND > odds THEN             //If we randomly beat the "odds", 
        top_half := NOT top_half#    //switch which half we use. 
      ENDIF 
 
      IF last_half = top_half# THEN  //If we are still using the same half, 
        odds := odds / 2             //cut odds of repeating it again in half, 

      ELSE 
        odds := 0.5                  //otherwise reset odds to a 50/50 chance. 

      ENDIF 
 
    ENDIF 

    CASE top_half# OF  //Do the actual shuffle of a card. 

      WHEN FALSE     //Use bottom "half-deck?"       
        shuffled_deck(shuffle) := start_deck(bottom)  //Move the card. 
        bottom :+ 1  //Increment card pointer for bottom "half-deck." 

      WHEN TRUE      //Use top "half-deck?" 
        shuffled_deck(shuffle) := fresh_deck(top)     //Move the card.
        top :+ 1     //Increment card pointer for top "half-deck." 

    ENDCASE 

    shuffle :+ 1   //Increment card pointer for new shuffled deck. 
 
  UNTIL shuffle# > 52  //Do this for each card until all 52 cards are shuffled. 

ENDPROCEDURE shuffle_once 
|3

   Feel free to use and/or modify this algorithm as you see fit, but please 
mention that you found the algorithm in BIG BLUE DISK. 
