There is still some room for improvement, but it comes as diminishing returns and with added complexity. I'll think I'll leave this code as it is for now and maybe forever.
Code: Select all
;;; Bitboard representation
(defconstant board-word-limit (/ sq-limit word-bit-limit))
(deftype type-bb () '(simple-vector 4))
(declaim (type (function () type-bb) mk-bb))
(defun mk-bb () (vector 0 0 0 0))
;;; Bitboard square set/reset/test
(declaim (type (function (type-bb fixnum) t) set-sq))
(defun set-sq (my-bb my-sq)
"Set a square in a bitboard."
(declare (type type-bb my-bb) (type fixnum my-sq))
(let ((wi (ash my-sq -4)))
(declare (type fixnum wi))
(setf
(svref my-bb wi)
(the fixnum
(logior
(the fixnum (svref my-bb wi))
(the fixnum (ash 1 (the fixnum (logand my-sq #x0f)))))))))
(declaim (type (function (type-bb fixnum) t) reset-sq))
(defun reset-sq (my-bb my-sq)
"Reset a square in a bitboard."
(declare (type type-bb my-bb) (type fixnum my-sq))
(let ((wi (ash my-sq -4)))
(declare (type fixnum wi))
(setf
(svref my-bb wi)
(the fixnum
(logandc2
(the fixnum (svref my-bb wi))
(the fixnum (ash 1 (the fixnum (logand my-sq #x0f)))))))))
(declaim (type (function (type-bb fixnum) t) sq-set?))
(defun sq-set? (my-bb my-sq)
"Test a square in a bitboard."
(declare (type type-bb my-bb) (type fixnum my-sq))
(bit?
(the fixnum (logand my-sq #x0f))
(the fixnum (svref my-bb (the fixnum (ash my-sq -4))))))
(declaim (type (function (type-bb fixnum) t) sq-reset?))
(defun sq-reset? (my-bb my-sq)
"Test a square in a bitboard; return inverted sense."
(declare (type type-bb my-bb) (type fixnum my-sq))
(not
(bit?
(the fixnum (logand my-sq #x0f))
(the fixnum (svref my-bb (the fixnum (ash my-sq -4)))))))
;;; Bitboard boolean operations
(declaim (type (function (type-bb) type-bb) bb-not))
(defun bb-not (my-bb)
(declare (type type-bb my-bb))
"Perform boolean complement of a single bitboard."
(let ((result (mk-bb)))
(declare (type type-bb result))
(setf (svref result 0) (logxor (the fixnum (svref my-bb 0)) #xffff))
(setf (svref result 1) (logxor (the fixnum (svref my-bb 1)) #xffff))
(setf (svref result 2) (logxor (the fixnum (svref my-bb 2)) #xffff))
(setf (svref result 3) (logxor (the fixnum (svref my-bb 3)) #xffff))
result))
(declaim (type (function (type-bb type-bb) type-bb) bb-or2))
(defun bb-or2 (my-bb0 my-bb1)
"Perform boolean sum of two bitboards."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(let ((result (mk-bb)))
(declare (type type-bb result))
(setf (svref result 0) (logior (the fixnum (svref my-bb0 0)) (the fixnum (svref my-bb1 0))))
(setf (svref result 1) (logior (the fixnum (svref my-bb0 1)) (the fixnum (svref my-bb1 1))))
(setf (svref result 2) (logior (the fixnum (svref my-bb0 2)) (the fixnum (svref my-bb1 2))))
(setf (svref result 3) (logior (the fixnum (svref my-bb0 3)) (the fixnum (svref my-bb1 3))))
result))
(declaim (type (function (type-bb type-bb) type-bb) bb-or2d))
(defun bb-or2d (my-bb0 my-bb1)
"Perform boolean sum of two bitboards; store result into the first."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(progn
(setf (svref my-bb0 0) (logior (the fixnum (svref my-bb0 0)) (the fixnum (svref my-bb1 0))))
(setf (svref my-bb0 1) (logior (the fixnum (svref my-bb0 1)) (the fixnum (svref my-bb1 1))))
(setf (svref my-bb0 2) (logior (the fixnum (svref my-bb0 2)) (the fixnum (svref my-bb1 2))))
(setf (svref my-bb0 3) (logior (the fixnum (svref my-bb0 3)) (the fixnum (svref my-bb1 3))))
my-bb0))
(declaim (type (function (type-bb type-bb) type-bb) bb-and2))
(defun bb-and2 (my-bb0 my-bb1)
"Perform boolean product of two bitboards."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(let ((result (mk-bb)))
(declare (type type-bb result))
(setf (svref result 0) (logand (the fixnum (svref my-bb0 0)) (the fixnum (svref my-bb1 0))))
(setf (svref result 1) (logand (the fixnum (svref my-bb0 1)) (the fixnum (svref my-bb1 1))))
(setf (svref result 2) (logand (the fixnum (svref my-bb0 2)) (the fixnum (svref my-bb1 2))))
(setf (svref result 3) (logand (the fixnum (svref my-bb0 3)) (the fixnum (svref my-bb1 3))))
result))
(declaim (type (function (type-bb type-bb) type-bb) bb-and2d))
(defun bb-and2d (my-bb0 my-bb1)
"Perform boolean product of two bitboards; store result into the first."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(progn
(setf (svref my-bb0 0) (logand (the fixnum (svref my-bb0 0)) (the fixnum (svref my-bb1 0))))
(setf (svref my-bb0 1) (logand (the fixnum (svref my-bb0 1)) (the fixnum (svref my-bb1 1))))
(setf (svref my-bb0 2) (logand (the fixnum (svref my-bb0 2)) (the fixnum (svref my-bb1 2))))
(setf (svref my-bb0 3) (logand (the fixnum (svref my-bb0 3)) (the fixnum (svref my-bb1 3))))
my-bb0))
(declaim (type (function (type-bb type-bb) type-bb) bb-and2c2))
(defun bb-and2c2 (my-bb0 my-bb1)
"Perform boolean product of two bitboards (complement 2nd)."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(let ((result (mk-bb)))
(declare (type type-bb result))
(setf (svref result 0) (logandc2 (the fixnum (svref my-bb0 0)) (the fixnum (svref my-bb1 0))))
(setf (svref result 1) (logandc2 (the fixnum (svref my-bb0 1)) (the fixnum (svref my-bb1 1))))
(setf (svref result 2) (logandc2 (the fixnum (svref my-bb0 2)) (the fixnum (svref my-bb1 2))))
(setf (svref result 3) (logandc2 (the fixnum (svref my-bb0 3)) (the fixnum (svref my-bb1 3))))
result))
(declaim (type (function (type-bb type-bb) type-bb) bb-and2c2d))
(defun bb-and2c2d (my-bb0 my-bb1)
"Perform boolean product of two bitboards (complement 2nd); store result into the first."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(progn
(setf (svref my-bb0 0) (logandc2 (the fixnum (svref my-bb0 0)) (the fixnum (svref my-bb1 0))))
(setf (svref my-bb0 1) (logandc2 (the fixnum (svref my-bb0 1)) (the fixnum (svref my-bb1 1))))
(setf (svref my-bb0 2) (logandc2 (the fixnum (svref my-bb0 2)) (the fixnum (svref my-bb1 2))))
(setf (svref my-bb0 3) (logandc2 (the fixnum (svref my-bb0 3)) (the fixnum (svref my-bb1 3))))
my-bb0))
(declaim (type (function (type-bb type-bb type-bb) type-bb) bb-and3))
(defun bb-and3 (my-bb0 my-bb1 my-bb2)
"Perform boolean product of three bitboards."
(declare (type type-bb my-bb0) (type type-bb my-bb1) (type type-bb my-bb2))
(let ((result (mk-bb)))
(declare (type type-bb result))
(setf
(svref result 0)
(logand
(the fixnum (svref my-bb0 0))
(the fixnum (svref my-bb1 0))
(the fixnum (svref my-bb2 0))))
(setf
(svref result 1)
(logand
(the fixnum (svref my-bb0 1))
(the fixnum (svref my-bb1 1))
(the fixnum (svref my-bb2 1))))
(setf
(svref result 2)
(logand
(the fixnum (svref my-bb0 2))
(the fixnum (svref my-bb1 2))
(the fixnum (svref my-bb2 2))))
(setf
(svref result 3)
(logand
(the fixnum (svref my-bb0 3))
(the fixnum (svref my-bb1 3))
(the fixnum (svref my-bb2 3))))
result))
(declaim (type (function (type-bb type-bb type-bb) type-bb) bb-and3d))
(defun bb-and3d (my-bb0 my-bb1 my-bb2)
"Perform boolean product of three bitboards; store result into the first."
(declare (type type-bb my-bb0) (type type-bb my-bb1) (type type-bb my-bb2))
(progn
(setf
(svref my-bb0 0)
(logand
(the fixnum (svref my-bb0 0))
(the fixnum (svref my-bb1 0))
(the fixnum (svref my-bb2 0))))
(setf
(svref my-bb0 1)
(logand
(the fixnum (svref my-bb0 1))
(the fixnum (svref my-bb1 1))
(the fixnum (svref my-bb2 1))))
(setf
(svref my-bb0 2)
(logand
(the fixnum (svref my-bb0 2))
(the fixnum (svref my-bb1 2))
(the fixnum (svref my-bb2 2))))
(setf
(svref my-bb0 3)
(logand
(the fixnum (svref my-bb0 3))
(the fixnum (svref my-bb1 3))
(the fixnum (svref my-bb2 3))))
my-bb0))
;;; Bitboard square scanning
(declaim (type (function (type-bb) t) first-sq))
(defun first-sq (my-bb)
"Return the index of the first bit in a bitboard; return nil if none."
(declare (type type-bb my-bb))
(let ((result nil) (index nil))
(setf index (first-bit-in-word (the fixnum (svref my-bb 0))))
(if index
(setf result (the fixnum index))
(progn
(setf index (first-bit-in-word (the fixnum (svref my-bb 1))))
(if index
(setf result (the fixnum (+ (the fixnum index) 16)))
(progn
(setf index (first-bit-in-word (the fixnum (svref my-bb 2))))
(if index
(setf result (the fixnum (+ (the fixnum index) 32)))
(progn
(setf index (first-bit-in-word (the fixnum (svref my-bb 3))))
(if index
(setf result (the fixnum (+ (the fixnum index) 48))))))))))
result))
(declaim (type (function (type-bb) t) next-sq))
(defun next-sq (my-bb)
"Return the index of the first bit in a bitboard and clear; return nil if none."
(declare (type type-bb my-bb))
(let ((result (first-sq my-bb)))
(when result
(reset-sq my-bb result))
result))
;;; Iteration
(defmacro loop-bb ((my-bb my-sq) &body my-body)
"Destructively iterate through the set squares in a bitboard."
`(do ((,my-sq (next-sq ,my-bb) (next-sq ,my-bb))) ((not ,my-sq))
(declare (type type-bb ,my-bb))
,@my-body))
;;; Reset and reset tests
(declaim (type (function (type-bb) t) reset-bb))
(defun reset-bb (my-bb)
(declare (type type-bb my-bb))
"Reset a bitboard."
(progn
(setf (svref my-bb 0) 0)
(setf (svref my-bb 1) 0)
(setf (svref my-bb 2) 0)
(setf (svref my-bb 3) 0)))
(declaim (type (function (type-bb) t) bb-empty?))
(defun bb-empty? (my-bb)
"Return t if the given bitboard is reset (e.g. empty)."
(declare (type type-bb my-bb))
(and
(zero? (the fixnum (svref my-bb 0)))
(zero? (the fixnum (svref my-bb 1)))
(zero? (the fixnum (svref my-bb 2)))
(zero? (the fixnum (svref my-bb 3)))))
(declaim (type (function (type-bb) t) bb-not-empty?))
(defun bb-not-empty? (my-bb)
"Return t if the given bitboard is not empty."
(declare (type type-bb my-bb))
(or
(nonzero? (the fixnum (svref my-bb 0)))
(nonzero? (the fixnum (svref my-bb 1)))
(nonzero? (the fixnum (svref my-bb 2)))
(nonzero? (the fixnum (svref my-bb 3)))))
(declaim (type (function (type-bb type-bb) t) bb-ni2?))
(defun bb-ni2? (my-bb0 my-bb1)
"Return t if the two given bitboards form a null intersection."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(and
(zero? (logand (the fixnum (svref my-bb0 0)) (the fixnum (svref my-bb1 0))))
(zero? (logand (the fixnum (svref my-bb0 1)) (the fixnum (svref my-bb1 1))))
(zero? (logand (the fixnum (svref my-bb0 2)) (the fixnum (svref my-bb1 2))))
(zero? (logand (the fixnum (svref my-bb0 3)) (the fixnum (svref my-bb1 3))))))
(declaim (type (function (type-bb type-bb type-bb) t) bb-ni3?))
(defun bb-ni3? (my-bb0 my-bb1 my-bb2)
"Return t if the three given bitboards form a null intersection."
(declare (type type-bb my-bb0) (type type-bb my-bb1) (type type-bb my-bb2))
(and
(zero?
(logand
(the fixnum (svref my-bb0 0))
(the fixnum (svref my-bb1 0))
(the fixnum (svref my-bb2 0))))
(zero?
(logand
(the fixnum (svref my-bb0 1))
(the fixnum (svref my-bb1 1))
(the fixnum (svref my-bb2 1))))
(zero?
(logand
(the fixnum (svref my-bb0 2))
(the fixnum (svref my-bb1 2))
(the fixnum (svref my-bb2 2))))
(zero?
(logand
(the fixnum (svref my-bb0 3))
(the fixnum (svref my-bb1 3))
(the fixnum (svref my-bb2 3))))))
;;; Bitboard cardinality
(declaim (type (function (type-bb) fixnum) bb-card))
(defun bb-card (my-bb)
"Cardinality: count the number of squares set in a bitboard."
(declare (type type-bb my-bb))
(+
(the fixnum (count-bits-in-word (the fixnum (svref my-bb 0))))
(the fixnum (count-bits-in-word (the fixnum (svref my-bb 1))))
(the fixnum (count-bits-in-word (the fixnum (svref my-bb 2))))
(the fixnum (count-bits-in-word (the fixnum (svref my-bb 3))))))
;;; Bitboard equality
(declaim (type (function (type-bb type-bb) t) bb-equal?))
(defun bb-equal? (my-bb0 my-bb1)
"Return t if the given bitboards are equal (e.g. same squares)."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(and
(= (svref my-bb0 0) (svref my-bb1 0))
(= (svref my-bb0 1) (svref my-bb1 1))
(= (svref my-bb0 2) (svref my-bb1 2))
(= (svref my-bb0 3) (svref my-bb1 3))))
(declaim (type (function (type-bb type-bb) t) bb-not-equal?))
(defun bb-not-equal? (my-bb0 my-bb1)
"Return t if the given bitboards are not equal (e.g. different squares)."
(declare (type type-bb my-bb0) (type type-bb my-bb1))
(or
(/= (svref my-bb0 0) (svref my-bb1 0))
(/= (svref my-bb0 1) (svref my-bb1 1))
(/= (svref my-bb0 2) (svref my-bb1 2))
(/= (svref my-bb0 3) (svref my-bb1 3))))
;;; Cloning and copying
(declaim (type (function (type-bb) type-bb) clone-bb))
(defun clone-bb (my-bb)
"Return a clone of the given bitboard."
(declare (type type-bb my-bb))
(vector (svref my-bb 0) (svref my-bb 1) (svref my-bb 2) (svref my-bb 3)))
(defun copy-bb (my-target-bb my-source-bb)
"Copy the given bitboard."
(declare (type type-bb my-target-bb) (type type-bb my-source-bb))
(setf (svref my-target-bb 0) (svref my-source-bb 0))
(setf (svref my-target-bb 1) (svref my-source-bb 1))
(setf (svref my-target-bb 2) (svref my-source-bb 2))
(setf (svref my-target-bb 3) (svref my-source-bb 3)))
;;; Bitboard color reversal
(declaim (type (function (type-bb) type-bb) flip-bb))
(defun flip-bb (my-bb)
"Return a color reversed bitboard."
(declare (type type-bb my-bb))
(let ((result (mk-bb)))
(declare (type type-bb result))
(dosqs (sq)
(when (sq-set? my-bb (flip-sq sq))
(set-sq result sq)))
result))
(defun flip-bbs (my-bbs) (mapcar #'flip-bb my-bbs))
;;; Reset vectors of bitboards
(defun reset-bb-vec (my-bb-vec)
"Reset a bitboard vector."
(let ((limit (array-total-size my-bb-vec)))
(dotimes (index limit)
(reset-bb (svref my-bb-vec index)))))
;;; Bitboard encoding
(defun encode-bb (my-stream my-bb)
"Encode a bitboard on a stream."
(declare (type type-bb my-bb))
(dosqs (sq)
(put-integer my-stream (if (sq-set? my-bb sq) 1 0)))
(values))
(defun encode-bb-alt (my-stream my-bb)
"Encode a bitboard on a stream with brackets and square names."
(declare (type type-bb my-bb))
(let ((needspace nil))
(fmt-brack-l my-stream)
(dosqs (sq)
(when (sq-set? my-bb sq)
(when needspace
(blank my-stream))
(encode-sq my-stream sq)
(setf needspace t)))
(fmt-brack-r my-stream))
(values))
(defun encode-bb-big (my-stream my-bb)
"Encode a bitboard on a stream with brackets and square names or spaces."
(declare (type type-bb my-bb))
(fmt-brack-l my-stream)
(dosqs (sq)
(if (sq-set? my-bb sq)
(encode-sq my-stream sq)
(put-string my-stream " ")))
(fmt-brack-r my-stream)
(values))
;;; Bitboard/square list conversions
(defun map-bb-to-sqs (my-bb)
"Generate a square list (ordered) from a bitboard."
(declare (type type-bb my-bb))
(let ((result nil) (bb (clone-bb my-bb)))
(declare (type type-bb bb))
(loop-bb (bb sq)
(push sq result))
(nreverse result)))
(defun map-sqs-to-bb (my-sqs)
"Generate a bitboard from a square list."
(let ((result (mk-bb)))
(declare (type type-bb result))
(dolist (sq my-sqs)
(set-sq result sq))
result))
;;; Bitboard vector construction
(defun mk-bb-vec (my-limit)
"Return a bitboard vector with all elements reset."
(let ((result (make-array my-limit)))
(dotimes (index my-limit)
(setf (svref result index) (mk-bb)))
result))
(defun clone-bb-vec (my-bb-vec)
"Return a clone of the given bitboard vector."
(let* ((limit (array-total-size my-bb-vec)) (result (make-array limit)))
(dotimes (index (array-total-size my-bb-vec))
(setf (svref result index) (clone-bb (svref my-bb-vec index))))
result))
(defun clone-bb-vecs (my-bb-vecs) (mapcar #'clone-bb-vec my-bb-vecs))
