VII: The Programmatic Side of Mathematica: Dealing Cards

You might recall in our last post, we had a way of declaring a deck of cards:

deck = Flatten[Outer[List, {s, h, c, d},
       Join[Range[2, 10], {J, Q, K, A}]], 1]
{{s,2},{s,3},{s,4},{s,5},{s,6},{s,7},{s,8},{s,9},{s,10},{s,J},
{s,Q},{s,K},{s,A},{h,2},{h,3},{h,4},{h,5},{h,6},{h,7},{h,8},{h,9},
{h,10},{h,J},{h,Q},{h,K},{h,A},{c,2},{c,3},{c,4},{c,5},{c,6},
{c,7},{c,8},{c,9},{c,10},{c,J},{c,Q},{c,K},{c,A},{d,2},{d,3},{d,4},
{d,5},{d,6},{d,7},{d,8},{d,9},{d,10},{d,J},{d,Q},{d,K},{d,A}}

… but alas, no way yet of dealing random cards. And this was because we said there was no way of actually shuffling the deck. Mathematica would likely provide a way, but it is probably better to declare a function that randomly deals out the cards, while removing the cards it deals from the deck. To see this more easily, let’s declare a small set whose results are easier to see:

m= {2,4, 6, 8, 12, 78, 114}
{2,4,6,8,12,78,114}

We need to declare a function that chooses a random element from the list:

Random[Integer, {1, Length[m]}]
3

The number 3 returned is not from the list, but random integer between 1 and the list length. That is, the third element in the list, or the number 6. This can still be useful, however:

removeRand[lis_]:=Delete[lis, Random[Integer,{1, Length[lis]}]]

We can pass this random element number into a function which deletes the number at the random position from the list, as shown above. But don’t we want to deal that card also? There is not really any way I can think of that can both delete and return an element, but there is a way we may use set theory. If I delete an element n from set A, then A’s complement (or “not A”) becomes the deleted element n.

Complement[m, removeRand[m]]
{12}

On the same call, m is the same copy with all the original elements. So, in this call to Complement[], an element is randomly removed from set m. This new set, without the “12”, is now compared against m to find the new set’s complement, the number that was removed, and it is displayed. removeRand[] evidently returned a “5”, which is the number 12, the 5th element in m. A new subset of m {2,4,6,8,78,114} is compared against m to determine the complement, and 12 is returned. Throughout this operation, m never really gets modified.

When we deal cards from a deck, we want to deal several cards in one hand. In rummy, that can consist of 7 cards, depending on how many people are playing (Wikipedia says up to 13 cards for two-handed rummy). So, let’s declare a function which will help us deal cards:

hand[n_]:=Complement[deck, Nest[removeRand, deck,n]]

What Nest[] does is remove n cards recursively from a set called “deck”, the set we originally declared in today’s article. The complement between “deck” and “deck” with 7 rummy cards removed, is the rummy hand.

hand[7]
{{c,6},{c,A},{d,A},{h,2},{h,J},{h,K},{s,2}}

With a pair of aces at the start, it’s not a bad hand, although your opponent might do better.