Created
February 28, 2015 20:40
-
-
Save alandipert/90060e9c035e67a5a489 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| (page "index.html" | |
| (:require [tailrecursion.hoplon.reload :refer [reload-all]] | |
| [clojure.set :refer [intersection]])) | |
| (reload-all 0) | |
| (defn random-mines [size n] | |
| (loop [mines #{}] | |
| (if (< (count mines) n) | |
| (recur (conj mines [(rand-int size) (rand-int size)])) | |
| mines))) | |
| (defn neighbors [[x y]] | |
| (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])] | |
| [(+ dx x) (+ dy y)])) | |
| (defn mines-around [mines point] | |
| (count (intersection mines (set (neighbors point))))) | |
| (defn numberfield | |
| [mines size] | |
| (reduce (partial merge-with merge) | |
| (for [x (range size), y (range size) | |
| :when (not (contains? mines [x y]))] | |
| {x {y (mines-around mines [x y])}}))) | |
| (defn new-game | |
| [size n-mines] | |
| (let [mines (random-mines size n-mines)] | |
| {:mines mines | |
| :numberfield (numberfield mines size) | |
| :revealed #{} | |
| :flagged #{} | |
| :size size | |
| :n-mines n-mines})) | |
| (defn mine? [g point] (contains? (:mines g) point)) | |
| (defn number [g [x y]] (get-in g [:numberfield x y])) | |
| (defn flag? [g point] (contains? (:flagged g) point)) | |
| (defn revealed? [g point] (contains? (:revealed g) point)) | |
| (def +size+ 9) | |
| (def +axis+ (range +size+)) | |
| (def +n-mines+ 10) | |
| (defc game (new-game +size+ +n-mines+)) | |
| (defc= lost? (not (empty? (intersection (:mines game) (:revealed game))))) | |
| (defc= won? (= (:mines game) (:flagged game))) | |
| (defc= flagged (intersection (:mines game) (:flagged game))) | |
| (defc= over? (or lost? won?)) | |
| (defc= playing? (not over?)) | |
| (defc= hide-point? (fn [point] | |
| (and playing? | |
| (not (revealed? game point)) | |
| (not (flag? game point))))) | |
| (defc= label-point (fn [hidden-fn show-fn point] | |
| (if (hide-point? point) | |
| (hidden-fn game point) | |
| (show-fn game point)))) | |
| (defn reveal [g point] | |
| (-> (update-in g [:revealed] conj point) | |
| (update-in [:flagged] disj point))) | |
| (defn flag [g point] | |
| (cond | |
| (revealed? g point) g | |
| (flag? g point) (update-in g [:flagged] disj point) | |
| :else (update-in g [:flagged] conj point))) | |
| (defn new! [] | |
| (reset! game (new-game +size+ +n-mines+))) | |
| (defn tap! [point] | |
| (if @playing? | |
| (swap! game reveal point) | |
| (new!))) | |
| (defn taphold! [point] | |
| (when @playing? | |
| (swap! game flag point))) | |
| (defn number-color [n] | |
| (cond (< n 2) "blue" | |
| (< n 3) "green" | |
| :else "red")) | |
| (defn format [g point] | |
| (cond | |
| (flag? g point) {:label "âš‘" :class "red"} | |
| (mine? g point) {:label "!" :class "red"} | |
| :else (let [n (number g point)] | |
| {:label (str n) :class (number-color n)}))) | |
| (defn format-hidden [g point] {:label "?" :class "light"}) | |
| (defmethod do! :set-class | |
| [elem _ class] | |
| (doto (js/jQuery elem) .removeClass (.addClass class))) | |
| (set! (.. js/jQuery -event -special -tap -emitTapOnTaphold) false) | |
| (set! (.. js/jQuery -event -special -tap -tapholdThreshold) 500) | |
| (html | |
| (head | |
| (title "Minesweeper")) | |
| (body | |
| (table | |
| :id "grid" | |
| :class "noselect" | |
| (for [i +axis+] | |
| (tr | |
| (for [j +axis+ :let [point [i j]]] | |
| (cell-let [place (label-point format-hidden format point)] | |
| (td | |
| :taphold #(taphold! point) | |
| :tap #(tap! point) | |
| :set-class (cell= (:class place)) | |
| (text "~{(:label place)}"))))))) | |
| (div | |
| :id "footer" | |
| :toggle over? | |
| (span | |
| :id "face" | |
| :tap #(new!) | |
| (cell= (if won? "☺" "☹")))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment