Belofte  version 2.1.5
A promising chess program using the UCI or Winboard interface
piece.cpp
Go to the documentation of this file.
1 /*---------------------------------------------------------------------+
2  * File: piece.cpp
3  * Project: part of belofte - A Promising Chess Program
4  * Author: yves
5  * SPDX-License-Identifier: GPL-2.0-only
6  +---------------------------------------------------------------------*/
7 
8 #include "belofte.h"
9 
10 /** Allow index mapper for char values of piece into int in 1-12 range
11  * to reduce space and easy initialisation
12  */
13 namespace belofte {
14  static piece_t bPieceIndex[128] = {};
17 }
18 
20 {
21 }
22 
24  : m_piece(p)
25 {
26 }
27 
29 {
30 }
31 
33 {
47 
61 
75 }
76 
78 {
79  for (int i = 0; i < tPiece::P_SIZE; i++) {
80  delete belofte::pieceinstances[i];
81  }
82 }
83 
84 //-----------------------------------------------------------------------
85 
86 /** static class member function */
88 {
89  return belofte::pieceinstances[piece];
90 }
91 
92 /** static class member function */
93 std::string const bPiece::getPieceStrUpper(piece_t const piece)
94 {
95  switch (piece) {
96  case tPiece::W_PAWN:
97  case tPiece::B_PAWN:
98  return S_P_PAWN;
99  case tPiece::W_ROOK:
100  case tPiece::B_ROOK:
101  return S_P_ROOK;
102  case tPiece::W_KNIGHT:
103  case tPiece::B_KNIGHT:
104  return S_P_KNIGHT;
105  case tPiece::W_BISHOP:
106  case tPiece::B_BISHOP:
107  return S_P_BISHOP;
108  case tPiece::W_KING:
109  case tPiece::B_KING:
110  return S_P_KING;
111  case tPiece::W_QUEEN:
112  case tPiece::B_QUEEN:
113  return S_P_QUEEN;
114  case tPiece::P_EMPTY:
115  case tPiece::P_SIZE:
116  break;
117  }
118  return S_P_EMPTY;
119 }
120 
121 //-----------------------------------------------------------------------
122 
124 {
125  if (!m_piece) return tSide::SIDE_UNDEFINED;
126  if (m_piece <= tPiece::W_QUEEN) return tSide::SIDE_WHITE;
127  return tSide::SIDE_BLACK;
128 }
129 
130 //-----------------------------------------------------------------------
131 
132 /** static class member function */
134 {
135  return belofte::bPieceMapper[p];
136 }
137 
138 /** static class member function */
140 {
141  return belofte::bPieceIndex[p];
142 }
143 
144 /** static class member function */
145 bool bPiece::isOpponent(side_t const s, piece_t const p)
146 {
147  if (!p) return false;
148  if (p <= tPiece::W_QUEEN) return s == tSide::SIDE_BLACK ;
149  return s == tSide::SIDE_WHITE;
150 }
151 
152 /** static class member function */
153 bool bPiece::isOwnColour(side_t const s, piece_t const p)
154 {
155  if (!p) return false;
156  if (p <= tPiece::W_QUEEN) return s == tSide::SIDE_WHITE;
157  return s == tSide::SIDE_BLACK;
158 }
159 
160 //-----------------------------------------------------------------------
161 
163  : m_side{s}
164 {
165 }
166 
168 {
169 }
170 
171 /**
172  * Check if piece on position is attacked, start with piece always on board
173  * and then with pieces with greatest mobility, goal is to break ou asap
174  * @param b board
175  * @param cf piece position
176  * @return true if attacked, false if not
177 */
178 bool bWhitePiece::isAttacked(bBoard const& b, case_t const& cf) const
179 {
180  // king
181  if (isAttackedByPiece(b, cf, tPiece::B_KING, 1, -1)) return true;
182  if (isAttackedByPiece(b, cf, tPiece::B_KING, 1, 0)) return true;
183  if (isAttackedByPiece(b, cf, tPiece::B_KING, 1, 1)) return true;
184  if (isAttackedByPiece(b, cf, tPiece::B_KING, 0, 1)) return true;
185  if (isAttackedByPiece(b, cf, tPiece::B_KING, 0, -1)) return true;
186  if (isAttackedByPiece(b, cf, tPiece::B_KING, -1, -1)) return true;
187  if (isAttackedByPiece(b, cf, tPiece::B_KING, -1, 0)) return true;
188  if (isAttackedByPiece(b, cf, tPiece::B_KING, -1, 1)) return true;
189 
190  // rook, queen
191  if (isAttackedBySlider(b, cf, tPiece::B_ROOK, tPiece::B_QUEEN, -1, 0)) return true;
192  if (isAttackedBySlider(b, cf, tPiece::B_ROOK, tPiece::B_QUEEN, 1, 0)) return true;
193  if (isAttackedBySlider(b, cf, tPiece::B_ROOK, tPiece::B_QUEEN, 0, -1)) return true;
194  if (isAttackedBySlider(b, cf, tPiece::B_ROOK, tPiece::B_QUEEN, 0, 1)) return true;
195 
196  // bishop, queen
197  if (isAttackedBySlider(b, cf, tPiece::B_BISHOP, tPiece::B_QUEEN, -1, -1)) return true;
198  if (isAttackedBySlider(b, cf, tPiece::B_BISHOP, tPiece::B_QUEEN, 1, -1)) return true;
199  if (isAttackedBySlider(b, cf, tPiece::B_BISHOP, tPiece::B_QUEEN, -1, 1)) return true;
200  if (isAttackedBySlider(b, cf, tPiece::B_BISHOP, tPiece::B_QUEEN, 1, 1)) return true;
201 
202  // knight
203  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, 1, -2)) return true;
204  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, 1, 2)) return true;
205  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, 2, -1)) return true;
206  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, 2, 1)) return true;
207  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, -1, -2)) return true;
208  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, -1, 2)) return true;
209  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, -2, -1)) return true;
210  if (isAttackedByPiece(b, cf, tPiece::B_KNIGHT, -2, 1)) return true;
211 
212  if (bCase::rank(cf) < 6) {
213  if (isAttackedByPiece(b, cf, tPiece::B_PAWN, 1, -1)) return true;
214  if (isAttackedByPiece(b, cf, tPiece::B_PAWN, 1, 1)) return true;
215  /// @todo TOCHECK how about ep
216  }
217 
218  return false;
219 }
220 
221 bool bBlackPiece::isAttacked(bBoard const& b, case_t const& cf) const
222 {
223  // king
224  if (isAttackedByPiece(b, cf, tPiece::W_KING, 1, -1)) return true;
225  if (isAttackedByPiece(b, cf, tPiece::W_KING, 1, 0)) return true;
226  if (isAttackedByPiece(b, cf, tPiece::W_KING, 1, 1)) return true;
227  if (isAttackedByPiece(b, cf, tPiece::W_KING, 0, 1)) return true;
228  if (isAttackedByPiece(b, cf, tPiece::W_KING, 0, -1)) return true;
229  if (isAttackedByPiece(b, cf, tPiece::W_KING, -1, -1)) return true;
230  if (isAttackedByPiece(b, cf, tPiece::W_KING, -1, 0)) return true;
231  if (isAttackedByPiece(b, cf, tPiece::W_KING, -1, 1)) return true;
232 
233  // rook, queen
234  if (isAttackedBySlider(b, cf, tPiece::W_ROOK, tPiece::W_QUEEN, -1, 0)) return true;
235  if (isAttackedBySlider(b, cf, tPiece::W_ROOK, tPiece::W_QUEEN, 1, 0)) return true;
236  if (isAttackedBySlider(b, cf, tPiece::W_ROOK, tPiece::W_QUEEN, 0, -1)) return true;
237  if (isAttackedBySlider(b, cf, tPiece::W_ROOK, tPiece::W_QUEEN, 0, 1)) return true;
238 
239  // bishop, queen
240  if (isAttackedBySlider(b, cf, tPiece::W_BISHOP, tPiece::W_QUEEN, -1, -1)) return true;
241  if (isAttackedBySlider(b, cf, tPiece::W_BISHOP, tPiece::W_QUEEN, 1, -1)) return true;
242  if (isAttackedBySlider(b, cf, tPiece::W_BISHOP, tPiece::W_QUEEN, -1, 1)) return true;
243  if (isAttackedBySlider(b, cf, tPiece::W_BISHOP, tPiece::W_QUEEN, 1, 1)) return true;
244 
245  // knight
246  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, 1, -2)) return true;
247  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, 1, 2)) return true;
248  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, 2, -1)) return true;
249  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, 2, 1)) return true;
250  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, -1, -2)) return true;
251  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, -1, 2)) return true;
252  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, -2, -1)) return true;
253  if (isAttackedByPiece(b, cf, tPiece::W_KNIGHT, -2, 1)) return true;
254 
255  if (bCase::rank(cf) > 1) {
256  if (isAttackedByPiece(b, cf, tPiece::W_PAWN, -1, -1)) return true;
257  if (isAttackedByPiece(b, cf, tPiece::W_PAWN, -1, 1)) return true;
258  /// @todo TOCHECK how about ep
259  }
260 
261  return false;
262 }
263 
266 {
267 }
268 
270 {
271 }
272 
275 {
276 }
277 
279 {
280 }
281 
282 /**
283  * Return true if position is attacked by opponent respecting move offsets
284  * @param b board
285  * @param cf field from
286  * @param cPiece attacking piece
287  * @param ri row increment
288  * @param ci col increment
289  * @return true/false
290  */
292  piece_t const cPiece, int8_t const ri, int8_t const ci) const
293 {
294  return (b.getPieceCtl(bCase::column(cf) + ci, bCase::rank(cf) + ri) == cPiece);
295 }
296 
297 /**
298  * Return true if position is attacked by opponent respecting move offsets
299  * @param b board
300  * @param cf field from
301  * @param cPiece first possible piece (rook/bishop)
302  * @param cPiece2 second possible piece (queen)
303  * @param ri row increment
304  * @param ci col increment
305  * @return true/false
306  */
308  piece_t const cPiece, piece_t const cPiece2,
309  int8_t const ri, int8_t const ci) const
310 {
311  rank_t newrank = bCase::rank(cf) + ri;
312  column_t newcol = bCase::column(cf) + ci;
313 
314  // slider move (queen, rook, bishop)
315  for (int8_t i = 0; i < 7; i++) {
316  // touch border?
317  if (newrank < 0 || newrank > 7) return false;
318  if (newcol < 0 || newcol > 7) return false;
319 
320  piece_t piece = b.getPiece(newcol, newrank);
321  if (piece) {
322  if (piece == cPiece) return true;
323  if (piece == cPiece2) return true;
324  // not empty, not opponent piece, so protected
325  return false;
326  }
327  newrank += ri; newcol += ci;
328  }
329  return false;
330 }
331 
332 /**
333  * Return true if king sees rook of own colour
334  * @param b board
335  * @param cf field from
336  * @param cPiece rook
337  * @param ci col increment
338  * @return true/false
339  */
340 bool bKing::kingSeesRook(bBoard const& b, case_t const& cf,
341  piece_t const cPiece, int8_t const ci) const
342 {
343  column_t newcol = bCase::column(cf) + ci;
344 
345  for (int8_t i = 0; i < 5; i++) {
346  // touch border?
347  if (newcol < 0 || newcol > 7) return false;
348 
349  piece_t p = b.getPiece(newcol, bCase::rank(cf));
350  if (p) {
351  if (p == cPiece) return true;
352  // not empty, other piece
353  return false;
354  }
355  newcol += ci;
356  }
357  return false;
358 }
359 
360 /** Check for in-check position, single step move
361  * used for King and Knight
362  */
363 int bPiece::addMove(bBoard const& b, case_t const& cf,
364  side_t const side,
365  int8_t const ri, int8_t const ci, bMoveList& ml) const
366 {
367  column_t newcol = bCase::column(cf) + ci;
368  rank_t newrank = bCase::rank(cf) + ri;
369 
370  if (newcol < 0 || newcol > 7) return 0;
371  if (newrank < 0 || newrank > 7) return 0;
372 
373  case_t to = bCase::coordToCase(newcol, newrank);
374  if (b.isFieldEmpty(to)) {
375  return ml.addMoveIfValid(b, bMove(cf, to), side);
376  } else if (bPiece::isOpponent(side, b.getPiece(to))) {
377  bMove m(cf, to);
378  m.setCapture();
379  return ml.addMoveIfValid(b, m, side);
380  }
381  return 0;
382 }
383 
384 /**
385  * Add moves for Queen, Rook and Bishop
386  * @return number of moves generated
387  */
388 int bPiece::addMoves(bBoard const& b, case_t const& cf,
389  side_t const side, int nMax,
390  int8_t const ri, int8_t const ci, bMoveList& ml) const
391 {
392  int nMoves = 0;
393  column_t newcol = bCase::column(cf) + ci;
394  rank_t newrank = bCase::rank(cf) + ri;
395 
396  while (--nMax >= 0) {
397  if (newcol < 0 || newcol > 7) return nMoves;
398  if (newrank < 0 || newrank > 7) return nMoves;
399 
400  case_t to = bCase::coordToCase(newcol, newrank);
401  if (b.isFieldEmpty(to)) {
402  nMoves += ml.addMoveIfValid(b, bMove(cf, to), side);
403  } else if (bPiece::isOpponent(side, b.getPiece(to))) {
404  bMove m(cf, to);
405  m.setCapture();
406  nMoves += ml.addMoveIfValid(b, m, side);
407  break;
408  } else {
409  // own colour, cannot jump
410  break;
411  }
412  newcol += ci;
413  newrank += ri;
414  }
415  return nMoves;
416 }
417 
418 /** Test move is possible, single step move
419  * non capture move
420  */
422  side_t const side,
423  int8_t const ri, bMoveList& ml) const
424 {
425  // no test on rank, as we remain on board
427  if (b.isFieldEmpty(to)) {
428  bMove m(cf, to);
429  return ml.addMoveIfValid(b, m, side);
430  }
431  return 0;
432 }
433 
435  side_t const side,
436  int8_t const ri, bMoveList& ml) const
437 {
438  // no test on rank, as we remain on board
440  if (b.isFieldEmpty(to)) {
441  bMove m(cf, to);
442  m.setEPPossible();
443  return ml.addMoveIfValid(b, m, side);
444  }
445  return 0;
446 }
447 
448 int bPawn::addCapturePawnMove(bBoard const& b, case_t const& cf,
449  side_t const side,
450  int8_t const ri, int8_t const ci, bMoveList& ml) const
451 {
452  column_t newcol = bCase::column(cf) + ci;
453 
454  if (newcol < 0 || newcol > 7) return 0;
455  // no test on rank, as we remain on board
456 
457  rank_t newrank = bCase::rank(cf) + ri;
458 
459  if (bPiece::isOpponent(side, b.getPiece(newcol, newrank))) {
460  bMove m(cf, bCase::coordToCase(newcol, newrank));
461  m.setCapture();
462  return ml.addMoveIfValid(b, m, side);
463  }
464  return 0;
465 }
466 
467 /** Test move is possible, single step move
468  * non capture move
469  */
471  side_t const side,
472  int8_t const ri, bMoveList& ml) const
473 {
474  // no test on new rank, as promotion is always in good rank
476  if (b.isFieldEmpty(to)) {
477  return ml.addPromotionIfValid(b, bMove(cf, to), side);
478  }
479  return 0;
480 }
481 
482 /** Test move is possible, single step move
483  * capture only move
484  */
486  side_t const side,
487  int8_t const ri, int8_t const ci, bMoveList& ml) const
488 {
489  column_t newcol = bCase::column(cf) + ci;
490 
491  if (newcol < 0 || newcol > 7) return 0;
492  // no test on new rank, as capture promotion is always in good rank
493 
494  rank_t newrank = bCase::rank(cf) + ri;
495 
496  if (bPiece::isOpponent(side, b.getPiece(newcol, newrank))) {
497  bMove m(cf, bCase::coordToCase(newcol, newrank));
498  m.setCapture();
499  return ml.addPromotionIfValid(b, m, side);
500  }
501  return 0;
502 }
503 
504 /** Test move is possible, e.p. move
505  * capture only move, no test if pawn is present
506  * only board e.p. flag is used in calling function
507  */
508 int bPawn::addEPMove(bBoard const& b, case_t const& cf,
509  side_t const side,
510  int8_t const ri, int8_t const ci, bMoveList& ml) const
511 {
512  // no test on column, as e.p. move is pre-calculated
513  // no test on new rank, as e.p. is always in good rank
514  case_t to = bCase::coordToCase(bCase::column(cf) + ci, bCase::rank(cf) + ri);
515  bMove m(cf, to);
516  m.setCapture();
517  m.setEPMove();
518  return ml.addMoveIfValid(b, m, side);
519 }
520 
521 int bWhitePawn::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
522  side_t const side)
523 {
524  int nMoves = 0;
525 
526  if (bCase::rank(cf) == 6) {
527  nMoves += addNonCapturePromotionMove(b, cf, side, 1, ml);
528  nMoves += addCapturePromotionMove(b, cf, side, 1, -1, ml);
529  nMoves += addCapturePromotionMove(b, cf, side, 1, 1, ml);
530  } else {
531  nMoves += addNonCapturePawnMove(b, cf, side, 1, ml);
532  if ((bCase::rank(cf) == 1) && b.isFieldEmpty(bCase::column(cf),2))
533  nMoves += addNonCaptureDoublePawnMove(b, cf, side, 2, ml);
534  nMoves += addCapturePawnMove(b, cf, side, 1, -1, ml);
535  nMoves += addCapturePawnMove(b, cf, side, 1, 1, ml);
536  if (bCase::rank(cf) == 4 && b.getEp()) {
537  if (bCase::column(cf) == bCase::column(b.getEp()) + 1) {
538  nMoves += addEPMove(b, cf, side, 1, -1, ml);
539  } else if (bCase::column(cf) == bCase::column(b.getEp()) - 1) {
540  nMoves += addEPMove(b, cf, side, 1, 1, ml);
541  }
542  }
543  }
544  return nMoves;
545 }
546 
547 int bBlackPawn::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
548  side_t const side)
549 {
550  int nMoves = 0;
551 
552  if (bCase::rank(cf) == 1) {
553  nMoves += addNonCapturePromotionMove(b, cf, side, -1, ml);
554  nMoves += addCapturePromotionMove(b, cf, side, -1, -1, ml);
555  nMoves += addCapturePromotionMove(b, cf, side, -1, 1, ml);
556  } else {
557  nMoves += addNonCapturePawnMove(b, cf, side, -1, ml);
558  if ((bCase::rank(cf) == 6) && b.isFieldEmpty(bCase::column(cf), 5))
559  nMoves += addNonCaptureDoublePawnMove(b, cf, side, -2, ml);
560  nMoves += addCapturePawnMove(b, cf, side, -1, -1, ml);
561  nMoves += addCapturePawnMove(b, cf, side, -1, 1, ml);
562  if (bCase::rank(cf) == 3 && b.getEp()) {
563  if (bCase::column(cf) == bCase::column(b.getEp()) + 1) {
564  nMoves += addEPMove(b, cf, side, -1, -1, ml);
565  } else if (bCase::column(cf) == bCase::column(b.getEp()) - 1) {
566  nMoves += addEPMove(b, cf, side, -1, 1, ml);
567  }
568  }
569  }
570  return nMoves;
571 }
572 
573 int bRook::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
574  side_t const side)
575 {
576  int nMoves = 0;
577 
578  nMoves += addMoves(b, cf, side, 7, -1, 0, ml);
579  nMoves += addMoves(b, cf, side, 7, 1, 0, ml);
580  nMoves += addMoves(b, cf, side, 7, 0, -1, ml);
581  nMoves += addMoves(b, cf, side, 7, 0, 1, ml);
582 
583  return nMoves;
584 }
585 
586 int bKnight::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
587  side_t const side)
588 {
589  int nMoves = 0;
590 
591  nMoves += addMove(b, cf, side, 1, 2, ml);
592  nMoves += addMove(b, cf, side, 1, -2, ml);
593  nMoves += addMove(b, cf, side, 2, 1, ml);
594  nMoves += addMove(b, cf, side, -2, 1, ml);
595  nMoves += addMove(b, cf, side, -1, 2, ml);
596  nMoves += addMove(b, cf, side, -1, -2, ml);
597  nMoves += addMove(b, cf, side, 2, -1, ml);
598  nMoves += addMove(b, cf, side, -2, -1, ml);
599 
600  return nMoves;
601 }
602 
603 int bBishop::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
604  side_t const side)
605 {
606  int nMoves = 0;
607 
608  nMoves += addMoves(b, cf, side, 7, -1, -1, ml);
609  nMoves += addMoves(b, cf, side, 7, 1, -1, ml);
610  nMoves += addMoves(b, cf, side, 7, -1, 1, ml);
611  nMoves += addMoves(b, cf, side, 7, 1, 1, ml);
612 
613  return nMoves;
614 }
615 
616 int bQueen::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
617  side_t const side)
618 {
619  int nMoves = 0;
620 
621  nMoves += addMoves(b, cf, side, 7, 0, -1, ml);
622  nMoves += addMoves(b, cf, side, 7, 0, 1, ml);
623  nMoves += addMoves(b, cf, side, 7, 1, -1, ml);
624  nMoves += addMoves(b, cf, side, 7, 1, 0, ml);
625  nMoves += addMoves(b, cf, side, 7, 1, 1, ml);
626  nMoves += addMoves(b, cf, side, 7, -1, -1, ml);
627  nMoves += addMoves(b, cf, side, 7, -1, 0, ml);
628  nMoves += addMoves(b, cf, side, 7, -1, 1, ml);
629 
630  return nMoves;
631 }
632 
633 int bKing::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
634  side_t const side)
635 {
636  int nMoves = 0;
637 
638  nMoves += addMove(b, cf, side, 0, -1, ml);
639  nMoves += addMove(b, cf, side, 0, 1, ml);
640  nMoves += addMove(b, cf, side, 1, -1, ml);
641  nMoves += addMove(b, cf, side, 1, 0, ml);
642  nMoves += addMove(b, cf, side, 1, 1, ml);
643  nMoves += addMove(b, cf, side, -1, -1, ml);
644  nMoves += addMove(b, cf, side, -1, 0, ml);
645  nMoves += addMove(b, cf, side, -1, 1, ml);
646 
647  return nMoves;
648 }
649 
650 int bWhiteKing::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
651  side_t const side)
652 {
653  int nMoves = bKing::GenerateMoves(b, cf, ml, side);
654 
655  // king not on original position, TODO: use absolute index
656  if ((bCase::column(cf) != 4) || (bCase::rank(cf) != 0)) return nMoves;
657 
658  // king in check
659  bWhiteKing* wking = static_cast<bWhiteKing *>(bPiece::getPieceClass(tPiece::W_KING));
660  if (wking->isAttacked(b, cf)) return nMoves;
661 
662  if (b.canCastle(tCFlags::WCASTLE_S)) {
663  // short castle
664  if (kingSeesRook(b, cf, tPiece::W_ROOK, 1)) {
665  // king is attacked by own rook, so it means it can castle
666  // TODO: use case constant instead of calculating
667  if (!wking->isAttacked(b, bCase::coordToCase(5, 0))) {
668  // king is not going over attacked field
669  bMove m(cf, bCase::coordToCase(bCase::column(cf) + 2, 0));
671  nMoves += ml.addMoveIfValid(b, m, side);
672  }
673  }
674  }
675 
676  if (b.canCastle(tCFlags::WCASTLE_L)) {
677  // long castle
678  if (kingSeesRook(b, cf, tPiece::W_ROOK, -1)) {
679  // king is attacked by own rook, so it means it can castle
680  // TODO: use case constant instead of calculating
681  if (!wking->isAttacked(b, bCase::coordToCase(3, 0))) {
682  // king is not going over attacked field
683  bMove m(cf, bCase::coordToCase(bCase::column(cf) - 2, 0));
685  nMoves += ml.addMoveIfValid(b, m, side);
686  }
687  }
688  }
689 
690  return nMoves;
691 }
692 
693 int bBlackKing::GenerateMoves(bBoard const& b, case_t const& cf, bMoveList& ml,
694  side_t const side)
695 {
696  int nMoves = bKing::GenerateMoves(b, cf, ml, side);
697 
698  // king not on original position, TODO: use absolute index
699  if ((bCase::column(cf) != 4) || (bCase::rank(cf) != 7)) return nMoves;
700 
701  // king in check
702  bBlackKing* bking = static_cast<bBlackKing *>(bPiece::getPieceClass(tPiece::B_KING));
703  if (bking->isAttacked(b, cf)) return nMoves;
704 
705  if (b.canCastle(tCFlags::BCASTLE_S)) {
706  // short castle
707  if (kingSeesRook(b, cf, tPiece::B_ROOK, 1)) {
708  // king is attacked by own rook, so it means it can castle
709  // TODO: use case constant instead of calculating
710  if (!bking->isAttacked(b, bCase::coordToCase(5, 7))) {
711  // king is not going over attacked field
712  bMove m(cf, bCase::coordToCase(bCase::column(cf) + 2, 7));
714  nMoves += ml.addMoveIfValid(b, m, side);
715  }
716  }
717  }
718 
719  if (b.canCastle(tCFlags::BCASTLE_L)) {
720  // long castle
721  if (kingSeesRook(b, cf, tPiece::B_ROOK, -1)) {
722  // king is attacked by own rook, so it means it can castle
723  // TODO: use case constant instead of calculating
724  if (!bking->isAttacked(b, bCase::coordToCase(3, 7))) {
725  // king is not going over attacked field
726  bMove m(cf, bCase::coordToCase(bCase::column(cf) - 2, 7));
728  nMoves += ml.addMoveIfValid(b, m, side);
729  }
730  }
731  }
732 
733  return nMoves;
734 }
735 
736 //-----------------------------------------------------------------------
737 // eof
This is the main include file, needs to be included before any other include.
int_fast8_t rank_t
Definition: belofte.h:96
uint8_t case_t
Definition: belofte.h:98
int_fast8_t column_t
Definition: belofte.h:97
@ BCASTLE_L
Definition: board.h:12
@ BCASTLE_S
Definition: board.h:12
@ WCASTLE_S
Definition: board.h:12
@ WCASTLE_L
Definition: board.h:12
bool canCastle(uint8_t const f) const
Definition: board.cpp:194
piece_t getPiece(case_t const bc) const
1 for white, 2 for black
Definition: board.cpp:138
case_t getEp() const
Definition: board.h:57
piece_t getPieceCtl(column_t const iColumn, rank_t const iRank) const
retrieve piece with bounds checking, return field empty in case of out of bounds
Definition: board.cpp:152
bool isFieldEmpty(case_t const bc) const
Definition: board.cpp:159
void setEPPossible()
Definition: move.h:145
void setCastleMove(uint16_t f)
Definition: move.h:138
void setCapture()
Definition: move.h:135
void setEPMove()
Definition: move.h:147
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:603
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:693
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:547
bBlackPiece()
Definition: piece.cpp:273
~bBlackPiece() override
Definition: piece.cpp:278
bool isAttacked(bBoard const &b, case_t const &cf) const override
Definition: piece.cpp:221
board
Definition: board.h:111
column_t column() const
Definition: move.cpp:56
static constexpr case_t coordToCase(column_t const c, rank_t const r)
Definition: move.h:40
rank_t rank() const
Definition: move.cpp:61
bool kingSeesRook(bBoard const &b, case_t const &cf, piece_t const cPiece, int8_t const ci) const
Return true if king sees rook of own colour.
Definition: piece.cpp:340
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) override
Definition: piece.cpp:633
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:586
Definition: move.h:164
uint8_t addMoveIfValid(bBoard const &b, bMove const &m, side_t const side)
Only add move to movelist if valid.
Definition: movelist.cpp:78
uint8_t addPromotionIfValid(bBoard const &b, bMove const &m, side_t const side)
Only add move to movelist if valid.
Definition: movelist.cpp:114
int addNonCapturePromotionMove(bBoard const &b, case_t const &cf, side_t const side, int8_t const ri, bMoveList &ml) const
Test move is possible, single step move non capture move.
Definition: piece.cpp:470
int addNonCapturePawnMove(bBoard const &b, case_t const &cf, side_t const side, int8_t const ri, bMoveList &ml) const
Test move is possible, single step move non capture move.
Definition: piece.cpp:421
int addNonCaptureDoublePawnMove(bBoard const &b, case_t const &cf, side_t const side, int8_t const ri, bMoveList &ml) const
Definition: piece.cpp:434
int addEPMove(bBoard const &b, case_t const &cf, side_t const side, int8_t const ri, int8_t const ci, bMoveList &ml) const
Test move is possible, e.p.
Definition: piece.cpp:508
int addCapturePawnMove(bBoard const &b, case_t const &cf, side_t const side, int8_t const ri, int8_t const ci, bMoveList &ml) const
Definition: piece.cpp:448
int addCapturePromotionMove(bBoard const &b, case_t const &cf, side_t const side, int8_t const ri, int8_t const ci, bMoveList &ml) const
Test move is possible, single step move capture only move.
Definition: piece.cpp:485
virtual ~bPieceColour()
Definition: piece.cpp:167
bPieceColour(side_t s)
Definition: piece.cpp:162
bool isAttackedByPiece(bBoard const &b, case_t const &cf, piece_t const cPiece, int8_t const ri, int8_t const ci) const
Return true if position is attacked by opponent respecting move offsets.
Definition: piece.cpp:291
bool isAttackedBySlider(bBoard const &b, case_t const &cf, piece_t const cPiece, piece_t const cPiece2, int8_t const ri, int8_t const ci) const
Return true if position is attacked by opponent respecting move offsets.
Definition: piece.cpp:307
piece representation
Definition: piece.h:86
int addMove(bBoard const &b, case_t const &cf, side_t const side, int8_t const ri, int8_t const ci, bMoveList &ml) const
Check for in-check position, single step move used for King and Knight.
Definition: piece.cpp:363
static bool isOwnColour(side_t const s, piece_t const p)
static class member function
Definition: piece.cpp:153
side_t toMove() const
Definition: piece.cpp:123
static bPiece * getPieceClass(piece_t const piece)
static class member function
Definition: piece.cpp:87
static cpiece_t getPieceChar(piece_t const p)
static class member function
Definition: piece.cpp:133
int addMoves(bBoard const &b, case_t const &cf, side_t const side, int nMax, int8_t const ri, int8_t const ci, bMoveList &ml) const
Add moves for Queen, Rook and Bishop.
Definition: piece.cpp:388
piece_t getPiece() const
Definition: piece.h:100
virtual ~bPiece()
Definition: piece.cpp:28
static bool isOpponent(side_t const s, piece_t const p)
static class member function
Definition: piece.cpp:145
bPiece()
Definition: piece.cpp:19
static const std::string getPieceStrUpper(piece_t const piece)
static class member function
Definition: piece.cpp:93
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:616
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:573
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:650
int GenerateMoves(bBoard const &b, case_t const &cf, bMoveList &ml, side_t const side) final
Definition: piece.cpp:521
~bWhitePiece() override
Definition: piece.cpp:269
bool isAttacked(bBoard const &b, case_t const &cf) const override
Check if piece on position is attacked, start with piece always on board and then with pieces with gr...
Definition: piece.cpp:178
bWhitePiece()
Definition: piece.cpp:264
Allow index mapper for char values of piece into int in 1-12 range to reduce space and easy initialis...
Definition: eval.h:43
static bPiece * pieceinstances[tPiece::P_SIZE]
Definition: piece.cpp:16
static piece_t bPieceIndex[128]
Definition: piece.cpp:14
static cpiece_t bPieceMapper[tPiece::P_SIZE]
Definition: piece.cpp:15
constexpr uint16_t LONG_CASTLE
Definition: move.h:75
constexpr uint16_t SHORT_CASTLE
Definition: move.h:74
void bPiece_dtor()
Definition: piece.cpp:77
void bPiece_ctor()
Definition: piece.cpp:32
#define S_P_EMPTY
Definition: piece.h:17
#define S_P_ROOK
Definition: piece.h:16
enum tSide side_t
Definition: piece.h:70
@ C_W_KNIGHT
Definition: piece.h:23
@ C_W_PAWN
Definition: piece.h:24
@ C_B_QUEEN
Definition: piece.h:31
@ C_W_ROOK
Definition: piece.h:26
@ C_EMPTY
Definition: piece.h:20
@ C_B_BISHOP
Definition: piece.h:27
@ C_W_QUEEN
Definition: piece.h:25
@ C_B_KNIGHT
Definition: piece.h:29
@ C_B_PAWN
Definition: piece.h:30
@ C_W_BISHOP
Definition: piece.h:21
@ C_B_ROOK
Definition: piece.h:32
@ C_B_KING
Definition: piece.h:28
@ C_W_KING
Definition: piece.h:22
@ W_PAWN
Definition: piece.h:39
@ W_KNIGHT
Definition: piece.h:39
@ P_SIZE
Definition: piece.h:41
@ B_BISHOP
Definition: piece.h:40
@ W_ROOK
Definition: piece.h:39
@ B_ROOK
Definition: piece.h:40
@ W_QUEEN
Definition: piece.h:39
@ B_KING
Definition: piece.h:40
@ P_EMPTY
Definition: piece.h:38
@ B_KNIGHT
Definition: piece.h:40
@ W_KING
Definition: piece.h:39
@ B_PAWN
Definition: piece.h:40
@ B_QUEEN
Definition: piece.h:40
@ W_BISHOP
Definition: piece.h:39
enum tPiece piece_t
Definition: piece.h:44
#define S_P_PAWN
Definition: piece.h:14
#define S_P_QUEEN
Definition: piece.h:15
enum tCPiece cpiece_t
Definition: piece.h:35
#define S_P_BISHOP
Definition: piece.h:11
#define S_P_KNIGHT
Definition: piece.h:13
#define S_P_KING
Definition: piece.h:12
tSide
Definition: piece.h:64
@ SIDE_BLACK
@ SIDE_WHITE
@ SIDE_UNDEFINED