The Pedigree Project  0.1
moves.cc
1 /*
2  *
3  * Copyright (c) 2008-2014, Pedigree Developers
4  *
5  * Please see the CONTRIB file in the root of the source tree for a full
6  * list of contributors.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include "moves.h"
22 #include <stdio.h>
23 
24 // Rank lookup table.
25 unsigned char rankLookupTable[256][256][8];
26 
27 unsigned char doRankComparison(unsigned char allPieces,
28  unsigned char enemyPieces,
29  int file);
30 
31 // Creates the lookup table.
32 void initLookupTable()
33 {
34  for(int i = 0; i < 256; i++)
35  {
36  for (int j = 0; j < 256; j++)
37  {
38  for (int k = 0; k < 8; k++)
39  {
40  rankLookupTable[i][j][k] = doRankComparison(i, j, k);
41  }
42  }
43  }
44 }
45 
46 // Normal rank comparison.
47 unsigned char rankComparison(unsigned char allPieces,
48  unsigned char enemyPieces,
49  int file)
50 {
51  return rankLookupTable[allPieces][enemyPieces][file];
52 }
53 
54 // Only used to generate the lookup table.
55 inline unsigned char doRankComparison(unsigned char allPieces,
56  unsigned char enemyPieces,
57  int file)
58 {
59  // Look right.
60  unsigned char toRet = 0;
61 
66 
67 
68  // Mask off everything but the right hand side.
69 // unsigned char masked = allPieces & (0xFF >> (file+1));
70 // if (masked == 0)
71 // {
72 // toRet = 0xFF >> (file+1);
73 // }
74 // else
75 // {
76 // unsigned int off;
77 // unsigned int tmp = masked;
78 // asm volatile("bsr %1, %0" : "=r" (off) : "r" (tmp));
79 // // off now holds the bit offset of the last set bit, or the first, scanning from the right.
80 // // We want to have a byte with ones between (8-file) and off inclusive (if bit off is set in
81 // // enemyPieces), or excluding bit off otherwise.
82 // if (!(enemyPieces & (0x1 << off)))
83 // off++;
84 // unsigned char fin = 0xFF >> file+1;
85 // unsigned char fin2 = 0xFF << off;
86 // toRet = fin & fin2;
87 // }
88  //
89 // masked = allPieces & (0xFF << (8-file));
90 // if (masked == 0)
91 // {
92 // toRet |= 0xFF << (8-file);
93 // return toRet;
94 // }
95 // else
96 // {
97 // unsigned int off;
98 // unsigned int tmp = masked;
99 // asm volatile("bsf %1, %0" : "=r" (off) : "r" (tmp));
100 // // off now holds the bit offset of the first bit set, or the last, scanning from the right.
101 // // We want to have a byte with ones between (file-1) and off inclusive (if bit off is set in
102 // // enemyPieces), or excluding bit off otherwise.
103 // if (!(enemyPieces & (0x1 << off)))
104 // off--;
105 // unsigned char fin = 0xFF << 8-file;
106 // unsigned char fin2 = 0xFF >> off;
107 // toRet |= fin & fin2;
108 // return toRet;
109 // }
110 
111  // Find the first one bit.
112  for (int i = file+1; i < 8; i++)
113  {
114  if ( ((allPieces << i) & 0x80) == 0)
115  {
116  toRet |= 0x80 >> i;
117  }
118  else
119  {
120  // Here we check enemyPieces. If an enemy piece is here then we can
121  // add a 1 in the move byte. Else it's a friendly piece and we can't
122  // move there.
123  if ((enemyPieces << i) & 0x80)
124  toRet |= 0x80 >> i;
125  break;
126  }
127  }
128 
129  // Look left.
130  for (int i = file-1; i >= 0; i--)
131  {
132  if ( ((allPieces << i) & 0x80) == 0)
133  toRet |= 0x80 >> i;
134  else
135  {
136  // Here we check enemyPieces. If an enemy piece is here then we can
137  // add a 1 in the move byte. Else it's a friendly piece and we can't
138  // move there.
139  if ((enemyPieces << i) & 0x80)
140  toRet |= 0x80 >> i;
141  break;
142  }
143  }
144  return toRet;
145 }
146 
147 Bitboard rookMoves(Bitboard allPieces, Bitboard enemyPieces, Square pos)
148 {
149  unsigned char rankAll = allPieces.getRank(pos.row);
150  unsigned char rankEnemy = enemyPieces.getRank(pos.row);
151  unsigned char retRank = rankComparison(rankAll, rankEnemy, pos.col);
152 
153  Bitboard toRet;
154  toRet.setRank(pos.row, retRank);
155 
156  allPieces.flip();
157  enemyPieces.flip();
158  rankAll = allPieces.getRank(pos.col);
159  rankEnemy = enemyPieces.getRank(pos.col);
160  retRank = rankComparison(rankAll, rankEnemy, pos.row);
161  Bitboard toRet2;
162  toRet2.setRank(pos.col, retRank);
163  toRet2.flip();
164 
165  return toRet | toRet2;
166 }
167 
168 Bitboard bishopMoves(Bitboard allPieces, Bitboard enemyPieces, Square pos)
169 {
170  int allPiecesFile, enemyPiecesFile;
171  unsigned char rankAll = allPieces.getDiagonalRank45(pos.row, pos.col, &allPiecesFile);
172  unsigned char rankEnemy = enemyPieces.getDiagonalRank45(pos.row, pos.col, &enemyPiecesFile);
173  unsigned char retRank = rankComparison(rankAll, rankEnemy, allPiecesFile);
174 
175  Bitboard toRet;
176  toRet.setDiagonalRank45(pos.row, pos.col, retRank);
177 
178  rankAll = allPieces.getDiagonalRank315(pos.row, pos.col, &allPiecesFile);
179  rankEnemy = enemyPieces.getDiagonalRank315(pos.row, pos.col, &enemyPiecesFile);
180  retRank = rankComparison(rankAll, rankEnemy, allPiecesFile);
181 
182  Bitboard toRet2;
183  toRet2.setDiagonalRank315(pos.row, pos.col, retRank);
184 
185  return toRet | toRet2;
186 }
187 
188 Bitboard queenMoves(Bitboard allPieces, Bitboard enemyPieces, Square pos)
189 {
190  return rookMoves(allPieces, enemyPieces, pos) | bishopMoves(allPieces, enemyPieces, pos);
191 }
192 
193 unsigned char kJumpTable[] = {0,1,0,1,0,0,0,0,
194  1,0,0,0,1,0,0,0,
195  0,0,0,0,0,0,0,0,
196  1,0,0,0,1,0,0,0,
197  0,1,0,1,0,0,0,0,
198  0,0,0,0,0,0,0,0,
199  0,0,0,0,0,0,0,0,
200  0,0,0,0,0,0,0,0};
201 
202 Bitboard knightMoves(Bitboard allPieces, Bitboard enemyPieces, Square pos)
203 {
204  Bitboard kTable(kJumpTable);
205  kTable.shift(pos.col-2, pos.row-2); // That jump table is centred on (2,2).
206 
207  // So we now have a bitboard for all the places the knight can move. But we really need to AND that with
208  // places that white pieces AREN'T.
209  Bitboard noPieces = ~allPieces; // No pieces at all in these squares.
210  Bitboard noFriendlyPieces = noPieces | enemyPieces;
211  return kTable & noFriendlyPieces;
212 }
213 
214 unsigned char KJumpTable[] = {1,1,1,0,0,0,0,0,
215  1,0,1,0,0,0,0,0,
216  1,1,1,0,0,0,0,0,
217  0,0,0,0,0,0,0,0,
218  0,0,0,0,0,0,0,0,
219  0,0,0,0,0,0,0,0,
220  0,0,0,0,0,0,0,0,
221  0,0,0,0,0,0,0,0};
222 unsigned char leftCastleSquares[] = {0,1,1,1,0,0,0,0,
223  0,0,0,0,0,0,0,0,
224  0,0,0,0,0,0,0,0,
225  0,0,0,0,0,0,0,0,
226  0,0,0,0,0,0,0,0,
227  0,0,0,0,0,0,0,0,
228  0,0,0,0,0,0,0,0,
229  0,0,0,0,0,0,0,0};
230 unsigned char rightCastleSquares[] = {0,0,0,0,0,1,1,0,
231  0,0,0,0,0,0,0,0,
232  0,0,0,0,0,0,0,0,
233  0,0,0,0,0,0,0,0,
234  0,0,0,0,0,0,0,0,
235  0,0,0,0,0,0,0,0,
236  0,0,0,0,0,0,0,0,
237  0,0,0,0,0,0,0,0};
238 unsigned char leftCastleMove [] = {0,0,1,0,0,0,0,0,
239  0,0,0,0,0,0,0,0,
240  0,0,0,0,0,0,0,0,
241  0,0,0,0,0,0,0,0,
242  0,0,0,0,0,0,0,0,
243  0,0,0,0,0,0,0,0,
244  0,0,0,0,0,0,0,0,
245  0,0,0,0,0,0,0,0};
246 unsigned char rightCastleMove [] = {0,0,0,0,0,0,1,0,
247  0,0,0,0,0,0,0,0,
248  0,0,0,0,0,0,0,0,
249  0,0,0,0,0,0,0,0,
250  0,0,0,0,0,0,0,0,
251  0,0,0,0,0,0,0,0,
252  0,0,0,0,0,0,0,0,
253  0,0,0,0,0,0,0,0};
254 
255 Bitboard kingMoves(Bitboard allPieces, Bitboard enemyPieces, Square pos, bool leftRookMoved,
256  bool rightRookMoved, bool kingMoved)
257 {
258  Bitboard kTable(KJumpTable);
259  kTable.shift(pos.col-1, pos.row-1); // That jump table is centred on (1,1).
260 
261  // So we now have a bitboard for all the places the knight can move. But we really need to AND that with
262  // places that white pieces AREN'T.
263  Bitboard noPieces = ~allPieces; // No pieces at all in these squares.
264  Bitboard noFriendlyPieces = noPieces | enemyPieces;
265  Bitboard toRet = kTable & noFriendlyPieces;
266 
267  // Now, can we castle?
268  if (!kingMoved && (!rightRookMoved || !leftRookMoved))
269  {
270  if (!rightRookMoved)
271  {
272  // So, we can castle to the right if and only if the right castle squares are empty.
273  if ( (allPieces & Bitboard(rightCastleSquares)).empty() )
274  {
275  toRet = toRet | Bitboard(rightCastleMove);
276  }
277  }
278  if (!leftRookMoved)
279  {
280  // So, we can castle to the left if and only if the left castle squares are empty.
281  if ( (allPieces & Bitboard(leftCastleSquares)).empty() )
282  {
283  toRet = toRet | Bitboard(leftCastleMove);
284  }
285  }
286  }
287  return toRet;
288 }
289 
290 unsigned char pawnMove[] = {0,0,0,0,0,0,0,0,
291  1,0,0,0,0,0,0,0,
292  0,0,0,0,0,0,0,0,
293  0,0,0,0,0,0,0,0,
294  0,0,0,0,0,0,0,0,
295  0,0,0,0,0,0,0,0,
296  0,0,0,0,0,0,0,0,
297  0,0,0,0,0,0,0,0};
298 unsigned char pawnInitial[] ={0,0,0,0,0,0,0,0,
299  1,0,0,0,0,0,0,0,
300  1,0,0,0,0,0,0,0,
301  0,0,0,0,0,0,0,0,
302  0,0,0,0,0,0,0,0,
303  0,0,0,0,0,0,0,0,
304  0,0,0,0,0,0,0,0,
305  0,0,0,0,0,0,0,0};
306 unsigned char pawnAttack[]={0,0,0,0,0,0,0,0,
307  1,0,1,0,0,0,0,0,
308  0,0,0,0,0,0,0,0,
309  0,0,0,0,0,0,0,0,
310  0,0,0,0,0,0,0,0,
311  0,0,0,0,0,0,0,0,
312  0,0,0,0,0,0,0,0,
313  0,0,0,0,0,0,0,0};
314 
315 Bitboard pawnMoves(Bitboard allPieces, Bitboard enemyPieces, Bitboard enemyPawnsEnPassant, Square pos)
316 {
317  // Has this pawn moved yet?
318  Bitboard normalMove(pawnMove);
319  Bitboard initialMove(pawnInitial);
320  Bitboard *move = &normalMove;
321 
322  if (pos.row == 1)
323  move = &initialMove;
324 
325  move->shift(pos.col, pos.row); // That jump table is centred on (0,0).
326 
327  // If there is a piece one square above us, we can't move 2 spaces!
328  if (allPieces & Bitboard(Square(pos.row+1, pos.col)))
329  *move = *move & ~Bitboard(Square(pos.row+2, pos.col));
330 
331  Bitboard attack(pawnAttack);
332  attack.shift(pos.col-1, pos.row); // That jump table is centred on (1,0).
333 
334  // So where can we move?
335  Bitboard finalMove = *move & (~allPieces); // We can move wherever there aren't any pieces!
336 
337  // So we now have a bitboard for all the places the pawn can move. But we really need to AND that with
338  // places that white pieces AREN'T.
339  Bitboard noPieces = ~allPieces; // No pieces at all in these squares.
340  Bitboard noFriendlyPieces = noPieces | enemyPieces;
341  finalMove = finalMove & noFriendlyPieces;
342 
343  // Where can we attack?
344  Bitboard finalAttack = attack & enemyPieces; // We can attack wherever there are enemy pieces!
345 
346  // But, we can also attack pawns En Passant...
347  finalAttack = finalAttack | (attack & enemyPawnsEnPassant);
348 
349  return finalMove | finalAttack;
350 }
351 
352 Bitboard pawnAttackOnly(Bitboard allPieces, Bitboard enemyPieces, Bitboard enemyPawnsEnPassant, Square pos)
353 {
354 
355  Bitboard attack(pawnAttack);
356  attack.shift(pos.col-1, pos.row); // That jump table is centred on (1,0).
357 
358  // Where can we attack?
359  Bitboard finalAttack = attack & enemyPieces; // We can attack wherever there are enemy pieces!
360 
361  // But, we can also attack pawns En Passant...
362  finalAttack = finalAttack | (attack & enemyPawnsEnPassant);
363 
364  return finalAttack;
365 }
unsigned char getRank(int n)
Definition: Bitboard.h:51
void setRank(int n, unsigned char c)
Definition: Bitboard.h:59
void flip()
Definition: Bitboard.cc:56
Definition: Square.h:24