Case Study: Card Shuffling and Dealing Simulation

Case Study Card Shuffling and Dealing Simulation

The examples in the chapter thus far have used arrays containing elements of primitive types. Recall from Section 7.2 that the elements of an array can be either primitive types or reference types. This section uses random number generation and an array of reference-type elements, namely objects representing playing cards, to develop a class that simulates card shuffling and dealing. This class can then be used to implement applications that play specific card games. The exercises at the end of the chapter use the classes developed here to build a simple poker application.

We first develop class Card (Fig. 7.9), which represents a playing card that has a face (e.g., "Ace", "Deuce", "Three", ..., "Jack", "Queen", "King") and a suit (e.g., "Hearts", "Diamonds", "Clubs", "Spades"). Next, we develop the DeckOfCards class (Fig. 7.10), which creates a deck of 52 playing cards in which each element is a Card object. We then build a test application (Fig. 7.11) that demonstrates class DeckOfCards's card shuffling and dealing capabilities.

Figure 7.9. Card class represents a playing card.

(This item is displayed on page 299 in the print version)

1 // Fig. 7.9: Card.java 2 // Card class represents a playing card. 3 4 public class Card 5 { 6 private String face; // face of card ("Ace", "Deuce", ...) 7 private String suit; // suit of card ("Hearts", "Diamonds", ...) 8 9 // two-argument constructor initializes card's face and suit 10 public Card( String cardFace, String cardSuit ) 11 { 12 face = cardFace; // initialize face of card 13 suit = cardSuit; // initialize suit of card 14 } // end two-argument Card constructor 15 16 // return String representation of Card 17 public String toString() 18 { 19 return face + " of " + suit; 20 } // end method toString 21 } // end class Card

Figure 7.10. DeckOfCards class represents a deck of playing cards that can be shuffled and dealt one at a time.

(This item is displayed on pages 299 - 300 in the print version)

1 // Fig. 7.10: DeckOfCards.java 2 // DeckOfCards class represents a deck of playing cards. 3 import java.util.Random; 4 5 public class DeckOfCards 6 { 7 private Card deck[]; // array of Card objects 8 private int currentCard; // index of next Card to be dealt 9 private final int NUMBER_OF_CARDS = 52; // constant number of Cards 10 private Random randomNumbers; // random number generator 11 12 // constructor fills deck of Cards 13 public DeckOfCards() 14 { 15 String faces[] = { "Ace", "Deuce", "Three", "Four", "Five", "Six", 16 "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" }; 17 String suits[] = { "Hearts", "Diamonds", "Clubs", "Spades" }; 18 19 deck = new Card[ NUMBER_OF_CARDS ]; // create array of Card objects 20 currentCard = 0; // set currentCard so first Card dealt is deck[ 0 ] 21 randomNumbers = new Random(); // create random number generator 22 23 // populate deck with Card objects 24 for ( int count = 0; count < deck.length; count++ ) 25 deck[ count ] = 26 new Card( faces[ count % 13 ], suits[ count / 13 ] ); 27 } // end DeckOfCards constructor 28 29 // shuffle deck of Cards with one-pass algorithm 30 public void shuffle() 31 { 32 // after shuffling, dealing should start at deck[ 0 ] again 33 currentCard = 0; // reinitialize currentCard 34 35 // for each Card, pick another random Card and swap them 36 for ( int first = 0; first < deck.length; first++ ) 37 { 38 // select a random number between 0 and 51 39 int second = randomNumbers.nextInt( NUMBER_OF_CARDS ); 40 41 // swap current Card with randomly selected Card 42 Card temp = deck[ first ]; 43 deck[ first ] = deck[ second ]; 44 deck[ second ] = temp; 45 } // end for 46 } // end method shuffle 47 48 // deal one Card 49 public Card dealCard() 50 { 51 // determine whether Cards remain to be dealt 52 if ( currentCard < deck.length ) 53 return deck[ currentCard++ ]; // return current Card in array 54 else 55 return null; // return null to indicate that all Cards were dealt 56 } // end method dealCard 57 } // end class DeckOfCards

Figure 7.11. Card shuffling and dealing.

(This item is displayed on page 302 in the print version)

1 // Fig. 7.11: DeckOfCardsTest.java 2 // Card shuffling and dealing application. 3 4 public class DeckOfCardsTest 5 { 6 // execute application 7 public static void main( String args[] ) 8 { 9 DeckOfCards myDeckOfCards = new DeckOfCards(); 10 myDeckOfCards.shuffle(); // place Cards in random order 11 12 // print all 52 Cards in the order in which they are dealt 13 for ( int i = 0; i < 13; i++ ) 14 { 15 // deal and print 4 Cards 16 System.out.printf( "%-20s%-20s%-20s%-20s ", 17 myDeckOfCards.dealCard(), myDeckOfCards.dealCard(), 18 myDeckOfCards.dealCard(), myDeckOfCards.dealCard() ); 19 } // end for 20 } // end main 21 } // end class DeckOfCardsTest  

