HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Clojure Minesweeper from scratch

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
scratchfromclojureminesweeper

Problem

In order to exercise and learn Clojure, I decided to write a simple Minesweeper game from scratch. I'd consider myself as a Clojure novice and would be thankful if somebody could do a review or give me feedback on the code.

The full repository can be found here but I'd be also happy if somebody could have a look on the core functionalities at least:

board.clj

```
(ns minesweeper.board
(:use [clojure.pprint]))

(defn empty-board
"Create a rectangular empty board of
the specified with and height"
[w h]
(vec (repeat w (vec (repeat h {})))))

(defn to-coords
"Transform the board cells into coordinates"
([board]
(to-coords board (constantly true)))
([board pred]
(let [w (count board)
h (count (first board))]
(for [x (range w) y (range h) :when (pred (get-in board [x y]))]
[x y]))))

(defn neighbour-cells
"Locate neighbour cells based on coordinates [x y],
respecting board width and height"
[board [x y]]
(let [w (count board)
h (count (first board))]
(for [dx (map (partial + x) [-1 0 1])
dy (map (partial + y) [-1 0 1])
:when (and (or (not= x dx) (not= y dy))
(> w dx -1)
(> h dy -1))]
[dx dy])))

(defn warnings-freq [board]
"Count the number of nearby mines"
(let [mines (to-coords board :mine)
warnings (mapcat (partial neighbour-cells board) mines)]
(frequencies
(remove (set mines) warnings))))

(defn random-mines
[board start-pos]
(-> (set (to-coords board))
(disj start-pos)
(shuffle)))

(defn place-mines
"Place n mines randomly on the board"
[board mine-count start-pos]
(let [mines (take mine-count
(random-mines board start-pos))]
(reduce
(fn [m k]
(assoc-in m k {:mine true}))
board
mines)))

(defn place-warnings
"Place warnings on a mines' neighbour cells"
[board]
(let [mine-counts (warnings-freq board)]
(reduce-kv
(fn [m k v]

Solution

This is excellent. You have nice small functions, intent is clear, and the docstrings are helpful.

These are very minor suggestions:

(update-in board coords
         #(assoc % :flag (not (:flag %)))


Might be slightly more obvious as

(update-in board (conj coords :flag) not))


or

(update-in board coords update :flag not)


update is 1.7 only, but you could also use update-in [:flag]

I think this pred would be better promoted to a defn, and perhaps called something like boom

(letfn [(pred [m] (and (:mine m) (:explored m)))]


(especially since it is repeated 2x)

(disp/fire) might just be a multimethod?

Code Snippets

(update-in board coords
         #(assoc % :flag (not (:flag %)))
(update-in board (conj coords :flag) not))
(update-in board coords update :flag not)
(letfn [(pred [m] (and (:mine m) (:explored m)))]

Context

StackExchange Code Review Q#105448, answer score: 2

Revisions (0)

No revisions yet.