8.5. Case Study: Card Shuffling and Dealing SimulationThe examples in the chapter thus far have used arrays containing elements of primitive types. Recall from Section 8.2. that the elements of an array can be of either primitive types or reference types. This section uses random number generation and an array of reference-type elements, namely references to objects representing playing cards, to develop a class that simulates card shuffling and dealing. You can then use this class to implement applications that play specific card games. First, we develop class Card (Fig. 8.8), 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. 8.9), which creates a deck of 52 playing cards in which each element is a Card object. We then build a test application DeckOfCardsTest (Fig. 8.10) that demonstrates class DeckOfCards's card shuffling and dealing capabilities. Figure 8.8. Card class represents a playing card.
Figure 8.9. DeckOfCards class represents a deck of playing cards that can be shuffled and dealt one at a time.
Figure 8.10. Card shuffling and dealing (all 52 cards are dealt).
Class CardClass Card (Fig. 8.8) 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 811) receives two Strings that it uses to initialize face and suit. Method ToString (lines 1416) creates a String consisting of the face of the card, the String " of " and the suit of the card. Recall from Chapter 3 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 an object is output as a String. For this behavior to occur, ToString must be declared with the header shown in line 14 of Fig. 8.8. We discuss the special method ToString in Chapter 9, Classes and Objects: A Deeper Look. Class DeckOfCardsClass DeckOfCards (Fig. 8.9) declares an instance variable array named deck, which consists of Card objects (line 4). Like primitive-type array declarations, the declaration of an array of objects includes the name of the array variable, followed by the keyword As, the type of the elements in the array and parentheses (e.g., deck As Card()). Class DeckOfCards also declares an integer instance variable currentCard (line 5) representing the next Card to be dealt from the deck array and a named constant NUMBER_OF_CARDS (line 6) indicating the number of Cards in the deck (52). The class's constructor instantiates the deck array (line 15) with upper bound NUMBER_OF_CARDS - 1. When first created, the elements of the deck array are Nothing by default, so the constructor uses a For statement (lines 2022) to fill the deck array with Cards. This statement initializes control variable count to 0 and loops while count is less than or equal to deck.GetUpperBound(0), 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 Mod 13 always results in a value from 0 to 12 (the 13 indices of the faces array in lines 1112), and the calculation count \ 13 always results in a value from 0 to 3 (the four indices of the suits array in line 13). When the deck array is initialized, it contains the Cards with faces "Ace" through "King" in order for each suit. Method Shuffle (lines 2640) 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 (line 33). Next, the current Card object and the randomly selected Card object are swapped in the array (lines 3638). 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. Only 52 swaps are made in a single pass of the entire array, and the array of Card objects is shuffled! Method DealCard (lines 4352) 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 45 compares currentCard to the upper bound (51) of the deck array. If the deck is not empty (i.e., currentCard is less than or equal to 51), line 46 assigns currentCard (the index of the card that will be returned) to temporary variable lastCard, line 47 increments currentCard to prepare for the next call to DealCard and line 48 returns deck(lastCard), which represents the top card of the deck for this call to DealCard. Otherwise, DealCard returns Nothing to indicate that the deck is empty. Shuffling and Dealing CardsThe application in Fig. 8.10 demonstrates the card dealing and shuffling capabilities of class DeckOfCards (Fig. 8.9). Line 5 creates a DeckOfCards object named cards. Recall that the DeckOfCards constructor creates the deck with the 52 Card objects in order by suit and face. Line 6 invokes cards's Shuffle method to randomly rearrange the Card objects. The For statement in lines 913 deals all 52 Cards in the deck and prints them in four columns of 13 Cards each. Lines 1012 deal and print four Card objects (on one line), each obtained by invoking cards's DealCard method. When Console.WriteLine outputs a Card with the {0, -18} format specifier, the Card's ToString method (declared in lines 1416 of Fig. 8.8) is implicitly invoked, and the result is output left justified (because of the minus sign in -18) in a field of width 18. Again, we explain ToString in detail in Chapter 9. |