Skip to content

Instantly share code, notes, and snippets.

@m0smith
Forked from puredanger/rps.clj
Last active December 19, 2015 16:59
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 m0smith/5988151 to your computer and use it in GitHub Desktop.
Save m0smith/5988151 to your computer and use it in GitHub Desktop.
(require 'clojure.core.async :refer :all)
(def MOVES [:rock :paper :scissors])
(def BEATS {:rock :scissors, :paper :rock, :scissors :paper})
(defn rand-player
"Create a named player and return a channel to report moves."
[name]
(let [out (chan)]
(go (while true (>! out [name (rand-nth MOVES)])))
out))
(defn winner
"Based on two moves, return the name of the winner."
[[name1 move1] [name2 move2]]
(cond
(= move1 move2) "no one"
(= move2 (BEATS move1)) name1
:else name2))
(defn judge
"Given two channels on which players report moves, create and return an
output channel to report the results of each match as [move1 move2 winner]."
[p1 p2]
(let [out (chan)]
(go
(while true
(let [m1 (<! p1)
m2 (<! p2)]
(>! out [m1 m2 (winner m1 m2)]))))
out))
(defn init
"Create 2 players (by default Alice and Bob) and return an output channel of match results."
([] (init "Alice" "Bob"))
([n1 n2] (judge (rand-player n1) (rand-player n2))))
(defn report
"Report results of a match to the console."
[[name1 move1] [name2 move2] winner]
(println)
(println name1 "throws" move1)
(println name2 "throws" move2)
(println winner "wins!"))
(defn play
"Play by taking a match reporting channel and reporting the results of the latest match."
[out-chan]
(apply report (<!! out-chan)))
(defn play-seq
"Play by taking a match reporting channel and reporting the results of the latest match."
([out-chan] (repeatedly #(<!! out-chan)))
([out-chan n] (repeatedly n #(<!! out-chan))))
(defn play-many [out-chan n]
(frequencies (map #(nth % 2) (play-seq out-chan n))))
(defn merge-result [ result [m1 m2 winner] ]
(merge-with + result { winner 1 }))
(defn play-many2 [out-chan n]
(reduce merge-result {} (take n (play-seq out-chan))))
(defn play-many-recur
"Play n matches from out-chan and report a summary of the results."
[out-chan n]
(loop [remaining n
results {}]
(if (zero? remaining)
results
(let [[m1 m2 winner] (<!! out-chan)]
(recur (dec remaining)
(merge-with + results {winner 1}))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment