Created
January 26, 2015 17:30
-
-
Save unrealhoang/9e38d4b43b50db8933bd 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
(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