Skip to content

Instantly share code, notes, and snippets.

@oibot
Created July 23, 2016 14:42
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 oibot/53312327c11616386a797a2e5542d851 to your computer and use it in GitHub Desktop.
Save oibot/53312327c11616386a797a2e5542d851 to your computer and use it in GitHub Desktop.
(ns blackjack-helper.core
(:require [clojure.string :as str]
[clojure.set :as set])
(:gen-class))
(def H "HIT")
(def D "DOUBLE if allowed, otherwise HIT")
(def DS "DOUBLE if allowed, otherwise STAND")
(def S "STAND")
(def SP "SPLIT")
(def XH "SURRENDER if allowed, otherwise HIT")
(def XS "SURRENDER if allowed, otherwise STAND")
(def XP "SURRENDER if allowed, otherwise SPLIT")
(def B "BLACKJACK fool")
;; couldn't find strategies for 18, 19, 20. Make the assumption to always STAND
(def strategy-chart
{:8 {:2 H, :3 H, :4 H, :5 H, :6 H, :7 H, :8 H, :9 H, :10 H, :A H}
:9 {:2 H, :3 D, :4 D, :5 D, :6 D, :7 H, :8 H, :9 H, :10 H, :A H}
:10 {:2 D, :3 D, :4 D, :5 D, :6 D, :7 D, :8 D, :9 D, :10 H, :A H}
:11 {:2 D, :3 D, :4 D, :5 D, :6 D, :7 D, :8 D, :9 D, :10 D, :A D}
:12 {:2 H, :3 H, :4 S, :5 S, :6 S, :7 H, :8 H, :9 H, :10 H, :A H}
:13 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 H, :8 H, :9 H, :10 H, :A H}
:14 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 H, :8 H, :9 H, :10 H, :A H}
:15 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 H, :8 H, :9 H, :10 XH, :A XH}
:16 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 H, :8 H, :9 XH, :10 XH, :A XH}
:17 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A XS}
:18 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:19 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:20 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:A2 {:2 H, :3 H, :4 H, :5 D, :6 D, :7 H, :8 H, :9 H, :10 H, :A H}
:A3 {:2 H, :3 H, :4 H, :5 D, :6 D, :7 H, :8 H, :9 H, :10 H, :A H}
:A4 {:2 H, :3 H, :4 D, :5 D, :6 D, :7 H, :8 H, :9 H, :10 H, :A H}
:A5 {:2 H, :3 H, :4 D, :5 D, :6 D, :7 H, :8 H, :9 H, :10 H, :A H}
:A6 {:2 H, :3 D, :4 D, :5 D, :6 D, :7 H, :8 H, :9 H, :10 H, :A H}
:A7 {:2 S, :3 DS, :4 DS, :5 DS, :6 DS, :7 S, :8 S, :9 H, :10 H, :A H}
:A8 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:A9 {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:AT {:2 B, :3 B, :4 B, :5 B, :6 B, :7 B, :8 B, :9 B, :10 B, :A B}
:AJ {:2 B, :3 B, :4 B, :5 B, :6 B, :7 B, :8 B, :9 B, :10 B, :A B}
:AQ {:2 B, :3 B, :4 B, :5 B, :6 B, :7 B, :8 B, :9 B, :10 B, :A B}
:AK {:2 B, :3 B, :4 B, :5 B, :6 B, :7 B, :8 B, :9 B, :10 B, :A B}
:22 {:2 SP, :3 SP, :4 SP, :5 SP, :6 SP, :7 SP, :8 H, :9 H, :10 H, :A H}
:33 {:2 SP, :3 SP, :4 SP, :5 SP, :6 SP, :7 SP, :8 H, :9 H, :10 H, :A H}
:44 {:2 H, :3 H, :4 H, :5 SP, :6 SP, :7 H, :8 H, :9 H, :10 H, :A H}
:55 {:2 D, :3 D, :4 D, :5 D, :6 D, :7 D, :8 D, :9 D, :10 H, :A H}
:66 {:2 SP, :3 SP, :4 SP, :5 SP, :6 SP, :7 H, :8 H, :9 H, :10 H, :A H}
:77 {:2 SP, :3 SP, :4 SP, :5 SP, :6 SP, :7 SP, :8 H, :9 H, :10 H, :A H}
:88 {:2 SP, :3 SP, :4 SP, :5 SP, :6 SP, :7 SP, :8 SP, :9 SP, :10 SP, :A XP}
:99 {:2 SP, :3 SP, :4 SP, :5 SP, :6 SP, :7 S, :8 SP, :9 SP, :10 S, :A S}
:TT {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:JJ {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:QQ {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:KK {:2 S, :3 S, :4 S, :5 S, :6 S, :7 S, :8 S, :9 S, :10 S, :A S}
:AA {:2 SP, :3 SP, :4 SP, :5 SP, :6 SP, :7 SP, :8 SP, :9 SP, :10 SP, :A SP}})
;; The value for an ace is tentatively set to 11 and is corrected when
;; the hand value is calculated.
(def card-value
{"2" 2, "3" 3, "4" 4, "5" 5, "6" 6, "7" 7, "8" 8, "9" 9,
"T" 10, "J" 10, "Q" 10, "K" 10,
"A" 11})
(def blackjack 21)
(def sum-cards #(reduce + (map (comp card-value str) %)))
(defn num-aces
[hand]
((frequencies hand) \A))
(defn correct-for-aces
"Aces count 11 until the hand value is greater than 21. Then aces in the
hand are set successively to 1 until the hand value is less than 21."
[hand-value aces]
(if (and (> hand-value blackjack) (> aces 0))
(recur (- hand-value 10) (dec aces))
hand-value))
(defn hand-value
[hand]
(let [hand-value (sum-cards hand)]
(correct-for-aces hand-value (num-aces hand))))
(defn format-hand
[hand]
(->> hand
(str/upper-case)
(map str)
(sort-by card-value >)
(str/join)))
(defn hand-type
"Categorizes into hands with pairs, hands with two cards and an ace,
and other hands"
[[fst snd & others]]
(cond
(and (empty? others) (= fst snd)) :pair-hand
(and (empty? others) (= fst \A)) :ace-hand
:else :other-hand))
(defn hand->hero-key
"The hero key is determined as the keyword of the pair or ace hand or the
keyword of the hand value otherwise"
[hand]
(case (hand-type hand)
:pair-hand (keyword hand)
:ace-hand (keyword hand)
:other-hand (-> hand
hand-value
str
keyword)))
(defn hand->villain-key
"The villain key is determined as the keyword of the value of the hand or as the
keyword of the hand if it contains an ace"
[hand]
(if (str/includes? hand "A")
(keyword hand)
(keyword (str (hand-value hand)))))
(def cards "23456789TJQKA")
(def not-a-hand (str "Sorry, this is not a hand.\n"
"Allowed cards: 2, 3, 4, 5, 6, 7, 8, 9, T, J, Q, K, A."))
(defn prompt-hand
[role]
(do
(print (str role "'s hand: "))
(flush)
(let [input (read-line)]
(if (set/subset? (set input) (set cards))
input
(do
(println not-a-hand)
(recur role))))))
(def msg (str "Provide the hand of the hero and the hand of the dealer. "
"A strategy is then printed out for this combination.\n"
"Examples of a hand are: AK22, 22, etc."))
(defn -main
[& args]
(do
(println msg)
(loop []
(let [hero (hand->hero-key (format-hand (prompt-hand "Hero")))
dealer (hand->villain-key (format-hand (prompt-hand "Dealer")))]
(if-let [strategy (dealer (hero strategy-chart))]
(println strategy)
(println "You are on your own")))
(recur))))
@oibot
Copy link
Author

oibot commented Jul 23, 2016

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