# Connect Four: Bitboard checking algorithm

I'm rather new to Clojure and so I decided to program a Connect Four for fun and learning.

The code below is a Clojure implementation of this bitboard algorithm.

The whole code can be found here: https://gist.github.com/3639220

What I'm unsure about are the functions (insert) and (bit-check-board):

(defn insert
"Inserts symbol for given player (either 1 or 2) at specified x and
calls bit-insert for corresponding bitboard."
[boards x player-num]
(let [y (get-y (boards 0) x)]
(if (= player-num 1) ; TODO: improve
(vector
(assoc-in (boards 0) [y x] (player player-num))
(bit-insert (boards 1) (- 5 y) x)
(boards 2))
(vector
(assoc-in (boards 0) [y x] (player player-num))
(boards 1)
(bit-insert (boards 2) (- 5 y) x)))))

(defn bit-check-board ; TODO: improve
"Checks whether given bitboard is a win."
[bitboard]
(let [diag1 (bit-and bitboard (bit-shift-right bitboard 6))
hori  (bit-and bitboard (bit-shift-right bitboard 7))
diag2 (bit-and bitboard (bit-shift-right bitboard 8))
vert  (bit-and bitboard (bit-shift-right bitboard 1))]
(bit-or (bit-and diag1 (bit-shift-right diag1 (* 2 6)))
(bit-and hori  (bit-shift-right hori  (* 2 7)))
(bit-and diag2 (bit-shift-right diag2 (* 2 8)))
(bit-and vert  (bit-shift-right vert  (* 2 1))))))

1. insert: Is there a better way to somehow make function calls depend on some test?
2. bit-check-board: A lot of similar lines where just one number (and one variable name) is different.

The bit-check-board can be indeed improved. This is what I got by just joining together common parts, even though I guess it could be further improved:

(defn check [c x]
(bit-and c (bit-shift-right c x)))

(defn bit-check-board
"Checks whether given bitboard is a win."
[bitboard]
(let [positions [6 7 8 1]
coords (mapv (partial check bitboard) positions)]
(apply bit-or (map check coords (map #(* 2 %) positions)))))


Also, you can reduce the repetition in the insert function by better modularize the code and use higher order functions with a pre-calculated transformation table:

(defn insert* [board x y]
(bit-insert board (- 5 y) x))

(defn get-transforms [num]
(if (= 1 num)
[identity insert* identity]
[identity identity insert*]))

(defn insert
"Inserts symbol for given player (either 1 or 2) at specified x and
calls bit-insert for corresponding bitboard."
[boards x player-num]
(let [y (get-y (boards 0) x)
board0 (assoc-in (boards 0) [y x] (player player-num))
transfv (get-transforms player-num)]
(mapv [board0 (boards 1) (boards 2)] transv)))


If you're on Clojure < 1.4 than you have to change (mapv ...) in (vector (map ...))

• I understand what map(v), apply and partial do, but I just couldn't come up with what you did. My mind is not that functional it seems... I can't remember seeing identity before and for sure not in such a usage. I don't understand (mapv [board0 (boards 1) (boards 2)] transv) - mapv returns a vector of applying a vector containing the boards on a vector containing functions? o.O also: let binding is transfv and in mapv it's transv and insert* should take [board y x] instead of [board x y] and while writing that I realized that I have no clue where insert* actually get its parameters from?
– naeg
Sep 6 '12 at 12:32
• Your code seems not to work, I guess you meant something similar to this: (defn insert [boards x player-num] (let [y (get-y (boards 0) x) board0 (assoc-in (boards 0) [y x] (player player-num)) funcorder (if (= 1 player-num) [identity #(bit-insert % (- 5 y) x) identity] [identity identity #(bit-insert % (- 5 y) x)])] (mapv #(% %2) funcorder [board0 (boards 1) (boards 2)])))
– naeg
Sep 10 '12 at 20:01