patternMinor
Creating and displaying a checkers board
Viewed 0 times
creatingdisplayingandboardcheckers
Problem
I am learning clojure this week end and just starting to develop a simple checkers engine. I currently coded some basic functions to create the board and display it. I would love to get some feedback !
(ns sandbox.checkers)
(def standard-size 10)
(defn empty-board [size]
(vec (replicate size (vec (replicate size :empty)))))
(defn str-piece [piece]
(cond
(= piece :empty) " "
(= piece :white_man) "O"
(= piece :black_man) "0"))
(defn str-board [board]
(str "\n"
(clojure.string/join
"\n"
(map
#(clojure.string/join " | " (map str-piece %))
board))))
(defn print-board [board]
(println (str-board board)))
(defn fill-white [size]
(apply comp
(map
(fn [pos]
(fn [board] (assoc-in board pos :white_man)))
(for [x (range size)
y (range (inc (/ size 2)) size)
:when (or (and (even? x) (even? y))
(and (odd? x) (odd? y)))]
[y x]))))
(defn fill-black [size]
(apply comp
(map
(fn [pos]
(fn [board] (assoc-in board pos :black_man)))
(for [x (range size)
y (range 0 (dec (/ size 2)))
:when (or (and (even? x) (even? y))
(and (odd? x) (odd? y)))]
[y x]))))
(defn starting-board [size]
((fill-black size) ((fill-white size) (empty-board size))))
(print-board (starting-board standard-size))Solution
A few small points
constants. Use
This gives us
Edited subsequently:
There are simpler ways to generate the lists of squares for
For a given row
A thorough reworking
The
It is simpler to describe the repetitive pattern using functions
Notice that the same row vectors are used again and again, not copies. This works in Clojure because vectors (and other native data structures) are immutable.
replicateis deprecated. Userepeatinstead.
- Use
-instead of_in names.
- The
condinstr-piececomparespieceagainst a number of
constants. Use
case instead.- Simplify the
:whenconditions to(= (even? x) (even? y))
This gives us
(ns sandbox.checkers)
(def standard-size 10)
(defn empty-board [size]
(vec (repeat size (vec (repeat size :empty)))))
(defn str-piece [piece]
(case piece
:empty " "
:white-man "O"
:black-man "0"))
(defn str-board [board]
(str "\n"
(clojure.string/join
"\n"
(map
#(clojure.string/join " | " (map str-piece %))
board))))
(defn print-board [board]
(println (str-board board)))
(defn fill-white [size]
(apply comp
(map
(fn [pos]
(fn [board] (assoc-in board pos :white-man)))
(for [x (range size)
y (range (inc (/ size 2)) size)
:when (= (even? x) (even? y))]
[y x]))))
(defn fill-black [size]
(apply comp
(map
(fn [pos]
(fn [board] (assoc-in board pos :black-man)))
(for [x (range size)
y (range 0 (dec (/ size 2)))
:when (= (even? x) (even? y))]
[y x]))))
(defn starting-board [size]
((fill-black size) ((fill-white size) (empty-board size))))
(print-board (starting-board standard-size))Edited subsequently:
There are simpler ways to generate the lists of squares for
fill-white and fill-black. For a given row
y, the required xs are (range (mod y 2) size 2). The functions become(defn fill-white [size]
(apply comp
(map
(fn [pos] (fn [board] (assoc-in board pos :white-man)))
(for [y (range (inc (/ size 2)) size)
x (range (mod y 2) size 2)]
[y x]))))
(defn fill-black [size]
(apply comp
(map
(fn [pos] (fn [board] (assoc-in board pos :black-man)))
(for [y (range 0 (dec (/ size 2)))
x (range (mod y 2) size 2)]
[y x]))))A thorough reworking
The
fill... functions construct and apply a sequence of functions, one function for each change to the empty board. It is simpler to describe the repetitive pattern using functions
cycle and take, with vec to convert to vectors: (defn starting-board [size]
(let [block (fn [rows piece]
(let [source (cycle [piece :empty])
row-pair (map (comp vec (partial take size))
[source (rest source)])]
(take rows (cycle row-pair))))
block-size (dec (quot size 2))]
(vec (concat (block block-size :black-man)
(block 2 :empty)
(block block-size :white-man)))))Notice that the same row vectors are used again and again, not copies. This works in Clojure because vectors (and other native data structures) are immutable.
Code Snippets
(ns sandbox.checkers)
(def standard-size 10)
(defn empty-board [size]
(vec (repeat size (vec (repeat size :empty)))))
(defn str-piece [piece]
(case piece
:empty " "
:white-man "O"
:black-man "0"))
(defn str-board [board]
(str "\n"
(clojure.string/join
"\n"
(map
#(clojure.string/join " | " (map str-piece %))
board))))
(defn print-board [board]
(println (str-board board)))
(defn fill-white [size]
(apply comp
(map
(fn [pos]
(fn [board] (assoc-in board pos :white-man)))
(for [x (range size)
y (range (inc (/ size 2)) size)
:when (= (even? x) (even? y))]
[y x]))))
(defn fill-black [size]
(apply comp
(map
(fn [pos]
(fn [board] (assoc-in board pos :black-man)))
(for [x (range size)
y (range 0 (dec (/ size 2)))
:when (= (even? x) (even? y))]
[y x]))))
(defn starting-board [size]
((fill-black size) ((fill-white size) (empty-board size))))
(print-board (starting-board standard-size))(defn fill-white [size]
(apply comp
(map
(fn [pos] (fn [board] (assoc-in board pos :white-man)))
(for [y (range (inc (/ size 2)) size)
x (range (mod y 2) size 2)]
[y x]))))
(defn fill-black [size]
(apply comp
(map
(fn [pos] (fn [board] (assoc-in board pos :black-man)))
(for [y (range 0 (dec (/ size 2)))
x (range (mod y 2) size 2)]
[y x]))))(defn starting-board [size]
(let [block (fn [rows piece]
(let [source (cycle [piece :empty])
row-pair (map (comp vec (partial take size))
[source (rest source)])]
(take rows (cycle row-pair))))
block-size (dec (quot size 2))]
(vec (concat (block block-size :black-man)
(block 2 :empty)
(block block-size :white-man)))))Context
StackExchange Code Review Q#115651, answer score: 4
Revisions (0)
No revisions yet.