Six of Spades Eight of Spades Six of Clubs Nine of Hearts Queen of Hearts Seven of Clubs Nine of Spades King of Hearts Three of Diamonds Deuce of Clubs Ace of Hearts Ten of Spades Four of Spades Ace of Clubs Seven of Diamonds Four of Hearts Three of Clubs Deuce of Hearts Five of Spades Jack of Diamonds King of Clubs Ten of Hearts Three of Hearts Six of Diamonds Queen of Clubs Eight of Diamonds Deuce of Diamonds Ten of Diamonds Three of Spades King of Diamonds Nine of Clubs Six of Hearts Ace of Spades Four of Diamonds Seven of Hearts Eight of Clubs Deuce of Spades Eight of Hearts Five of Hearts Queen of Spades Jack of Hearts Seven of Spades Four of Clubs Nine of Diamonds Ace of Diamonds Queen of Diamonds Five of Clubs King of Spades Five of Diamonds Ten of Clubs Jack of Spades Jack of Clubs  

Class Card

Class Card (Fig. 7.9) contains two String instance variablesface and suitthat are used to store references to the face name and suit name for a specific Card. The constructor for the class (lines 1014) receives two Strings that it uses to initialize face and suit. Method toString (lines 1720) creates a String consisting of the face of the card, the String " of " and the suit of the card. Recall from Chapter 6 that the + operator can be used to concatenate (i.e., combine) several Strings to form one larger String. Card's toString method can be invoked explicitly to obtain a string representation of a Card object (e.g., "Ace of Spades"). The toString method of an object is called implicitly when the object is used where a String is expected (e.g., when printf outputs the object as a String using the %s format specifier or when the object is concatenated to a String using the + operator). For this behavior to occur, toString must be declared with the header shown in Fig. 7.9.

Class DeckOfCards

Class DeckOfCards (Fig. 7.10) declares an instance variable array named deck of Card objects (line 7). Like primitive-type array declarations, the declaration of an array of objects includes the type of the elements in the array, followed by the name of the array variable and square brackets (e.g., Card deck[]). Class DeckOfCards also declares an integer instance variable currentCard (line 8) representing the next Card to be dealt from the deck array and a named constant NUMBER_OF_CARDS (line 9) indicating the number of Cards in the deck (52).

The class's constructor instantiates the deck array (line 19) to be of size NUMBER_OF_CARDS. When first created, the elements of the deck array are null by default, so the constructor uses a for statement (lines 2426) to fill the deck array with Cards. The for statement initializes control variable count to 0 and loops while count is less than deck.length, causing count to take on each integer value from 0 to 51 (the indices of the deck array). Each Card is instantiated and initialized with two Stringsone from the faces array (which contains the Strings "Ace" tHRough "King") and one from the suits array (which contains the Strings "Hearts", "Diamonds", "Clubs" and "Spades"). The calculation count % 13 always results in a value from 0 to 12 (the 13 indices of the faces array in lines 1516), and the calculation count / 13 always results in a value from 0 to 3 (the four indices of the suits array in line 17). When the deck array is initialized, it contains the Cards with faces "Ace" through "King" in order for each suit.

Method shuffle (lines 3046) shuffles the Cards in the deck. The method loops through all 52 Cards (array indices 0 to 51). For each Card, a number between 0 and 51 is picked randomly to select another Card. Next, the current Card object and the randomly selected Card object are swapped in the array. This exchange is performed by the three assignments in lines 4244. The extra variable temp temporarily stores one of the two Card objects being swapped. The swap cannot be performed with only the two statements

deck[ first ] = deck[ second ]; deck[ second ] = deck[ first ];

If deck[ first ] is the "Ace" of "Spades" and deck[ second ] is the "Queen" of "Hearts", after the first assignment, both array elements contain the "Queen" of "Hearts" and the "Ace" of "Spades" is losthence, the extra variable temp is needed. After the for loop terminates, the Card objects are randomly ordered. A total of only 52 swaps are made in a single pass of the entire array, and the array of Card objects is shuffled!

Method dealCard (lines 4956) deals one Card in the array. Recall that currentCard indicates the index of the next Card to be dealt (i.e., the Card at the top of the deck). Thus, line 52 compares currentCard to the length of the deck array. If the deck is not empty (i.e., currentCard is less than 52), line 53 returns the top Card and increments currentCard to prepare for the next call to dealCardotherwise, null is returned. Recall from Chapter 3 that null represents a "reference to nothing."

Shuffling and Dealing Cards

The application of Fig. 7.11 demonstrates the card dealing and shuffling capabilities of class DeckOfCards (Fig. 7.10). Line 9 creates a DeckOfCards object named myDeckOfCards. Recall that the DeckOfCards constructor creates the deck with the 52 Card objects in order by suit and face. Line 10 invokes myDeckOfCards's shuffle method to rearrange the Card objects. The for statement in lines 1319 deals all 52 Cards in the deck and prints them in four columns of 13 Cards each. Lines 1618 deal and print four Card objects, each obtained by invoking myDeckOfCards's dealCard method. When printf outputs a Card with the %-20s format specifier, the Card's toString method (declared in lines 1720 of Fig. 7.9) is implicitly invoked, and the result is output left justified in a field of width 20.

Категории