Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add presentation and org file with (labrepl) solution.

  • Loading branch information...
commit 6616eacabccc5033221fe876e1fdfc02e0d8380d 1 parent 7898f84
@ck ck authored
Showing with 163 additions and 0 deletions.
  1. BIN  OO-Clojure.pdf
  2. +163 −0 rock_paper_scissors.org
View
BIN  OO-Clojure.pdf
Binary file not shown
View
163 rock_paper_scissors.org
@@ -0,0 +1,163 @@
+* Rock Paper Scissors
+
+** Setup
+
+First define the namespace and require the necessary libraries.
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (ns oo-clj.rock-paper-scissors)
+#+end_src
+
+** The Rules
+
+The rules are pretty simple: Rock beats scissors, scissors beats paper, and paper beats rock.
+
+Write an idiomatic Clojure function `dominates` that returns the thing that dominates the argument passed in.
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (def dominates
+ {:rock :paper
+ :scissors :rock
+ :paper :scissors})
+#+end_src
+
+Create a `choices` set that contains the possible choices.
+Don't Repeat Yourself.
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (def choices (set (keys dominates)))
+#+end_src
+
+Create a `winner` function that takes two players' choices,
+and returns the winner, or `nil` for a tie.
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defn winner
+ [choice1 choice2]
+ (cond
+ (= choice1 choice2) nil
+ (= (dominates choice1) choice2) choice2
+ :else choice1))
+#+end_src
+
+Create a `draw?` predicate that takes two players' choices
+and returns true if they are a draw
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defn draw?
+ [me you]
+ (= me you))
+#+end_src
+
+Create an `iwon?` predicate that takes two players' choices
+and returns true if the first player won.
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defn iwon?
+ [me you]
+ (= (winner me you) me))
+#+end_src
+
+
+** The Players
+
+All the players will conform to a `Player` protocol. It should have two methods:
+
+1. `choose`: takes a player and returns that player's choice
+2. `update-strategy`: takes a player, that player's last choice, and the other player's last choice, returning the `Player` for the next round.
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defprotocol Player
+ (choose [this])
+ (update-strategy [this me you]))
+#+end_src
+
+The random player always picks at random, and never changes
+strategy based on what the other player is doing:
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defn random-choice []
+ "Random choice"
+ (nth (vec choices) (rand-int (count choices))))
+
+ (defrecord Random []
+ Player
+ (choose [_] (random-choice))
+ (update-strategy [this me you] this))
+#+end_src
+
+The stubborn player is initialized with a choice and never
+changes it:
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defrecord Stubborn [choice]
+ Player
+ (choose [_] choice)
+ (update-strategy [this me you] this))
+#+end_src
+
+The mean player sticks with what worked last time,
+or plays at random following a loss:
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defrecord Mean [last-winner]
+ Player
+ (choose [_] (or last-winner (random-choice)))
+ (update-strategy [_ me you] (Mean. (when (iwon? me you) me))))
+#+end_src
+
+The copycat player picks the opponents last choice or plays at random:
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defrecord CopycatPlayer [choice]
+ Player
+ (choose [_]
+ (if choice choice (random-choice)))
+ (update-strategy [_ player-last-choice opponent-last-choice]
+ (CopycatPlayer. opponent-last-choice)))
+#+end_src
+
+The cycle player simply cycles through the available choices:
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defrecord CyclePlayer [choices-seq]
+ Player
+ (choose [_] (first choices-seq))
+ (update-strategy [_ _ _] (CyclePlayer. (rest choices-seq))))
+#+end_src
+
+** The Game
+
+To play, create a `game` function with three arguments:
+two players and a number of rounds.
+
+It reads nicely as a loop with five arguments:"
+
+1. Player 1
+2. Player 2
+3. Player 1's current score
+4. Player 2's current score
+5. Number of rounds remaining
+
+Have the `game` return the two player's scores in a map.
+
+#+begin_src clojure :tangle src/oo_clj/rock_paper_scissors.clj
+ (defn game
+ [p1 p2 rounds]
+ (loop [p1 p1
+ p2 p2
+ p1-score 0
+ p2-score 0
+ rounds rounds]
+ (if (pos? rounds)
+ (let [p1-choice (choose p1)
+ p2-choice (choose p2)
+ result (winner p1-choice p2-choice)]
+ (recur
+ (update-strategy p1 p1-choice p2-choice)
+ (update-strategy p2 p2-choice p1-choice)
+ (+ p1-score (if (= result p1-choice) 1 0))
+ (+ p2-score (if (= result p2-choice) 1 0))
+ (dec rounds)))
+ {:p1 p1-score :p2 p2-score})))
+#+end_src
Please sign in to comment.
Something went wrong with that request. Please try again.