Question

I'm trying to calculate ray attacks given the index of a 64-bit Long bitboard representation:

(defn se [board index]
  "Produces a ray attack from the indexed bit in the south-east direction"
  (reduce bit-or
    (for [bit (rest (range index 0 -7))]
      (bit-flip board bit))))

The rook attacks (straight along a file or rank) are easy enough. However, the problem with the above code is I'm ending up with the following possibility for diagonal Bishop attacks:

00000000
00100000
01000000
10000001
00000010
00000100
00001000
00010000

How should I account for the case when the piece goes off the edge of the board? I'm using big endian mapping (A8 = 0, H1 = 63).

Was it helpful?

Solution

(defn se [board index]
  "Produces a ray attack from the indexed bit in the south-east direction"
  (reduce bit-or 0
    (for [bit (take (- 7 (rem index 8)) (rest (range index 0 -7)))]
      (bit-flip board bit))))

OTHER TIPS

I would probably do this using the x,y co-ordinates on the board: this makes it easier to do the boundary condition checks on the board edges, something like

(defn se [x y]
  "Produces a ray attack from the indexed bit in the south-east direction"
  (let [initial (bit-shift-left (bit-shift-left (long 1) x) (* y 8))
        dx 1 ;; x direction
        dy 1 ;; y direction
        distance (min 
                   (- 7 x) 
                   (- 7 y))
        shift (+ dx (* 8 dy))]
    (loop [value 0
           distance distance]
      (if (<= distance 0)
        value
        (recur (bit-or value (bit-shift-left initial (* distance shift))) (dec distance))))))

(defn bits [^long bitboard]
  (map 
    #(if (> (bit-and 1 (bit-shift-right bitboard %)) 0) 1 0)
    (range 64)))

(defn display [bitboard]
  (let [bits (partition 8 (bits bitboard))]
    (doseq [ss bits]
      (println (apply str ss)))))

(display (se 1 3))

00000000
00000000
00000000
00000000
00100000
00010000
00001000
00000100

With a bit of extra work you could generalize this to cast a ray in any (dx, dy) direction, e.g. (1,0) for a rook moving east. If you put a distance limit you can even use (2,1) for knights.....

I think this will be more practical than defining separate functions for each piece direction.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top