View Javadoc

1   package com.alonsoruibal.chess.bitboard;
2   
3   import com.alonsoruibal.chess.Board;
4   import com.alonsoruibal.chess.log.Logger;
5   
6   /**
7    * Discover attacks to squares
8    */
9   public class BitboardAttacks {
10  	private static final Logger logger = Logger.getLogger("BitboardAttacksGwt");
11  	public static boolean initialized = false;
12  	
13  	public final static byte rookShiftBits[] = {
14  		  12, 11, 11, 11, 11, 11, 11, 12,
15  		  11, 10, 10, 10, 10, 10, 10, 11,
16  		  11, 10, 10, 10, 10, 10, 10, 11,
17  		  11, 10, 10, 10, 10, 10, 10, 11,
18  		  11, 10, 10, 10, 10, 10, 10, 11,
19  		  11, 10, 10, 10, 10, 10, 10, 11,
20  		  11, 10, 10, 10, 10, 10, 10, 11,
21  		  12, 11, 11, 11, 11, 11, 11, 12
22  		};
23  		 
24  	public final static byte bishopShiftBits[] = {
25  		  6, 5, 5, 5, 5, 5, 5, 6,
26  		  5, 5, 5, 5, 5, 5, 5, 5,
27  		  5, 5, 7, 7, 7, 7, 5, 5,
28  		  5, 5, 7, 9, 9, 7, 5, 5,
29  		  5, 5, 7, 9, 9, 7, 5, 5,
30  		  5, 5, 7, 7, 7, 7, 5, 5,
31  		  5, 5, 5, 5, 5, 5, 5, 5,
32  		  6, 5, 5, 5, 5, 5, 5, 6
33  		};
34  	
35  	// Magic numbers generated with MagicNumbersGen
36  //	public final static long rookMagicNumber[] = {0x1080108000400020L, 0x40200010004000L, 0x100082000441100L, 0x480041000080080L, 0x100080005000210L, 0x100020801000400L, 0x280010000800200L, 0x100008020420100L, 0x400800080400020L, 0x401000402000L, 0x100801000200080L, 0x801000800800L, 0x800400080080L, 0x800200800400L, 0x1000200040100L, 0x4840800041000080L, 0x20008080004000L, 0x404010002000L, 0x808010002000L, 0x828010000800L, 0x808004000800L, 0x14008002000480L, 0x40002100801L, 0x20001004084L, 0x802080004000L, 0x200080400080L, 0x810001080200080L, 0x10008080080010L, 0x4000080080040080L, 0x40080020080L, 0x1000100040200L, 0x80008200004124L, 0x804000800020L, 0x804000802000L, 0x801000802000L, 0x2000801000800804L, 0x80080800400L, 0x80040080800200L, 0x800100800200L, 0x8042000104L, 0x208040008008L, 0x10500020004000L, 0x100020008080L, 0x2000100008008080L, 0x200040008008080L, 0x8020004008080L, 0x1000200010004L, 0x100040080420001L, 0x80004000200040L, 0x200040100140L, 0x20004800100040L, 0x100080080280L, 0x8100800400080080L, 0x8004020080040080L, 0x9001000402000100L, 0x40080410200L, 0x208040110202L, 0x800810022004012L, 0x1000820004011L, 0x1002004100009L, 0x41001002480005L, 0x81000208040001L, 0x4000008201100804L, 0x2841008402L};
37  //	public final static long bishopMagicNumber[] = {0x1020041000484080L, 0x20204010a0000L, 0x8020420240000L, 0x404040085006400L, 0x804242000000108L, 0x8901008800000L, 0x1010110400080L, 0x402401084004L, 0x1000200810208082L, 0x20802208200L, 0x4200100102082000L, 0x1024081040020L, 0x20210000000L, 0x8210400100L, 0x10110022000L, 0x80090088010820L, 0x8001002480800L, 0x8102082008200L, 0x41001000408100L, 0x88000082004000L, 0x204000200940000L, 0x410201100100L, 0x2000101012000L, 0x40201008200c200L, 0x10100004204200L, 0x2080020010440L, 0x480004002400L, 0x2008008008202L, 0x1010080104000L, 0x1020001004106L, 0x1040200520800L, 0x8410000840101L, 0x1201000200400L, 0x2029000021000L, 0x4002400080840L, 0x5000020080080080L, 0x1080200002200L, 0x4008202028800L, 0x2080210010080L, 0x800809200008200L, 0x1082004001000L, 0x1080202411080L, 0x840048010101L, 0x40004010400200L, 0x500811020800400L, 0x20200040800040L, 0x1008012800830a00L, 0x1041102001040L, 0x11010120200000L, 0x2020222020c00L, 0x400002402080800L, 0x20880000L, 0x1122020400L, 0x11100248084000L, 0x210111000908000L, 0x2048102020080L, 0x1000108208024000L, 0x1004100882000L, 0x41044100L, 0x840400L, 0x4208204L, 0x80000200282020cL, 0x8a001240100L, 0x2040104040080L};
38  	
39  //	public static long[] rook;
40  	// The same but with border removed for magic bitboards
41  //	public static long[] rookMask;
42  //	public static long[][] rookMagic;
43  //	public static long[] bishop;
44  //	public static long[] bishopMask;
45  	public static long[][] bishopMagic;
46  	public static long[] knight;
47  	public static long[] king;
48  	public static long[] pawnDownwards;
49  	public static long[] pawnUpwards;
50  
51  	static {
52  		init();
53  	}
54  
55  	static long squareAttackedAux(long square, int shift, long border) {
56  		if ((square & border) == 0) {
57  			if (shift > 0) square <<= shift; else square >>>= -shift;
58  			return square;
59  		}
60  		return 0;
61  	}
62  	
63  	static long squareAttackedAuxSlider(long square, int shift, long border) {
64  		long ret = 0;
65  		while ((square & border) == 0) {
66  			if (shift > 0) square <<= shift; else square >>>= -shift;
67  			ret |= square;
68  		}
69  		return ret;
70  	}
71  
72  	static long squareAttackedAuxSliderMask(long square, int shift, long border) {
73  		long ret = 0;
74  		while ((square & border) == 0) {
75  			if (shift > 0) square <<= shift; else square >>>= -shift;
76  			if ((square & border) == 0) ret |= square;
77  		}
78  		return ret;
79  	}
80  	
81  	public static void generateAttacks() {
82  		logger.debug("Generating attack tables...");
83  		long time1 = System.currentTimeMillis();
84  //		rook = new long[64];
85  //		rookMask = new long[64];
86  //		rookMagic = new long[64][];
87  //		bishop = new long[64];
88  //		bishopMask = new long[64];
89  		bishopMagic = new long[64][];
90  		knight = new long[64];
91  		king = new long[64];
92  		pawnDownwards = new long[64];
93  		pawnUpwards = new long[64];
94  
95  		long square = 1;
96  		byte i = 0;
97  		while (square != 0) {
98  //			rook[i] = squareAttackedAuxSlider(square, +8, BitboardUtils.b_u)
99  //					| squareAttackedAuxSlider(square, -8, BitboardUtils.b_d)
100 //					| squareAttackedAuxSlider(square, -1, BitboardUtils.b_r)
101 //					| squareAttackedAuxSlider(square, +1, BitboardUtils.b_l);
102 //
103 //			rookMask[i] = squareAttackedAuxSliderMask(square, +8, BitboardUtils.b_u)
104 //					| squareAttackedAuxSliderMask(square, -8, BitboardUtils.b_d)
105 //					| squareAttackedAuxSliderMask(square, -1, BitboardUtils.b_r)
106 //					| squareAttackedAuxSliderMask(square, +1, BitboardUtils.b_l);
107 //
108 //			bishop[i] = squareAttackedAuxSlider(square, +9, BitboardUtils.b_u | BitboardUtils.b_l) 
109 //					| squareAttackedAuxSlider(square, +7, BitboardUtils.b_u | BitboardUtils.b_r)
110 //					| squareAttackedAuxSlider(square, -7, BitboardUtils.b_d | BitboardUtils.b_l)
111 //					| squareAttackedAuxSlider(square, -9, BitboardUtils.b_d | BitboardUtils.b_r);
112 //			
113 //			bishopMask[i] = squareAttackedAuxSliderMask(square, +9, BitboardUtils.b_u | BitboardUtils.b_l) 
114 //					| squareAttackedAuxSliderMask(square, +7, BitboardUtils.b_u | BitboardUtils.b_r)
115 //					| squareAttackedAuxSliderMask(square, -7, BitboardUtils.b_d | BitboardUtils.b_l)
116 //					| squareAttackedAuxSliderMask(square, -9, BitboardUtils.b_d | BitboardUtils.b_r);
117 
118 			knight[i] = squareAttackedAux(square, +17, BitboardUtils.b2_u | BitboardUtils.b_l)
119 					| squareAttackedAux(square, +15, BitboardUtils.b2_u | BitboardUtils.b_r)
120 					| squareAttackedAux(square, -15, BitboardUtils.b2_d | BitboardUtils.b_l)
121 					| squareAttackedAux(square, -17, BitboardUtils.b2_d | BitboardUtils.b_r)
122 					| squareAttackedAux(square, +10, BitboardUtils.b_u | BitboardUtils.b2_l)
123 					| squareAttackedAux(square, +6, BitboardUtils.b_u | BitboardUtils.b2_r)
124 					| squareAttackedAux(square, -6, BitboardUtils.b_d | BitboardUtils.b2_l)
125 					| squareAttackedAux(square, -10, BitboardUtils.b_d | BitboardUtils.b2_r);
126 
127 			pawnUpwards[i] = squareAttackedAux(square, 7, BitboardUtils.b_u | BitboardUtils.b_r)
128 					| squareAttackedAux(square, 9, BitboardUtils.b_u | BitboardUtils.b_l);
129 
130 			pawnDownwards[i] = squareAttackedAux(square, -7, BitboardUtils.b_d | BitboardUtils.b_l)
131 					| squareAttackedAux(square, -9, BitboardUtils.b_d | BitboardUtils.b_r);
132 
133 			king[i] = squareAttackedAux(square, +8, BitboardUtils.b_u)
134 					| squareAttackedAux(square, -8, BitboardUtils.b_d)
135 					| squareAttackedAux(square, -1, BitboardUtils.b_r)
136 					| squareAttackedAux(square, +1, BitboardUtils.b_l)
137 					| squareAttackedAux(square, +9, BitboardUtils.b_u | BitboardUtils.b_l)
138 					| squareAttackedAux(square, +7, BitboardUtils.b_u | BitboardUtils.b_r)
139 					| squareAttackedAux(square, -7, BitboardUtils.b_d | BitboardUtils.b_l)
140 					| squareAttackedAux(square, -9, BitboardUtils.b_d | BitboardUtils.b_r);
141 
142 //			// And now generate magics			
143 //			int rookPositions = (1 << rookShiftBits[i]);
144 //			rookMagic[i] = new long[rookPositions];
145 //		    for (int j = 0; j < rookPositions; j++) {
146 //		      long pieces = BitboardAttacks.generatePieces(j, rookShiftBits[i], rookMask[i]);
147 //		      int magicIndex = magicTransform(pieces, rookMagicNumber[i], rookShiftBits[i]);
148 //		      rookMagic[i][magicIndex] = getRookShiftAttacks(square, pieces);
149 //		    }
150 			
151 //			int bishopPositions = (1 << bishopShiftBits[i]);
152 //			bishopMagic[i] = new long[bishopPositions];
153 //		    for (int j = 0; j < bishopPositions; j++) {
154 //		      long pieces = BitboardAttacks.generatePieces(j, bishopShiftBits[i], bishopMask[i]);
155 //		      int magicIndex = magicTransform(pieces, bishopMagicNumber[i], bishopShiftBits[i]);
156 //		      bishopMagic[i][magicIndex] = getBishopShiftAttacks(square, pieces);
157 //		    }
158 		    
159 			square <<= 1;
160 			i++;
161 		}
162 		long time2 = System.currentTimeMillis();
163 		initialized = true;
164 		logger.debug("Generated attack tables in " + (time2-time1) + "ms");
165 	}
166 	
167 //	public static void loadAttacks() throws IOException, ClassNotFoundException {
168 //		logger.debug("Loading attack tables...");
169 //		long time1 = System.currentTimeMillis();
170 //		ObjectInputStream oo = new ObjectInputStream(BitboardAttacks.class.getResourceAsStream("/attacks.bin"));
171 //		rook = (long[]) oo.readObject();
172 //		rookMask = (long[]) oo.readObject();
173 //		rookMagic = (long[][]) oo.readObject();
174 //		bishop = (long[]) oo.readObject();
175 //		bishopMask = (long[]) oo.readObject();
176 //		bishopMagic = (long[][]) oo.readObject();
177 //		knight = (long[]) oo.readObject();
178 //		king = (long[]) oo.readObject();
179 //		pawnDownwards = (long[]) oo.readObject();
180 //		pawnUpwards = (long[]) oo.readObject();
181 //		long time2 = System.currentTimeMillis();
182 //		logger.debug("Loaded attacks table from file in " + (time2-time1) + "ms");
183 //	}
184 	
185 	/**
186 	 * Build/load attack tables
187 	 */
188 	public static void init() {
189 //		boolean loaded = false;
190 		// It's slower to load attacks from file in many devices (like Android) but may be necesary on GWT
191 //		try {
192 //			loadAttacks();
193 //			loaded = true;
194 //		} catch (IOException e) {
195 //			e.printStackTrace();
196 //		} catch (ClassNotFoundException e) {
197 //			e.printStackTrace();
198 //		}
199 		if (initialized) return;
200 		generateAttacks();
201 	}
202 	
203 	/**
204 	 * Discover attacks to squares using magics: expensive version
205 	 */
206 	public static boolean isSquareAttacked(Board board, long square, boolean white) {
207 		return isIndexAttacked(board, BitboardUtils.square2Index(square), white);
208 	}
209 	
210 	/**
211 	 * Discover attacks to squares using magics: cheap version
212 	 */
213 	public static boolean isIndexAttacked(Board board, byte index, boolean white) {
214 		if (index < 0 || index > 63) return false;
215 		long others = (white ? board.blacks : board.whites);
216 		long all = board.getAll();
217 		
218 		if (((white ? BitboardAttacks.pawnUpwards[index] : BitboardAttacks.pawnDownwards[index]) & board.pawns & others) != 0) return true;
219 		if ((BitboardAttacks.king[index] & board.kings & others) != 0) return true; 
220 		if ((BitboardAttacks.knight[index] & board.knights & others) != 0) return true; 
221 		if ((getRookAttacks(index, all) & (board.rooks | board.queens) & others) != 0) return true;
222 		if ((getBishopAttacks(index, all) & (board.bishops | board.queens) & others) != 0) return true;
223 		return false;
224 	}
225 
226 	/**
227 	 * Discover attacks to squares using magics: cheap version
228 	 */
229 	public static long getIndexAttacks(Board board, int index) {
230 		if (index < 0 || index > 63) return 0;
231 		long all = board.getAll();
232 		
233 		return ((board.blacks & BitboardAttacks.pawnUpwards[index] | board.whites & BitboardAttacks.pawnDownwards[index]) & board.pawns) |
234 		(BitboardAttacks.king[index] & board.kings) |
235 		(BitboardAttacks.knight[index] & board.knights) |
236 		(getRookAttacks(index, all) & (board.rooks | board.queens)) |
237 		(getBishopAttacks(index, all) & (board.bishops | board.queens));
238 	}
239 
240 	public static long getXrayAttacks(Board board, int index, long all) {
241 		if (index < 0 || index > 63) return 0;
242 	
243 		return ((getRookAttacks(index, all) & (board.rooks | board.queens)) |
244 		(getBishopAttacks(index, all) & (board.bishops | board.queens))) & all;
245 	}
246 	
247 	/**
248 	 * Magic! attacks, very fast method
249 	 */
250 	public static long getRookAttacks(int index, long all) {
251 		return getRookShiftAttacks(BitboardUtils.index2Square((byte) index), all);
252 //		int i = magicTransform(all & rookMask[index], rookMagicNumber[index], rookShiftBits[index]);
253 //		return rookMagic[index][i];
254 	}
255 	
256 	public static long getBishopAttacks(int index, long all) {
257 		return getBishopShiftAttacks(BitboardUtils.index2Square((byte) index), all);
258 //		int i = magicTransform(all & bishopMask[index], bishopMagicNumber[index], bishopShiftBits[index]);
259 //		return bishopMagic[index][i];
260 	}
261 	
262 	public static int magicTransform(long b, long magic, byte bits) {
263 		  return (int)((b * magic) >>> (64 - bits));
264 	}
265 	
266 	/**
267 	 * Fills pieces from a mask. Neccesary for magic generation
268 	 * variable bits is the mask bytes number
269 	 * index goes from 0 to 2^bits
270 	 */
271 	public static long generatePieces(int index, int bits, long mask) {
272 		  int i;
273 		  long lsb;
274 		  long result = 0L;
275 		  for (i = 0; i < bits; i++) {
276 			lsb = mask & (-mask);
277 		    mask ^= lsb; // Deactivates lsb bit of the mask to get next bit next time
278 		    if ((index & (1 << i)) != 0) result |= lsb; // if bit is set to 1
279 		  }
280 		  return result;
281 	}
282 	
283 	/** 
284 	 * without magic bitboards, too expensive, but neccesary for magic generation
285 	 */
286 	public static long getRookShiftAttacks(long square, long all) {
287 		return checkSquareAttackedAux(square, all, +8, BitboardUtils.b_u) |
288 			checkSquareAttackedAux(square, all, -8, BitboardUtils.b_d) |
289 			checkSquareAttackedAux(square, all, -1, BitboardUtils.b_r) |
290 			checkSquareAttackedAux(square, all, +1, BitboardUtils.b_l);
291 	}
292 	
293 	public static long getBishopShiftAttacks(long square, long all) {
294 		return checkSquareAttackedAux(square, all, +9, BitboardUtils.b_u | BitboardUtils.b_l) |
295 			checkSquareAttackedAux(square, all, +7, BitboardUtils.b_u | BitboardUtils.b_r) |
296 			checkSquareAttackedAux(square, all, -7, BitboardUtils.b_d | BitboardUtils.b_l) |
297 			checkSquareAttackedAux(square, all, -9, BitboardUtils.b_d | BitboardUtils.b_r);
298 	}
299 	
300 	/**
301 	 * Attacks for sliding pieces
302 	 */
303 	private static long checkSquareAttackedAux(long square, long all, int shift, long border) {
304 		long ret = 0;
305 		while ((square & border) == 0) {
306 			if (shift>0) square <<= shift; else square >>>= -shift;
307 			ret |= square;
308 			// If we collide with other piece
309 			if ((square & all) != 0) break;
310 		}
311 		return ret;
312 	}
313 }