Repository: exercism/clojure
Pull request #218 (2018-03-18 23:51:31)

add poker


Patch:
diff --git a/config.json b/config.json
index 415fa09..eab68af 100644
--- a/config.json
+++ b/config.json
@@ -589,6 +589,14 @@
       "topics": null,
       "unlocked_by": null,
       "uuid": "c8ba6ce5-9a7e-4c1c-8044-bb18a0d6ad39"
+    },
+    {
+      "core": false,
+      "difficulty": 1,
+      "slug": "poker",
+      "topics": null,
+      "unlocked_by": null,
+      "uuid": "7df7ff1c-74ab-4f4e-aaf0-257b6e1cbc18"
     }
   ],
   "foregone": [],
diff --git a/exercises/poker/README.md b/exercises/poker/README.md
new file mode 100644
index 0000000..542c2b0
--- /dev/null
+++ b/exercises/poker/README.md
@@ -0,0 +1,11 @@
+Pick the best hand(s) from a list of poker hands.
+
+See [wikipedia](https://en.wikipedia.org/wiki/List_of_poker_hands) for an
+overview of poker hands.
+
+## Source
+
+[Inspired by the training course from Udacity.](https://www.udacity.com/course/viewer#!/c-cs212/)
+
+## Submitting Incomplete Solutions
+It's possible to submit an incomplete solution so you can see how others have completed the exercise.
diff --git a/exercises/poker/project.clj b/exercises/poker/project.clj
new file mode 100644
index 0000000..c2d6a23
--- /dev/null
+++ b/exercises/poker/project.clj
@@ -0,0 +1,4 @@
+(defproject poker "0.1.0-SNAPSHOT"
+  :description "poker exercise."
+  :url "https://github.com/exercism/clojure/tree/master/exercises/poker"
+  :dependencies [[org.clojure/clojure "1.9.0"]])
diff --git a/exercises/poker/src/example.clj b/exercises/poker/src/example.clj
new file mode 100644
index 0000000..221f79c
--- /dev/null
+++ b/exercises/poker/src/example.clj
@@ -0,0 +1,42 @@
+(ns poker
+  (:require [clojure.string :as cs]))
+
+(defn rank-hand [hand]
+  (let [h (cs/split (cs/replace hand #"10" "T") #" ")
+        initial-ranks (map #(.indexOf (seq "..23456789TJQKA") (first %)) h)
+        score-frec (reverse (sort-by vec (map (comp vec reverse)
+                                              (frequencies initial-ranks))))
+        rank-counts (mapv first score-frec)
+        normalized-ranks (if (= (mapv second score-frec) [14,5,4,3,2]) [5,4,3,2,1]
+                             (mapv second score-frec))
+        straight? (and (= 5 (count rank-counts))
+                       (= 4 (- (apply max rank-counts) (apply min rank-counts))))
+        flush? (= 1 (count (distinct (map last h))))]
+    (cond (= 5 rank-counts)         [9 normalized-ranks]
+          (and straight? flush?)    [8 normalized-ranks]
+          (= rank-counts [4 1])     [7 normalized-ranks]
+          (= rank-counts [3 2])     [6 normalized-ranks]
+          flush?                    [5 normalized-ranks]
+          straight?                 [4 normalized-ranks]
+          (= rank-counts [3 1 1])   [3 normalized-ranks]
+          (= rank-counts [2 2 1])   [2 normalized-ranks]
+          (= rank-counts [2 1 1 1]) [1 normalized-ranks]
+          :else                     [0 normalized-ranks])))
+
+(defn greater-than [xs ys]
+  (or (> (first xs) (first ys))
+      (->> (map compare (second xs) (second ys))
+           (take-while (partial not= -1))
+           (some (partial = 1)))))
+
+(defn best-hands [hands]
+  (-> (fn [[max-rank record hands]]
+        (let [[x & xs] hands
+              rank     (rank-hand x)]
+           (cond
+             (or (empty? record) (greater-than rank max-rank)) [rank [x] xs]
+             (= rank max-rank) [max-rank (conj record x) xs]
+             :else [max-rank record xs])))
+      (iterate  [[0 []] [] hands])
+      (nth (count hands))
+      (second)))
diff --git a/exercises/poker/src/poker.clj b/exercises/poker/src/poker.clj
new file mode 100644
index 0000000..cba55cf
--- /dev/null
+++ b/exercises/poker/src/poker.clj
@@ -0,0 +1,3 @@
+(ns poker)
+
+(defn best-hands [hands])


Test patch:
diff --git a/exercises/poker/test/poker_test.clj b/exercises/poker/test/poker_test.clj
new file mode 100644
index 0000000..f32518b
--- /dev/null
+++ b/exercises/poker/test/poker_test.clj
@@ -0,0 +1,147 @@
+(ns poker-test
+  (:require [clojure.test :refer [deftest is]]
+            [poker :refer [best-hands]]))
+
+(defn f [xs ys] (= (sort (best-hands xs)) (sort ys)))
+
+(deftest single-hand-always-wins
+  (is (f ["4S 5S 7H 8D JC"] ["4S 5S 7H 8D JC"])))
+
+(deftest highest-card-out-of-all-hands-wins
+  (is (f ["4D 5S 6S 8D 3C"
+          "2S 4C 7S 9H 10H"
+          "3S 4S 5D 6H JH"]
+         ["3S 4S 5D 6H JH"])))
+
+(deftest a-tie-has-multiple-winners
+  (is (f ["4D 5S 6S 8D 3C"
+          "2S 4C 7S 9H 10H"
+          "3S 4S 5D 6H JH"
+          "3H 4H 5C 6C JD"]
+         ["3S 4S 5D 6H JH"
+          "3H 4H 5C 6C JD"])))
+
+(deftest multiple-hands-with-the-same-high-cards-tie-compares-next-highest-ranked-down-to-last-card
+  (is (f ["3S 5H 6S 8D 7H"
+          "2S 5D 6D 8C 7S"]
+         ["3S 5H 6S 8D 7H"])))
+
+(deftest one-pair-beats-high-card
+  (is (f ["4S 5H 6C 8D KH"
+          "2S 4H 6S 4D JH"]
+         ["2S 4H 6S 4D JH"])))
+
+(deftest highest-pair-wins
+  (is (f ["4S 2H 6S 2D JH"
+          "2S 4H 6C 4D JD"]
+         ["2S 4H 6C 4D JD"])))
+
+(deftest two-pairs-beats-one-pair
+  (is (f ["2S 8H 6S 8D JH"
+          "4S 5H 4C 8C 5C"]
+         ["4S 5H 4C 8C 5C"])))
+
+(deftest both-hands-have-two-pairs-highest-ranked-pair-wins
+  (is (f ["2S 8H 2D 8D 3H"
+          "4S 5H 4C 8S 5D"]
+         ["2S 8H 2D 8D 3H"])))
+
+(deftest both-hands-have-two-pairs-with-the-same-highest-ranked-pair-tie-goes-to-low-pair
+  (is (f ["2S QS 2C QD JH"
+          "JD QH JS 8D QC"]
+         ["JD QH JS 8D QC"])))
+
+(deftest both-hands-have-two-identically-ranked-pairs-tie-goes-to-remaining-card-kicker
+  (is (f ["JD QH JS 8D QC"
+          "JS QS JC 2D QD"]
+         ["JD QH JS 8D QC"])))
+
+(deftest three-of-a-kind-beats-two-pair
+  (is (f ["2S 8H 2H 8D JH"
+          "4S 5H 4C 8S 4H"]
+         ["4S 5H 4C 8S 4H"])))
+
+(deftest both-hands-have-three-of-a-kind-tie-goes-to-highest-ranked-triplet
+  (is (f ["2S 2H 2C 8D JH"
+          "4S AH AS 8C AD"]
+         ["4S AH AS 8C AD"])))
+
+(deftest with-multiple-decks-two-players-can-have-same-three-of-a-kind-ties-go-to-highest-remaining-cards
+  (is (f ["4S AH AS 7C AD"
+          "4S AH AS 8C AD"]
+         ["4S AH AS 8C AD"])))
+
+(deftest a-straight-beats-three-of-a-kind
+  (is (f ["4S 5H 4C 8D 4H"
+          "3S 4D 2S 6D 5C"]
+         ["3S 4D 2S 6D 5C"])))
+
+(deftest aces-can-end-a-straight-10-J-Q-K-A
+  (is (f ["4S 5H 4C 8D 4H"
+          "10D JH QS KD AC"]
+         ["10D JH QS KD AC"])))
+
+(deftest aces-can-start-a-straight-A-2-3-4-5
+  (is (f ["4S 5H 4C 8D 4H"
+          "4D AH 3S 2D 5C"]
+         ["4D AH 3S 2D 5C"])))
+
+(deftest both-hands-with-a-straight-tie-goes-to-highest-ranked-card
+  (is (f ["4S 6C 7S 8D 5H"
+          "5S 7H 8S 9D 6H"]
+         ["5S 7H 8S 9D 6H"])))
+
+(deftest even-though-an-ace-is-usually-high-a-5-high-straight-is-the-lowest-scoring-straight
+  (is (f ["2H 3C 4D 5D 6H"
+          "4S AH 3S 2D 5H"]
+         ["2H 3C 4D 5D 6H"])))
+
+(deftest flush-beats-a-straight
+  (is (f ["4C 6H 7D 8D 5H"
+          "2S 4S 5S 6S 7S"]
+         ["2S 4S 5S 6S 7S"])))
+
+(deftest both-hands-have-a-flush-tie-goes-to-high-card-down-to-the-last-one-if-necessary
+  (is (f ["4H 7H 8H 9H 6H"
+          "2S 4S 5S 6S 7S"]
+         ["4H 7H 8H 9H 6H"])))
+
+(deftest full-house-beats-a-flush
+  (is (f ["3H 6H 7H 8H 5H"
+          "4S 5H 4C 5D 4H"]
+         ["4S 5H 4C 5D 4H"])))
+
+(deftest both-hands-have-a-full-house-tie-goes-to-highest-ranked-triplet
+  (is (f ["4H 4S 4D 9S 9D"
+          "5H 5S 5D 8S 8D"]
+         ["5H 5S 5D 8S 8D"])))
+
+(deftest with-multiple-decks-both-hands-have-a-full-house-with-the-same-triplet-tie-goes-to-the-pair
+  (is (f ["5H 5S 5D 9S 9D"
+          "5H 5S 5D 8S 8D"]
+         ["5H 5S 5D 9S 9D"])))
+
+(deftest four-of-a-kind-beats-a-full-house
+  (is (f ["4S 5H 4D 5D 4H"
+          "3S 3H 2S 3D 3C"]
+         ["3S 3H 2S 3D 3C"])))
+
+(deftest both-hands-have-four-of-a-kind-tie-goes-to-high-quad
+  (is (f ["2S 2H 2C 8D 2D"
+          "4S 5H 5S 5D 5C"]
+         ["4S 5H 5S 5D 5C"])))
+
+(deftest with-multiple-decks-both-hands-with-identical-four-of-a-kind-tie-determined-by-kicker
+  (is (f ["3S 3H 2S 3D 3C"
+          "3S 3H 4S 3D 3C"]
+         ["3S 3H 4S 3D 3C"])))
+
+(deftest straight-flush-beats-four-of-a-kind
+  (is (f ["4S 5H 5S 5D 5C"
+          "7S 8S 9S 6S 10S"]
+         ["7S 8S 9S 6S 10S"])))
+
+(deftest both-hands-have-straight-flush-tie-goes-to-highest-ranked-card
+  (is (f ["4H 6H 7H 8H 5H"
+          "5S 7S 8S 9S 6S"]
+         ["5S 7S 8S 9S 6S"])))