Skip to content

Instantly share code, notes, and snippets.

@richhollis
Created November 23, 2013 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richhollis/7614183 to your computer and use it in GitHub Desktop.
Save richhollis/7614183 to your computer and use it in GitHub Desktop.
Clojure Week 3 Homework - Poker hand
(defn deck []
(for [suit [:clubs :hearts :spades :diamonds]
pip (range 2 15)]
{:suit suit
:pip pip}))
(defn hand-frequencies [hand]
(frequencies (map :pip (hand))))
(defn n-of-a-kind?
[n hand]
(some #{n} (vals (hand-frequencies hand))))
(defn full-house? [hand]
(and (n-of-a-kind? 2 hand) (n-of-a-kind? 3 hand)))
(defn hand []
(take 5 (shuffle (deck))))
(full-house? hand)
@krisajenkins
Copy link

Well done! This is good stuff.

There's one thing here that's a little confusing though, which you may not have noticed. Here's a question for you: What should the argument to full-house? be? A list of 5 cards? Or a function that deals them?

Either is legal. There's nothing wrong with supplying a function as an argument. (In fact, it can lead to serious Function Programming-fu.) But for this exercise, I think full-house? should take 5 cards and return true or false, so we need to change things.

I'd lean strongly towards naming values with nouns, functions with verbs. So let's change your last few lines to:

(defn deal-hand []
  (take 5 (shuffle (deck))))

; Invoke the deal-hand function, to get 5 new cards, and pass those to full-house?
(full-house? (deal-hand))

If you do that, you'll get this error:

: ClassCastException clojure.lang.LazySeq cannot be cast
:   to clojure.lang.IFn  user/hand-frequencies (...clj:8)

What does that mean? If we read it from right to left, it's saying, "On line 8, in the hand-frequencies function, I was expecting a function (something that implements IFn), but got a LazySeq (one of the list classes) instead."

If we look on line 8, yup, you're calling (hand). What you've been doing is passing the function-that-does-dealing down through the chain, and only invoking it when you get to hand-frequencies. I think what you want to do is deal those cards right at the top, then pass the 5 cards down the chain. So another quick change:

(defn hand-frequencies [hand]
  (frequencies (map :pip hand)))

And it will work again. We've now got this code:

(defn deck []
  (for [suit [:clubs :hearts :spades :diamonds]
    pip (range 2 15)]
    {:suit suit
     :pip pip}))

(defn hand-frequencies [hand]
  (frequencies (map :pip hand)))

(defn n-of-a-kind?
  [n hand]
  (some #{n} (vals (hand-frequencies hand))))

(defn full-house? [hand]
  (and (n-of-a-kind? 2 hand) (n-of-a-kind? 3 hand)))

(defn deal-hand []
  (take 5 (shuffle (deck))))

(full-house? (deal-hand))

hand means 5 cards. deal-hand is a function that creates a new list of 5 cards. Variable names and functions are named more clearly.

So...let's ask a question of this system. And it's the one you raised: How do you repeat this 30 times looking for a full house? Well, let's look at one of those FP-fu functions that takes a function as an argument.
repeatedly takes a function and calls it over-and-over again to make a list of its results. We can say:

(repeatedly 30 deal-hand)

And get 30 hands. Then we could just run full-house? over those 30 with map:

(map full-house? (repeatedly 30 deal-hand))

That's us done.

Except...

If you run that I'll bet you get a list of 30 nils, right? That's not the code's fault. That's poker's fault. The odds of a full house are 693/1, so 30 hands isn't enough dealing. Maybe we should ask a different question. "How many hands do we need to deal before we get a full house?" I'm going to give you one possible approach, which for now I leave you to decipher. Hopefully we can break down in detail next week:

 (loop [n 0]                                                                                                         
    (if (full-house? (deal-hand))                                                                                     
      n                                                                                                               
      (recur (inc n))))    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment