13.9. Shuffling and dealingΒΆ

In Section 13.6, I wrote pseudocode for a shuffling algorithm. Assuming that we have a function called shuffle_deck that takes a deck as an argument and shuffles it, we can create and shuffle a deck:

card_deck deck;               // create a standard 52-card deck
deck.shuffle_deck ();     // shuffle it

Then, to deal out several hands, we can use subdeck:

card_deck hand1 = deck.subdeck (0, 4);
card_deck hand2 = deck.subdeck (5, 9);
card_deck pack = deck.subdeck (10, 51);

This code puts the first 5 cards in one hand, the next 5 cards in the other, and the rest into the pack.

When you thought about dealing, did you think we should give out one card at a time to each player in the round-robin style that is common in real card games? I thought about it, but then realized that it is unnecessary for a computer program. The round-robin convention is intended to mitigate imperfect shuffling and make it more difficult for the dealer to cheat. Neither of these is an issue for a computer.

This example is a useful reminder of one of the dangers of engineering metaphors: sometimes we impose restrictions on computers that are unnecessary, or expect capabilities that are lacking, because we unthinkingly extend a metaphor past its breaking point. Beware of misleading analogies.

The active code below deals a deck of cards among three players for a game of Go Fish. Feel free to experiment with the code and deal decks for other games like War, Poker, and Egyptian Ratscrew.

Example c192_shuffle_deal_ac_1
 1#include <stdexcept>
 2#include <iterator>
 3#include <cstddef>
 4#include <random>
 5#include <iostream>
 6#include <string>
 7#include <vector>
 8#include <cstdlib>
 9using std::cout;
10
11enum card_suit { clubs, diamonds, hearts, spades };
12
13enum card_rank { ace=1, two, three, four, five, six, seven, eight, nine,
14ten, jack, queen, king };
15
16std::size_t random_int(std::size_t low, std::size_t high);
17
18struct playing_card {
19    card_rank rank;
20    card_suit suit;
21    playing_card ();
22    playing_card (card_suit s, card_rank r);
23    void print () const;
24    bool is_greater (const playing_card& c2) const;
25    bool equals (const playing_card& c2) const;
26};
27
28struct card_deck {
29    std::vector<playing_card> cards;
30    card_deck ();
31    card_deck (std::size_t n);
32    void print () const;
33    void swap_cards (std::size_t index1, std::size_t index2);
34    std::size_t find_lowest_card (std::size_t index);
35    void shuffle_deck ();
36    void sort_deck ();
37    card_deck subdeck (std::ptrdiff_t low, std::ptrdiff_t high) const;
38};
39
40std::ptrdiff_t find_bisect (card_deck subdeck, playing_card card);
41
42int main() {
43    card_deck deck;
44    deck.shuffle_deck();
45    card_deck hand1 = deck.subdeck(0, 6);
46    card_deck hand2 = deck.subdeck(7, 13);
47    card_deck hand3 = deck.subdeck(14, 20);
48    card_deck pack = deck.subdeck(21, 51);
49    cout << "Player 1's hand:" << std::endl;
50    hand1.print();
51    cout << std::endl;
52    cout << "Player 2's hand:" << std::endl;
53    hand2.print();
54    cout << std::endl;
55    cout << "Player 3's hand:" << std::endl;
56    hand3.print();
57}