Skip to content

Instantly share code, notes, and snippets.

@unrealhoang
Created January 26, 2015 17:30
Show Gist options
  • Save unrealhoang/9e38d4b43b50db8933bd to your computer and use it in GitHub Desktop.
Save unrealhoang/9e38d4b43b50db8933bd to your computer and use it in GitHub Desktop.
(ns minesweeper.core
(:require [reagent.core :as reagent :refer [atom]]))
(def rows 30)
(def cols 30)
(def bombs 30)
(def mine-map (atom ()))
(def state-map (atom ()))
;; ------------------------
;; Pure functions
(defn reset-state-map []
(into [] (for [x (range rows)]
(into [] (for [y (range cols)] :close)))))
(defn generate-mine-map []
(into [] (for [x (range rows)]
(into [] (for [y (range cols)]
(if (< (rand-int (* rows cols)) bombs) :bomb :empty)
)
))))
(defn matrix-indexed-map [f matrix]
(map-indexed
(fn [row-idx row]
(map-indexed
(fn [col-idx value] (f row-idx col-idx value))
row))
matrix)
)
(defn matrix-indexed-apply [f matrix]
(map-indexed
(fn [row-idx row]
(map-indexed
(fn [col-idx value] (f matrix row-idx col-idx))
row))
matrix)
)
(defn get-matrix-value [matrix x y default]
(try
(-> matrix
(nth x)
(nth y))
(catch js/Object e default))
)
(defn valid-index? [x y]
(and (>= x 0) (>= y 0) (< x rows) (< y cols))
)
(def neighbor-indexes
(memoize (fn [x y]
(for [xi (map #(+ x %1) [-1 0 1])
yi (map #(+ y %1) [-1 0 1]) :when (valid-index? xi yi)]
[xi yi]
))
))
(defn neighbor-values [matrix x y]
(for [[xi yi] (neighbor-indexes x y)]
(get-matrix-value matrix xi yi :empty))
)
(defn count-neighbor [matrix x y]
(if (= (get-matrix-value matrix x y :empty) :bomb)
:bomb
(->> (neighbor-values matrix x y)
(filter #(= %1 :bomb))
count)
)
)
(def radar (memoize (fn [mine-map]
(matrix-indexed-apply count-neighbor mine-map)
)))
;; -------------------------
;; Event Handlers
(defn start-game []
(swap! mine-map #(radar (generate-mine-map)))
(swap! state-map reset-state-map)
)
(defn open-cell [x y]
(when-not (= (get-matrix-value @state-map x y :close) :opened)
(swap! state-map #(assoc-in %1 [x y] :opened))
(if (= (get-matrix-value @mine-map x y 0) 0)
(doall (for [[xi yi] (neighbor-indexes x y)]
(open-cell xi yi)))
)
nil
)
)
;; -------------------------
;; Views
(defn mine-cell [x y data]
(let
[state (get-matrix-value @state-map x y :close)
cell-value (if (= state :close)
" "
(case data
:bomb "*"
0 " "
(str data))
)
opened? (= state :opened)
class-name (str (if opened? "opened") " "
(if (= data 0) "empty"))]
[:td [:button {:class class-name
:on-click #(open-cell x y)
:disabled opened? } cell-value]]
)
)
(defn mine-field []
[:table
(map-indexed
(fn [row-idx row]
[:tr (map-indexed
(fn [col-idx value] ^{:key [row-idx col-idx]} [mine-cell row-idx col-idx value])
row)])
@mine-map)
]
)
(defn app []
[:div
[:h2 "Welcome to MineSweeper"]
[:button {:on-click start-game} "Start"]
[:div [mine-field]
]])
;; -------------------------
;; Initialize app
(defn init! []
(reagent/render-component [app] (.getElementById js/document "app")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment