-
-
Save kindlychung/9f932ae4c9b752f87431 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
(t/check-ns 'typedclj.rps-async) | |
Start collecting typedclj.rps-async | |
Start collecting clojure.core.typed.async | |
Finished collecting clojure.core.typed.async | |
Finished collecting typedclj.rps-async | |
Collected 2 namespaces in 1435.241686 msecs | |
Not checking clojure.core.typed (does not depend on clojure.core.typed) | |
Not checking clojure.core.async (does not depend on clojure.core.typed) | |
Not checking clojure.core.async.impl.channels (does not depend on clojure.core.typed) | |
Not checking clojure.core.async.impl.ioc-macros (does not depend on clojure.core.typed) | |
Not checking clojure.core.async.impl.protocols (does not depend on clojure.core.typed) | |
Not checking clojure.core.async.impl.dispatch (does not depend on clojure.core.typed) | |
Not checking clojure.core.typed.util-vars (does not depend on clojure.core.typed) | |
Start checking clojure.core.typed.async | |
Checked clojure.core.typed.async in 165.176927 msecs | |
Start checking typed |
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
(defproject typedclj "0.1.0-SNAPSHOT" | |
:description "FIXME: write description" | |
:url "http://example.com/FIXME" | |
:license {:name "Eclipse Public License" | |
:url "http://www.eclipse.org/legal/epl-v10.html"} | |
:dependencies [[org.clojure/clojure "1.6.0"] | |
[org.clojure/core.async "0.1.346.0-17112a-alpha" :exclusions [org.clojure/tools.analyzer.jvm]] | |
[org.clojure/core.typed "0.2.92"] | |
[clj-http "1.1.2"] | |
[http-kit "2.1.18"] | |
] | |
:repl-options {:nrepl-middleware [clojure.core.typed.repl/wrap-clj-repl]} | |
:main ^:skip-aot typedclj.core | |
:target-path "target/%s" | |
:profiles {:uberjar {:aot :all}}) |
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 typedclj.rps-async | |
(:require [clojure.core.typed :as t] | |
[clojure.core.async :as a] | |
[clojure.core.typed.async :as ta])) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Types | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(t/defalias Move | |
"A legal move in rock-paper-scissors" | |
(t/U ':rock ':paper ':scissors)) | |
(t/defalias PlayerName | |
"A player's name in rock-paper-scissors" | |
t/Str) | |
(t/defalias PlayerMove | |
"A move in rock-paper-scissors. A Tuple of player name and move" | |
'[PlayerName Move]) | |
(t/defalias RPSResult | |
"The result of a rock-paper-scissors match. | |
A 3 place vector of the two player moves, and the winner" | |
'[PlayerMove PlayerMove PlayerName]) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Implementation | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(t/ann MOVES (t/Vec Move)) | |
(def MOVES [:rock :paper :scissors]) | |
(t/ann BEATS (t/Map Move Move)) | |
(def BEATS {:rock :scissors, :paper :rock, :scissors :paper}) | |
(t/ann rand-player [PlayerName -> (ta/Chan PlayerMove)]) | |
(defn rand-player | |
"Create a named player and return a channel to report moves." | |
[name] | |
(let [out (ta/chan :- PlayerMove)] | |
(ta/go (while true (a/>! out [name (rand-nth MOVES)]))) | |
out)) | |
(t/ann winner [PlayerMove PlayerMove -> PlayerName]) | |
(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)) | |
(t/ann judge [(ta/Chan PlayerMove) (ta/Chan PlayerMove) -> (ta/Chan RPSResult)]) | |
(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 (ta/chan :- RPSResult)] | |
(ta/go | |
(while true | |
(let [m1 (a/<! p1) | |
m2 (a/<! p2)] | |
(assert m1) | |
(assert m2) | |
(a/>! out (t/ann-form [m1 m2 (winner m1 m2)] | |
RPSResult))))) | |
out)) | |
(t/ann init (t/IFn [PlayerName PlayerName -> (ta/Chan RPSResult)] | |
[-> (ta/Chan RPSResult)])) | |
(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)))) | |
(t/ann report [PlayerMove PlayerMove PlayerName -> nil]) | |
(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!")) | |
(t/ann play [(ta/Chan RPSResult) -> nil]) | |
(defn play | |
"Play by taking a match reporting channel and reporting the results of the latest match." | |
[out-chan] | |
(let [[move1 move2 winner] (a/<!! out-chan)] | |
(assert move1) | |
(assert move2) | |
(assert winner) | |
(report move1 move2 winner))) | |
(t/ann play-many [(ta/Chan RPSResult) t/Int -> (t/Map t/Any t/Any)]) | |
(defn play-many | |
"Play n matches from out-chan and report a summary of the results." | |
[out-chan n] | |
(t/loop [remaining :- t/Int, n | |
results :- (t/Map PlayerName t/Int), {}] | |
(if (zero? remaining) | |
results | |
(let [[m1 m2 winner] (a/<!! out-chan)] | |
(assert m1) | |
(assert m2) | |
(assert winner) | |
(recur (dec remaining) | |
(merge-with + results {winner 1})))))) | |
(fn [] | |
(t/ann-form (a/<!! (init)) | |
(t/U nil RPSResult))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment