Skip to content

Instantly share code, notes, and snippets.

@alandipert
Created February 28, 2015 20:40
Show Gist options
  • Select an option

  • Save alandipert/90060e9c035e67a5a489 to your computer and use it in GitHub Desktop.

Select an option

Save alandipert/90060e9c035e67a5a489 to your computer and use it in GitHub Desktop.
(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