The Pedigree Project  0.1
SideState.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 "SideState.h"
22 #include "moves.h"
23 
24 long g_nIsAttacking = 0;
25 long g_nHeuristic = 0;
26 
27 unsigned char initialPawns[] = {0,0,0,0,0,0,0,0,
28  1,1,1,1,1,1,1,1,
29  0,0,0,0,0,0,0,0,
30  0,0,0,0,0,0,0,0,
31  0,0,0,0,0,0,0,0,
32  0,0,0,0,0,0,0,0,
33  0,0,0,0,0,0,0,0,
34  0,0,0,0,0,0,0,0};
35 unsigned char initialKnights[] = {0,1,0,0,0,0,1,0,
36  0,0,0,0,0,0,0,0,
37  0,0,0,0,0,0,0,0,
38  0,0,0,0,0,0,0,0,
39  0,0,0,0,0,0,0,0,
40  0,0,0,0,0,0,0,0,
41  0,0,0,0,0,0,0,0,
42  0,0,0,0,0,0,0,0};
43 unsigned char initialRooks[] = {1,0,0,0,0,0,0,1,
44  0,0,0,0,0,0,0,0,
45  0,0,0,0,0,0,0,0,
46  0,0,0,0,0,0,0,0,
47  0,0,0,0,0,0,0,0,
48  0,0,0,0,0,0,0,0,
49  0,0,0,0,0,0,0,0,
50  0,0,0,0,0,0,0,0};
51 unsigned char initialBishops[] = {0,0,1,0,0,1,0,0,
52  0,0,0,0,0,0,0,0,
53  0,0,0,0,0,0,0,0,
54  0,0,0,0,0,0,0,0,
55  0,0,0,0,0,0,0,0,
56  0,0,0,0,0,0,0,0,
57  0,0,0,0,0,0,0,0,
58  0,0,0,0,0,0,0,0};
59 unsigned char initialQueen[] = {0,0,0,1,0,0,0,0,
60  0,0,0,0,0,0,0,0,
61  0,0,0,0,0,0,0,0,
62  0,0,0,0,0,0,0,0,
63  0,0,0,0,0,0,0,0,
64  0,0,0,0,0,0,0,0,
65  0,0,0,0,0,0,0,0,
66  0,0,0,0,0,0,0,0};
67 unsigned char initialKing[] = {0,0,0,0,1,0,0,0,
68  0,0,0,0,0,0,0,0,
69  0,0,0,0,0,0,0,0,
70  0,0,0,0,0,0,0,0,
71  0,0,0,0,0,0,0,0,
72  0,0,0,0,0,0,0,0,
73  0,0,0,0,0,0,0,0,
74  0,0,0,0,0,0,0,0};
75 
77  pawns(initialPawns),
78  rooks(initialRooks),
79  knights(initialKnights),
80  bishops(initialBishops),
81  queen(initialQueen),
82  king(initialKing),
83  enPassant(),
84  kingMoved(false),
85  hasCastled(false),
86  nextBoard()
87 {
88  rooksMoved[0] = false;
89  rooksMoved[1] = false;
90 }
91 
93 {
94  nextBoard = pawns;
95  nextPiece = Pawn;
96  return next();
97 }
98 
99 Square SideState::firstRook()
100 {
101  nextBoard = rooks;
102  nextPiece = Rook;
103  return next();
104 }
105 
106 Square SideState::firstKnight()
107 {
108  nextBoard = knights;
109  nextPiece = Knight;
110  return next();
111 }
112 
113 Square SideState::firstBishop()
114 {
115  nextBoard = bishops;
116  nextPiece = Bishop;
117  return next();
118 }
119 
120 Square SideState::firstQueen()
121 {
122  nextBoard = queen;
123  nextPiece = Queen;
124  return next();
125 }
126 
127 Square SideState::firstKing()
128 {
129  nextBoard = king;
130  nextPiece = King;
131  return next();
132 }
133 
134 Square SideState::next()
135 {
136  return nextBoard.getAndClearFirstSetBit();
137 }
138 
140 {
141  g_nIsAttacking++;
142  // Make a bitboard for the square under attack.
143  Bitboard sqBoard;
144  sqBoard.set(sq.row, sq.col);
145 
146  // Make a bitboard for all friendly pieces.
147  Bitboard frBoard = pawns | rooks | knights | bishops | king | queen;
148 
149  // And a bit board for all pieces.
150  Bitboard all = enemyPieces | frBoard;
151  for (Square i = firstPawn();
152  !i.invalid();
153  i = next())
154  {
155  // NOTE: ignores En Passant atm!
156  if ( pawnAttackOnly(all, enemyPieces, Bitboard(), i) & sqBoard )
157  return true;
158  }
159  for (Square i = firstRook();
160  !i.invalid();
161  i = next())
162  {
163  if ( rookMoves(all, enemyPieces, i) & sqBoard )
164  return true;
165  }
166  for (Square i = firstBishop();
167  !i.invalid();
168  i = next())
169  {
170  if ( bishopMoves(all, enemyPieces, i) & sqBoard )
171  return true;
172  }
173  for (Square i = firstQueen();
174  !i.invalid();
175  i = next())
176  {
177  if ( queenMoves(all, enemyPieces, i) & sqBoard )
178  return true;
179  }
180  if (!firstKing().invalid() &&
181  (kingMoves (all, enemyPieces, firstKing(), true, true, true)) & sqBoard) // Can't attack with a castle!
182  return true;
183 
184  return false;
185 }
186 
188 {
189  Square k = firstKing();
190  return (k.col == m.sCol && k.row == m.eRow &&
191  (m.eCol-m.sCol > 1 || m.eCol-m.sCol < -1));
192 }
193 
194 bool SideState::isLegal(Move m, Bitboard enemyPieces, Bitboard enemyPawnsEnPassant)
195 {
196  Square startSq(m.sCol, m.sRow);
197  Square endSq(m.eCol, m.eRow);
198 
199  Bitboard allPieces = pawns|knights|rooks|bishops|queen|king|enemyPieces;
200  if (pawns & Bitboard(startSq))
201  {
202  // Pawn moving.
203  if ( pawnMoves(allPieces, enemyPieces, enemyPawnsEnPassant, startSq) & Bitboard(endSq) )
204  return true;
205  }
206  else if (knights & Bitboard(startSq))
207  {
208  // Knight moving.
209  if ( knightMoves(allPieces, enemyPieces, startSq) & Bitboard(endSq) )
210  return true;
211  }
212  else if (rooks & Bitboard(startSq))
213  {
214  // Rook moving.
215  if ( rookMoves(allPieces, enemyPieces, startSq) & Bitboard(endSq) )
216  return true;
217  }
218  else if (bishops & Bitboard(startSq))
219  {
220  // Bishop moving.
221  if ( bishopMoves(allPieces, enemyPieces, startSq) & Bitboard(endSq) )
222  return true;
223  }
224  else if (queen & Bitboard(startSq))
225  {
226  // Queen moving.
227  if ( queenMoves(allPieces, enemyPieces, startSq) & Bitboard(endSq) )
228  return true;
229  }
230  else if (king & Bitboard(startSq))
231  {
232  // King moving.
233  if ( kingMoves(allPieces, enemyPieces, startSq, rooksMoved[0], rooksMoved[1], kingMoved) & Bitboard(endSq) )
234  return true;
235  }
236  return false;
237 }
238 
239 void SideState::friendlyMove(Move m, Piece promotion)
240 {
241  Bitboard mb, mb2;
242  mb.set(m.sRow, m.sCol);
243  mb2.set(m.eRow, m.eCol);
244  bool operationCompleted = false;
245 
246  // We must identify if this move is a pawn, or a king, as special things can happen
247  // (promotion, castle).
248  if ( (pawns & mb) && (m.eRow == 7)) // Pawn promotion
249  {
250  pawns = pawns & ~mb; // Remove the pawn.
251  switch (promotion)
252  {
253  case Pawn: pawns.set(m.eRow, m.eCol); break;
254  case Knight: knights.set(m.eRow, m.eCol); break;
255  case Bishop: bishops.set(m.eRow, m.eCol); break;
256  case Queen: queen.set(m.eRow, m.eCol); break;
257  case Rook: rooks.set(m.eRow, m.eCol); break;
258  default: printf("Oh fuck.\n");
259  }
260  operationCompleted = true;
261  }
262  else if ( (pawns & mb) && ( m.eRow - m.sRow == 2 ) )
263  {
264  // Pawn moved two spaces. We must set the square that this pawn moved over
265  // as "en-passant-able".
266  enPassant.set(m.sRow+1, m.sCol);
267  }
268  else if ( (king & mb) && ( (m.sCol - m.eCol > 1) || (m.eCol - m.sCol > 1)) )
269  {
270  // Castle ahoy!
271  king = Bitboard();
272  king.set(m.eRow, m.eCol);
273 
274  // Castling left?
275  if (m.eCol == 2)
276  {
277  // Remove left rook.
278  rooks.clear(0, 0);
279  // Add it again.
280  rooks.set(0, 3);
281  }
282  else
283  {
284  // Remove right rook.
285  rooks.clear(0, 7);
286  // Add it again.
287  rooks.set(0, 5);
288  }
289  kingMoved = true; // Doesn't matter about rooksMoved now.
290  hasCastled = true;
291  operationCompleted = true;
292  }
293 
294  if (!operationCompleted)
295  {
296  if (pawns & mb)
297  {
298  pawns = pawns & ~mb;
299  pawns = pawns | mb2;
300  }
301  if (knights & mb)
302  {
303  knights = knights & ~mb;
304  knights = knights | mb2;
305  }
306  if (rooks & mb)
307  {
308  rooks = rooks & ~mb;
309  rooks = rooks | mb2;
310  }
311  if (bishops & mb)
312  {
313  bishops = bishops & ~mb;
314  bishops = bishops | mb2;
315  }
316  if (queen & mb)
317  {
318  queen = queen & ~mb;
319  queen = queen | mb2;
320  }
321  if (king & mb)
322  {
323  king = king & ~mb;
324  king = king | mb2;
325  }
326  }
327 }
328 
329 void SideState::enemyMove(Move m, Bitboard enemyPawns)
330 {
331  // Check for en passant.
332  Bitboard mb, mb2;
333  mb.set(m.sRow, m.sCol);
334  mb2.set(m.eRow, m.eCol);
335  Bitboard nmb2 = ~mb2;
336  bool operationCompleted = false;
337 
338  if ( (enemyPawns & mb) && // A pawn moving?
339  (enPassant & mb2) ) // To an en passant square?
340  {
341  // Behold, en passant.
342  pawns.clear(m.eRow+1, m.eCol); // Remove the pawn.
343  operationCompleted = true;
344  }
345 
346  // Clear en-passant bitboard.
347  enPassant.clear();
348 
349  if (!operationCompleted)
350  {
351  pawns = pawns & nmb2;
352  rooks = rooks & nmb2;
353  bishops = bishops & nmb2;
354  knights = knights & nmb2;
355  queen = queen & nmb2;
356  king = king & nmb2;
357  }
358 }
359 
360 extern unsigned char pawnAttack[];
361 unsigned char knightCentre[]={0,0,0,0,0,0,0,0,
362  0,0,0,0,0,0,0,0,
363  0,0,0,0,0,0,0,0,
364  1,1,1,1,1,1,1,1,
365  1,1,1,1,1,1,1,1,
366  0,0,0,0,0,0,0,0,
367  0,0,0,0,0,0,0,0,
368  0,0,0,0,0,0,0,0};
369 
370 long SideState::heuristic()
371 {
372  long h = 0;
373  g_nHeuristic ++;
375  // Pawns
376  // +100 for each, and +10 for every friendly piece protected by a pawn.
377  Bitboard _pawns = pawns;
378  for (Square sq = _pawns.getAndClearFirstSetBit();
379  !sq.invalid();
380  sq = _pawns.getAndClearFirstSetBit())
381  {
382  h += 100; // +100 for each.
383  Bitboard attack(pawnAttack);
384  attack.shift(sq.col-1, sq.row); // That jump table is centred on (1,0).
385  // What pieces can we defend? (not including king).
386  Bitboard finalAttack = attack & (pawns|knights|rooks|bishops|queen);
387  while (!finalAttack.getAndClearFirstSetBit().invalid())
388  h += 10; // +1 for each friendly piece protected.
389  }
390 
392  // Rooks
393  // +400 for each.
394  Bitboard _rooks = rooks;
395  for (Square sq = _rooks.getAndClearFirstSetBit();
396  !sq.invalid();
397  sq = _rooks.getAndClearFirstSetBit())
398  {
399  h += 400; // +400 for each.
400  }
401 
403  // Knights
404  // +500 for each, and +20 for each in the middle set of squares.
405  Bitboard _knights = knights;
406  for (Square sq = _knights.getAndClearFirstSetBit();
407  !sq.invalid();
408  sq = _knights.getAndClearFirstSetBit())
409  {
410  h += 500; // +500 for each.
411  Bitboard knightsInCentre = knights & Bitboard(knightCentre);
412  while (!knightsInCentre.getAndClearFirstSetBit().invalid())
413  h += 20; // +20 for each knight in centre.
414  }
415 
417  // Bishops
418  // +400 for each
419  Bitboard _bishops = bishops;
420  for (Square sq = _bishops.getAndClearFirstSetBit();
421  !sq.invalid();
422  sq = _bishops.getAndClearFirstSetBit())
423  {
424  h += 400; // +400 for each.
425  }
426 
428  // Queen
429  // +1000 for each
430  Bitboard _queens = queen;
431  for (Square sq = _queens.getAndClearFirstSetBit();
432  !sq.invalid();
433  sq = _queens.getAndClearFirstSetBit())
434  {
435  h += 1000; // +1000 for each.
436  }
437 
439  // King
440  // +50 for castling.
441  if (hasCastled)
442  h += 50;
443 
444  return h;
445 }
Bitboard pawns
Definition: SideState.h:100
Bitboard attack
Definition: SideState.h:112
void friendlyMove(Move m, Piece promotion=Pawn)
Definition: SideState.cc:239
bool rooksMoved[2]
Definition: SideState.h:93
bool isCastle(Move m)
Definition: SideState.cc:187
Bitboard nextBoard
Definition: SideState.h:117
Definition: Move.h:29
bool isAttacking(Square sq, Bitboard enemyPieces)
Definition: SideState.cc:139
Square firstPawn()
Definition: SideState.cc:92
bool set(int rank, int file)
Definition: Bitboard.h:83
bool isLegal(Move m, Bitboard enemyPieces, Bitboard enemyPawnsEnPassant)
Definition: SideState.cc:194
Definition: Square.h:24
bool clear(int rank, int file)
Definition: Bitboard.h:75