Search code examples
javaclojurechess

How should I represent a chess bitboard in clojure?


What are some of the possible ways of representing a chess bitboard in Clojure (/Java)?

http://pages.cs.wisc.edu/~psilord/blog/data/chess-pages/rep.html

I need to be able to access individual bits and also perform bitwise operations.

I thought of using java.lang.Long but this causes issues with 1x10^63 because of the signage. I'm also not sure how I would access bits at a specific index?

I also looked at BitSet, but I need a fixed length ideally.


Solution

  • There's no reason you can't use a straight long. The problem, as you've noted, is that java's (and therefore clojure's) long is signed, allowing only 63 bits for positive numbers

    Java, by default, allows arithmetic overflow without error. Clojure, by default, doesn't allow arithmetic overflow without error (see *unchecked-math* flag). It adds extra checking around arithmetic operations and casts, so, for instance, (byte 128) will cause an exception. Since clojure v1.3.0 there are functions like (unchecked-byte) which is equivalent to the java functionality....

    (unchecked-byte 128)
    ;=> -128 ; 2s-complement of 10000000
    (unchecked-byte 2r10000001)
    ;=> -127 ; 2s-complement of 10000001
    

    There are a whole raft of unchecked-* operations available (see clojuredocs).

    If you use a straight long and the unchecked-* operations you are mostly there, and then you can use the bit-* operations to twiddle/check bits.

    Finally storing your chessboard in an atom makes sense, and you then update it with (swap! chessboard fn args)

    (updated 15/02/13 with slightly more idiomatic swap! calls)

    e.g.

    (inc Long/MAX_VALUE) ; java.lang.ArithmeticException
    
    (unchecked-inc Long/MAX_VALUE) ; wraps.
    -9223372036854775808
    
    (def chessboard (atom 0))
    @chessboard
    ;=> 0
    (bit-test @chessboard 1)
    ;=> false
    (swap! chessboard bit-flip 1)
    ;=> 2
    (bit-test @chessboard 1)
    ;=> true
    @chessboard
    ;=> 2
    (reset! chessboard 0)
    ;=> 0
    (swap! chessboard bit-flip 63)
    ;=> -9223372036854775808 
    (bit-test @chessboard 63)
    ;=> true