Created
July 23, 2016 14:42
-
-
Save oibot/53312327c11616386a797a2e5542d851 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Compiled in a jar package: https://dl.dropboxusercontent.com/u/1246687/blackjack-helper-0.1.0-SNAPSHOT-standalone.jar