Shuffling cards with Clojure
Standard disclaimer: Clojure is a new hobby.
One of my friends and coworkers has been gently cluesticking me into learning poker. Along the way he suggested I write a very simple hand generator to get a feel for how the number of players changes the relative strength of your hole cards. Shuffling cards is one small step along the way, and that seemed like a good place to start.
First, let's create a poker namespace to work in and then define some basic constants as keywords in sets.
(def suits #{:hearts, :diamonds, :clubs, :spades})
(def names #{:two, :three, :four, :five, :six,
:seven, :eight, :nine, :ten, :jack,
:queen, :king, :ace})
Next, let's "define a class." I'm quoting that because a struct in Clojure is just a map with some keys to be expected.
Next we actually need, you know, a full deck of cards to shuffle. This was harder than I expected. At first I tried two loops, first iterating over suits and then values. This resulted in a list of ... four lists of... thirteen cards.
(map (fn [suit]
(map (fn [name]
(struct card suit name))
names))
suits))
(count sequence-of-suits) ;; 4
(count (first sequence-of-suits)) ;; 13
Unfortunately (map) didn't work as hoped. I decided to try a list comprehension. This was something I remembered from using once in Python. It turned out to be exactly what I needed:
(for [suit suits, name names]
(struct-map card :suit suit :name name)))
This yields a lot of text, so let's inspect the output programmatically. (filter) is a function which takes a function and a list; the output consists of the list items for which the function inspects and returns true.
;; 52
(first deck)
;; {:suit :hearts, :name :queen}
(last deck)
;; {:suit :clubs, :name :four}
(defn heart? [card]
(= :hearts (card :suit)))
(count (filter heart? deck))
;; 13
(defn king? [card]
(= :king (card :name)))
(count (filter king? deck))
;; 4
(defn king-of-hearts? [card]
(and (king? card) (heart? card)))
(filter king-of-hearts? deck)
;; ({:suit :hearts, :name :king})
Now that we have the deck straightened out, it's time to shuffle it. I'm getting the feeling there is a beautiful mathmatical way to sort 52 cards involving permutations which would be easy to code functionally. Unfortunately I'm not there yet on either side. This implementation is really crude.
For example, this random-card implementation instantiates java.util.Random each time it is called (and without a seed value). (nth) returns the nth item of a sequence; (seq) is being used here because deck is a hashmap, which doesn't support ordered extraction.
(nth (seq deck)
(. (new java.util.Random)
nextInt
(count deck))))
Continuing on with the vulgar display of crude code... here is the shuffle method:
([deck]
(shuffle [] deck))
([clean dirty]
(if (empty? dirty)
clean
(let [pick (random-card dirty)]
(shuffle (conj clean pick)
(disj (set dirty) pick))))))
Let's ignore the lack of comments of any sort here. This implementation uses variable arity. That means when the function is passed one parameter the following code will run:
(shuffle [] deck))
And when two parameters are passed the following code runs:
(if (empty? dirty)
clean
(let [pick (random-card dirty)]
(shuffle (conj clean pick)
(disj (set dirty) pick))))))
This is a feature of Clojure. I kind of like it. The way recursion was used here the variable arity made the code simple to read. I probably could have used (recur) for a very similar amount of code, but the dogs had to go out.
So the second chunk of (shuffle) picks a card at random from the unsorted pile, uses (conj) to include it in the sorted pile, uses (disj) to exclude the picked card from the unsorted pile, and then GOTO 10.
And now, with lots of gory code I'm not proud of, here is my first hand of 5 card draw:
({:suit :diamonds, :name :three}
{:suit :clubs, :name :ten}
{:suit :diamonds, :name :four}
{:suit :spades, :name :three}
{:suit :hearts, :name :three})
Wow, three of a kind. It's almost as if I programmed in a "be nice to Seth" bit somewhere...


