static bool add_piece_moves(list_t * list, const board_t * board, int to, bool legal, bool stop) { int me; const sq_t * ptr; int from, piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); me = board->turn; for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; if (PIECE_ATTACK(board,piece,from,to)) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; LIST_ADD(list,MOVE_MAKE(from,to)); } } } return false; }
bool pseudo_is_legal(int move, board_t * board) { int me, opp; int from, to; int piece; bool legal; int king; undo_t undo[1]; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[from]; ASSERT(COLOUR_IS(piece,me)); // slow test for en-passant captures if (MOVE_IS_EN_PASSANT(move)) { move_do(board,move,undo); legal = !IS_IN_CHECK(board,me); move_undo(board,move,undo); return legal; } // king moves (including castle) if (PIECE_IS_KING(piece)) { legal = !is_attacked(board,to,opp); if (DEBUG) { ASSERT(board->square[from]==piece); board->square[from] = Empty; ASSERT(legal==!is_attacked(board,to,opp)); board->square[from] = piece; } return legal; } // pins if (is_pinned(board,from,me)) { king = KING_POS(board,me); return DELTA_INC_LINE(king-to) == DELTA_INC_LINE(king-from); // does not discover the line } return true; }
static bool add_pawn_moves(list_t * list, const board_t * board, int to, bool legal, bool stop) { int me; int inc; int pawn; int from; int piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(board->square[to]==Empty); me = board->turn; inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); from = to - inc; piece = board->square[from]; if (piece == pawn) { // single push if (!legal || !is_pinned(board,from,me)) { if (stop) return true; add_pawn_move(list,from,to); } } else if (piece == Empty && PAWN_RANK(to,me) == Rank4) { // double push from = to - (2*inc); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } return false; }
bool move_is_check(int move, board_t * board) { undo_t undo[1]; bool check; int me, opp, king; int from, to, piece; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // slow test for complex moves if (MOVE_IS_SPECIAL(move)) { move_do(board,move,undo); check = IS_IN_CHECK(board,board->turn); move_undo(board,move,undo); return check; } // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[from]; ASSERT(COLOUR_IS(piece,me)); // direct check if (PIECE_ATTACK(board,piece,to,king)) return true; // indirect check if (is_pinned(board,from,opp) && DELTA_INC_LINE(king-to) != DELTA_INC_LINE(king-from)) { return true; } return false; }
bool pseudo_is_legal( int move, board_t *board ) { int me; ASSERT(move_is_ok(move)); ASSERT(board != NULL); // init me = board->turn; // pins if( is_pinned(board, move, me) ) { return false; } return true; }
static bool add_pawn_captures(list_t * list, const board_t * board, int to, bool legal, bool stop) { int me; int inc; int pawn; int from; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(COLOUR_IS(board->square[to],COLOUR_OPP(board->turn))); me = board->turn; inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); from = to - (inc-1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; add_pawn_move(list,from,to); } } from = to - (inc+1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; add_pawn_move(list,from,to); } } if (board->ep_square != SquareNone && to == SQUARE_EP_DUAL(board->ep_square)) { ASSERT(PAWN_RANK(to,me)==Rank5); ASSERT(PIECE_IS_PAWN(board->square[to])); to = board->ep_square; ASSERT(PAWN_RANK(to,me)==Rank6); ASSERT(board->square[to]==Empty); from = to - (inc-1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant)); } } from = to - (inc+1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant)); } } } return false; }
static void add_quiet_checks(list_t * list, const board_t * board) { int me, opp; int king; const sq_t * ptr, * ptr_2; int from, to, sq; int piece; const inc_t * inc_ptr; int inc; int pawn; int rank; int pin[8+1]; ASSERT(list!=NULL); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); find_pins(pin,board); // indirect checks for (ptr = pin; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; ASSERT(is_pinned(board,from,opp)); if (PIECE_IS_PAWN(piece)) { inc = PAWN_MOVE_INC(me); rank = PAWN_RANK(from,me); if (rank != Rank7) { // promotes are generated with captures to = from + inc; if (board->square[to] == Empty) { if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); if (rank == Rank2) { to = from + (2*inc); if (board->square[to] == Empty) { ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king)); ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } } else if (PIECE_IS_SLIDER(piece)) { for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) { for (to = from+inc; board->square[to] == Empty; to += inc) { ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } else { for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; if (board->square[to] == Empty) { if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } // piece direct checks for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king for (ptr_2 = pin; (sq=*ptr_2) != SquareNone; ptr_2++) { if (sq == from) goto next_piece; } ASSERT(!is_pinned(board,from,opp)); piece = board->square[from]; inc_ptr = PIECE_INC(piece); if (PIECE_IS_SLIDER(piece)) { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { for (to = from+inc; board->square[to] == Empty; to += inc) { if (PIECE_ATTACK(board,piece,to,king)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } else { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; if (board->square[to] == Empty) { if (PSEUDO_ATTACK(piece,king-to)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } next_piece: ; } // pawn direct checks inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); to = king - (inc-1); ASSERT(PSEUDO_ATTACK(pawn,king-to)); from = to - inc; if (board->square[from] == pawn) { if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } else { from = to - (2*inc); if (board->square[from] == pawn) { if (PAWN_RANK(from,me) == Rank2 && board->square[to] == Empty && board->square[from+inc] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } to = king - (inc+1); ASSERT(PSEUDO_ATTACK(pawn,king-to)); from = to - inc; if (board->square[from] == pawn) { if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } else { from = to - (2*inc); if (board->square[from] == pawn) { if (PAWN_RANK(from,me) == Rank2 && board->square[to] == Empty && board->square[from+inc] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } }
/* * mg_app_prom() * Append all legal promotion moves to the specified list. * No conditions need be assured. * Optionally there are left out obviously non-checking moves. */ Eximpl void mg_app_prom( register Xconst Board* bp, Movelist* lp, Bool needcheck) { register rColour self; register rColour enemy; register Xconst Field* p; register Xconst Field* tp; register rPosition pos; register rPosition tpos; register rPosition kpos; register rPieceSet ckset; register int pindir; register const Field* ep; register int delta; register int i; register Bool needckdirect; register rPosition ekpos; register Xconst Field* ekp; register int ckdir; PieceSet amask; self = bp->b_tomove; enemy = opp_colour(self); kpos = K_POS(bp, self); ckset = F_DATT(&(bp->b_f[kpos])) & COLOUR_MASK(enemy); /* those say check */ if( min2elems(ckset) ) { return; /* double check */ } if( needcheck ) { amask = COLOUR_MASK(self); ekp = &(bp->b_f[ ekpos = K_POS(bp, enemy) ]); } /* * Scan enemies base line to find own promotion candidates: */ p = &(bp->b_f[ pos = MK_POS(0, BAS_LIN(enemy)) ]); for( ; p->f_c != border ; pos += MK_DELTA(1,0), p += MK_DELTA(1,0) ) { if( (p->f_c == self) && (p->f_f == bauer) ) { pindir = att_dir(kpos, pos); needckdirect = ( needcheck && ( ! dam_dir(att_dir(pos, ekpos)) || ! (F_DATT(p) & F_IATT(ekp) & amask) ) ); for( i=0 ; i<2 ; ++i ) { tp = &(bp->b_f[ tpos = pos + (i ? bau_left:bau_right)[self] ]); if( tp->f_c == enemy ) { /* pseudo-legal */ if( ( !ckset || (ckset == SET1(tp->f_idx)) ) /* existing check removed */ && ( no_dir(pindir) || (pindir == att_dir(kpos, tpos)) || ! is_pinned(bp, pos) ) /* no check uncovered */ ) { if( ! needckdirect ) { app_4_proms(lp, pos, tpos, p->f_idx); } else if( ! no_dir(ckdir = att_dir(tpos, ekpos)) ) { app_ck_proms(lp, pos, tpos, p->f_idx, ckdir); } } } } tp = &(bp->b_f[ tpos = pos + bau_mov[self] ]); if( tp->f_c == empty ) { /* pseudo-legal */ if( ( !ckset || ( (ckset & F_DATT(tp)) && trm_dir(att_dir(kpos, tpos)) ) ) /* existing check may be removed */ && ( no_dir(pindir) || (pindir == att_dir(kpos, tpos)) || ! is_pinned(bp, pos) ) /* no check uncovered */ ) { if( ckset ) { delta = dam_mov[att_dir(kpos, tpos)]; ep = tp; do { ep += delta; } while( ep->f_c == empty ); if( (ep->f_c == enemy) && (ckset == SET1(ep->f_idx)) ) { if( ! needckdirect ) { app_4_proms(lp, pos, tpos, p->f_idx); } else if( ! no_dir(ckdir = att_dir(tpos, ekpos)) ) { app_ck_proms(lp, pos, tpos, p->f_idx, ckdir); } } } else { if( ! needckdirect ) { app_4_proms(lp, pos, tpos, p->f_idx); } else if( ! no_dir(ckdir = att_dir(tpos, ekpos)) ) { app_ck_proms(lp, pos, tpos, p->f_idx, ckdir); } } } } } } /* for pos, p */ }
/* * mg_app_ep() * Append all legal e.p. moves to the specified list. * No conditions need be assured. */ Eximpl void mg_app_ep( register Xconst Board* bp, register Movelist* lp) { register rColour self; register rPosition tpos; register rPosition pos; register rPosition kpos; register int i; register Xconst Field* p; register rPieceSet emask; register int dir; Move m; if( no_pos(bp->b_ep) ) { return; /* no (double step) target */ } self = bp->b_tomove; tpos = bp->b_ep + bau_mov[self]; for( i=0 ; i<2 ; ++i ) { pos = tpos - (i ? bau_left : bau_right)[self]; p = &( bp->b_f[pos] ); if( (p->f_c != self) || (p->f_f != bauer) ) { continue; } /* * Well, we have a target for e.p. (made double step), * and a B in the correct position to beat it. * Whether this goes into the move list depends now * on the legality of the move, i.e. * - an existing check must be removed * - no new check must be opened. * When there is an existing check, which is not directly * by the target we cannot remove it by beating e.p. * (topologically impossible). * It is also impossible for a B to say double check. */ kpos = K_POS(bp, self); emask = COLOUR_MASK(opp_colour(self)); if( F_DATT(&(bp->b_f[kpos])) & emask ) { /* self in check */ if( F_DATT(&(bp->b_f[kpos])) & emask & ~SET1(bp->b_f[bp->b_ep].f_idx) ) { continue; /* cannot be removed */ } /* * In direct check by the B to be beaten e.p. * This reduces the possible uncoverings: */ if( dam_dir(att_dir(pos, kpos)) && (F_IATT(&(bp->b_f[kpos])) & emask & F_DATT(p)) ) { /* . * . * B b . * K . . * Pinned vertically => illegal */ continue; } } else { /* self not in check */ /* * When removing just the enemy at "b_ep" would discover * a check on a L line, our king could have been beaten * instead of the double step (=> illegal condition). * Discovering vertically through "b_ep" is impossible * as blocked by our own B. * Discovering horizontally through "b_ep" is possible * through both B, only. * Remains to test uncovering through our own B. */ if( F_IATT(&(bp->b_f[kpos])) & emask & F_DATT(p) ) { dir = att_dir(kpos, pos); if( dam_dir(dir) && (lin_dir(dir) != lin_dir(att_dir(pos,tpos))) && is_pinned(bp, pos) ) { continue; /* pinned, and leaves pinning */ } } if( ! ep_legal(bp, pos, tpos, kpos) ) { continue; } } /* no legality objections to the move */ m.m_from = pos; m.m_to = tpos; m.m_fig = bauer; m.m_idx = p->f_idx; m.m_value = 0; m.m_attr = 0; app_move(&m, lp); } /* loop over left/right */ }
static int move_from_lan(const char string[], const board_t * board) { int len; int move; int promote; char s[256]; int from, to; int colour; int inc; int piece_char; int n; const uint8 * ptr; int piece; int side; ASSERT(string!=NULL); ASSERT(board_is_ok(board)); // init len = strlen(string); if (len != 7) return MoveNone; move = MoveNone; colour = board->turn; // promote promote = 0; switch (string[6]) { case '?': // not a promotion break; case 'N': promote = MovePromoteKnight; break; case 'B': promote = MovePromoteBishop; break; case 'R': promote = MovePromoteRook; break; case 'Q': promote = MovePromoteQueen; break; default: return MoveNone; break; } // to square s[0] = string[4]; s[1] = string[5]; s[2] = '\0'; to = square_from_string(s); if (to == SquareNone) return MoveNone; // known from square? if (string[1] != '?' && string[2] != '?') { // from square s[0] = string[1]; s[1] = string[2]; s[2] = '\0'; from = square_from_string(s); if (from == SquareNone) return MoveNone; // convert "king slide" castling to KxR if (piece_is_king(board->square[from]) && square_rank(to) == square_rank(from) && abs(to-from) > 1) { side = (to > from) ? SideH : SideA; to = board->castle[colour][side]; if (to == SquareNone) return MoveNone; } // move move = move_make(from,to) | promote; return move; } // pawn non-capture? if (string[0] == '?' && string[1] == '?') { if (board->square[to] != Empty) return MoveNone; // useful? inc = (colour_is_white(colour)) ? +16 : -16; from = to - inc; if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) { from -= inc; } if (board->square[from] != piece_make_pawn(colour)) { // useful? return MoveNone; } // move move = move_make(from,to) | promote; return move; } // pawn capture? piece_char = string[0]; if (piece_char == '?' && string[1] != '?') { piece_char = 'P'; } // attack loop n = 0; for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; if (toupper(piece_to_char(piece)) == piece_char) { if (piece_attack(board,piece,from,to)) { if (true && (string[1] == '?' || file_to_char(square_file(from)) == string[1]) && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) { if (!is_pinned(board,from,to,colour)) { move = move_make(from,to) | promote; n++; } } } } } if (n != 1) move = MoveNone; return move; }