bool is_pinned(const board_t * board, int square, int colour) { int from, to; int inc; int sq, piece; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(square)); ASSERT(COLOUR_IS_OK(colour)); from = square; to = KING_POS(board,colour); inc = DELTA_INC_LINE(to-from); if (inc == IncNone) return false; // not a line sq = from; do sq += inc; while (board->square[sq] == Empty); if (sq != to) return false; // blocker sq = from; do sq -= inc; while ((piece=board->square[sq]) == Empty); return COLOUR_IS(piece,COLOUR_OPP(colour)) && SLIDER_ATTACK(piece,inc); }
static bool is_passed(const board_t * board, int to) { int t2; int me, opp; int file, rank; me = board->turn; opp = COLOUR_OPP(me); file = SQUARE_FILE(to); rank = PAWN_RANK(to,me); t2 = board->pawn_file[me][file] | BitRev[board->pawn_file[opp][file]]; // passed pawns if ((t2 & BitGT[rank]) == 0) { if (((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitGT[rank]) == 0) { return true; } } 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; }
int see_square(const board_t * board, int to, int colour) { int att, def; alists_t alists[1]; alist_t * alist; int piece_value; int piece; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(COLOUR_IS_OK(colour)); ASSERT(COLOUR_IS(board->square[to],COLOUR_OPP(colour))); // build attacker list att = colour; alist = alists->alist[att]; ALIST_CLEAR(alist); alist_build(alist,board,to,att); if (alist->size == 0) return 0; // no attacker => stop SEE // build defender list def = COLOUR_OPP(att); alist = alists->alist[def]; ALIST_CLEAR(alist); alist_build(alist,board,to,def); // captured piece piece = board->square[to]; ASSERT(piece_is_ok(piece)); ASSERT(COLOUR_IS(piece,def)); piece_value = VALUE_PIECE(piece); // SEE search return see_rec(alists,board,att,to,piece_value); }
static void find_pins(int list[], const board_t * board) { int me, opp; int king; const sq_t * ptr; int from; int piece; int delta; int inc; int sq; int capture; int pin; ASSERT(list!=NULL); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; delta = king - from; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(piece,delta)) { ASSERT(PIECE_IS_SLIDER(piece)); inc = DELTA_INC_LINE(delta); ASSERT(inc!=IncNone); ASSERT(SLIDER_ATTACK(piece,inc)); sq = from; do sq += inc; while ((capture=board->square[sq]) == Empty); ASSERT(sq!=king); if (COLOUR_IS(capture,me)) { pin = sq; do sq += inc; while (board->square[sq] == Empty); if (sq == king) *list++ = pin; } } } *list = SquareNone; }
void move_do_null(board_t * board, undo_t * undo) { int sq; ASSERT(board!=NULL); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // initialise undo undo->turn = board->turn; undo->ep_square = board->ep_square; undo->ply_nb = board->ply_nb; undo->cap_sq = board->cap_sq; undo->moving_piece = board->moving_piece; undo->key = board->key; // update key stack ASSERT(board->sp<StackSize); board->stack[board->sp++] = board->key; // update turn board->turn = COLOUR_OPP(board->turn); board->key ^= RANDOM_64(RandomTurn); // update en-passant square sq = board->ep_square; if (sq != SquareNone) { board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA); board->ep_square = SquareNone; } // update move number board->ply_nb = 0; // HACK: null move is considered as a conversion // update last square board->cap_sq = SquareNone; board->moving_piece = PieceNone256; // debug ASSERT(board_is_ok(board)); }
static bool simple_stalemate(const board_t * board) { int me, opp; int king; int opp_flag; int from, to; int capture; const inc_t * inc_ptr; int inc; ASSERT(board!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // lone king? me = board->turn; if (board->piece_size[me] != 1 || board->pawn_size[me] != 0) return false; // no // king in a corner? king = KING_POS(board,me); if (king != A1 && king != H1 && king != A8 && king != H8) return false; // no // init opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // king can move? from = king; for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; capture = board->square[to]; if (capture == Empty || FLAG_IS(capture,opp_flag)) { if (!is_attacked(board,to,opp)) return false; // legal king move } } // no legal move ASSERT(board_is_stalemate((board_t*)board)); return true; }
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; }
static int see_rec(alists_t * alists, const board_t * board, int colour, int to, int piece_value) { int from, piece; int value; ASSERT(alists!=NULL); ASSERT(board!=NULL); ASSERT(COLOUR_IS_OK(colour)); ASSERT(SQUARE_IS_OK(to)); ASSERT(piece_value>0); // find the least valuable attacker from = alist_pop(alists->alist[colour],board); if (from == SquareNone) return 0; // no more attackers // find hidden attackers alists_hidden(alists,board,from,to); // calculate the capture value value = +piece_value; // captured piece if (value == ValueKing) return value; // do not allow an answer to a king capture piece = board->square[from]; ASSERT(piece_is_ok(piece)); ASSERT(COLOUR_IS(piece,colour)); piece_value = VALUE_PIECE(piece); // promote if (piece_value == ValuePawn && SQUARE_IS_PROMOTE(to)) { // HACK: PIECE_IS_PAWN(piece) ASSERT(PIECE_IS_PAWN(piece)); piece_value = ValueQueen; value += ValueQueen - ValuePawn; } value -= see_rec(alists,board,COLOUR_OPP(colour),to,piece_value); if (value < 0) value = 0; return value; }
void move_do_null( undo_t * undo) { ASSERT(undo!=NULL); //ASSERT(board_is_legal(board)); // initialise undo undo->turn = Turn; undo->key = Key; undo->lock = Lock; // update key stack Stack[Sp++] = Lock; Ply_nb = 0; // update turn Turn = COLOUR_OPP(Turn); Key ^= g_ZobristKeyPlayer; Lock ^= g_ZobristLockPlayer; }
void move_do(board_t * board, int move, undo_t * undo) { int me, opp; int from, to; int piece, pos, capture; int old_flags, new_flags; int delta; int sq; int pawn, rook; ASSERT(board!=NULL); ASSERT(move_is_ok(move)); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); // initialise undo undo->capture = false; undo->turn = board->turn; undo->flags = board->flags; undo->ep_square = board->ep_square; undo->ply_nb = board->ply_nb; undo->cap_sq = board->cap_sq; undo->opening = board->opening; undo->endgame = board->endgame; undo->key = board->key; undo->pawn_key = board->pawn_key; undo->material_key = board->material_key; // 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)); // update key stack ASSERT(board->sp<StackSize); board->stack[board->sp++] = board->key; // update turn board->turn = opp; board->key ^= RANDOM_64(RandomTurn); // update castling rights old_flags = board->flags; new_flags = old_flags & CastleMask[from] & CastleMask[to]; board->flags = new_flags; board->key ^= Castle64[new_flags^old_flags]; // HACK // update en-passant square if ((sq=board->ep_square) != SquareNone) { board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA); board->ep_square = SquareNone; } if (PIECE_IS_PAWN(piece)) { delta = to - from; if (delta == +32 || delta == -32) { pawn = PAWN_MAKE(opp); if (board->square[to-1] == pawn || board->square[to+1] == pawn) { board->ep_square = (from + to) / 2; board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(to)-FileA); } } } // update move number (captures are handled later) board->ply_nb++; if (PIECE_IS_PAWN(piece)) board->ply_nb = 0; // conversion // update last square board->cap_sq = SquareNone; // remove the captured piece sq = to; if (MOVE_IS_EN_PASSANT(move)) sq = SQUARE_EP_DUAL(sq); if ((capture=board->square[sq]) != Empty) { ASSERT(COLOUR_IS(capture,opp)); ASSERT(!PIECE_IS_KING(capture)); undo->capture = true; undo->capture_square = sq; undo->capture_piece = capture; undo->capture_pos = board->pos[sq]; square_clear(board,sq,capture,true); board->ply_nb = 0; // conversion board->cap_sq = to; } // move the piece if (MOVE_IS_PROMOTE(move)) { // promote undo->pawn_pos = board->pos[from]; square_clear(board,from,piece,true); piece = move_promote(move); // insert the promote piece in MV order for (pos = board->piece_size[me]; pos > 0 && piece > board->square[board->piece[me][pos-1]]; pos--) // HACK ; square_set(board,to,piece,pos,true); board->cap_sq = to; } else { // normal move square_move(board,from,to,piece,true); } // move the rook in case of castling if (MOVE_IS_CASTLE(move)) { rook = Rook64 | COLOUR_FLAG(me); // HACK if (to == G1) { square_move(board,H1,F1,rook,true); } else if (to == C1) { square_move(board,A1,D1,rook,true); } else if (to == G8) { square_move(board,H8,F8,rook,true); } else if (to == C8) { square_move(board,A8,D8,rook,true); } else { ASSERT(false); } } // debug ASSERT(board_is_ok(board)); }
void attack_set(attack_t * attack, const board_t * board) { int me, opp; const sq_t * ptr; int from, to; int inc; int pawn; int delta, piece; int sq; ASSERT(attack!=NULL); ASSERT(board!=NULL); // init attack->dn = 0; me = board->turn; opp = COLOUR_OPP(me); to = KING_POS(board,me); // pawn attacks inc = PAWN_MOVE_INC(opp); pawn = PAWN_MAKE(opp); from = to - (inc-1); if (board->square[from] == pawn) { attack->ds[attack->dn] = from; attack->di[attack->dn] = IncNone; attack->dn++; } from = to - (inc+1); if (board->square[from] == pawn) { attack->ds[attack->dn] = from; attack->di[attack->dn] = IncNone; attack->dn++; } // piece attacks for (ptr = &board->piece[opp][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; delta = to - from; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(piece,delta)) { inc = IncNone; if (PIECE_IS_SLIDER(piece)) { // check for blockers inc = DELTA_INC_LINE(delta); ASSERT(inc!=IncNone); sq = from; do sq += inc; while (board->square[sq] == Empty); if (sq != to) continue; // blocker => next attacker } attack->ds[attack->dn] = from; attack->di[attack->dn] = -inc; // HACK attack->dn++; } } attack->ds[attack->dn] = SquareNone; attack->di[attack->dn] = IncNone; // debug ASSERT(attack_is_ok(attack)); }
bool move_is_pseudo( int move, board_t *board ) { int me, opp; int from, to; int piece, capture; ASSERT(move_is_ok(move)); ASSERT(board != NULL); // init me = board->turn; opp = COLOUR_OPP(board->turn); // from from = MOVE_FROM(move); ASSERT(SQUARE_IS_OK(from)); piece = board->square[from]; if(INDEX_TO_COLOUR(piece) != me) return false; // to to = MOVE_TO(move); ASSERT(SQUARE_IS_OK(to)); capture = board->square[to]; if( INDEX_TO_COLOUR(capture) == me ) return false; // move switch(INDEX_TO_PIECE(piece)) { case RedKing: if(KING_IN_CITY(to) && KLegalDt[to - from + 256]) return true; if(EQUAL_FILE(from, to) && INDEX_TO_PIECE(capture) == BlackKing) { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; if(FileCapMin[row][board->file[col]] + col == to) return true; } return false; case BlackKing: if(KING_IN_CITY(to) && KLegalDt[to - from + 256]) return true; if(EQUAL_FILE(from, to) && INDEX_TO_PIECE(capture) ==RedKing) { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; if(FileCapMax[row][board->file[col]] + col == to) return true; } return false; case RedAdvisor: case BlackAdvisor: if(ADVISOR_IN_CITY(to) && ALegalDt[to - from + 256]) return true; return false; case RedBishop: case BlackBishop: if(BISHOP_IN_CITY(to) && BLegalDt[to - from + 256] && board->square[(to + from) >> 1] == PieceNone)// return true; return false; case RedKnight: case BlackKnight: if(NLegalDt[to - from + 256] && board->square[from + NLegalDt[to - from + 256]] == PieceNone)// return true; return false; case RedRook: case BlackRook: if(capture) { if(EQUAL_FILE(from, to)) { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; if(FileCapMax[row][board->file[col]] + col == to || FileCapMin[row][board->file[col]] + col == to) return true; } else if(EQUAL_RANK(from, to)) { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; if(RankCapMax[col][board->rank[row]] + (row << 4) == to || RankCapMin[col][board->rank[row]] + (row << 4) == to) return true; } } else { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; int to_row = SQUARE_RANK(to) - 3; int to_col = SQUARE_FILE(to) - 3; int rowbit = board->rank[row]; int colbit = board->file[col]; if(EQUAL_FILE(from, to)) { //if(FileNonCapMin[row][board->file[col]] + col <= to && to <= FileNonCapMax[row][board->file[col]] + col) if(PinNb[row][to_row][colbit] == 0) return true; } else if(EQUAL_RANK(from, to)) { //if(RankNonCapMin[col][board->rank[row]] + (row << 4) <= to && to <= RankNonCapMax[col][board->rank[row]] + (row << 4)) if(PinNb[col][to_col][rowbit] == 0) return true; } } return false; case RedCannon: case BlackCannon: if(capture) { if(EQUAL_RANK(from, to)) { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; if(CannonRankCapMax[col][board->rank[row]] + (row << 4) == to || CannonRankCapMin[col][board->rank[row]] + (row << 4) == to) return true; } else if(EQUAL_FILE(from, to)) { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; if(CannonFileCapMax[row][board->file[col]] + col == to || CannonFileCapMin[row][board->file[col]] + col == to) return true; } } else { int row=SQUARE_RANK(from) - 3; int col=SQUARE_FILE(from) - 3; int to_row = SQUARE_RANK(to) - 3; int to_col = SQUARE_FILE(to) - 3; int rowbit = board->rank[row]; int colbit = board->file[col]; if(EQUAL_RANK(from, to)) { //if(RankNonCapMin[col][board->rank[row]] + (row << 4) <= to && to <= RankNonCapMax[col][board->rank[row]] + (row << 4)) if(PinNb[col][to_col][rowbit] == 0) return true; } else if(EQUAL_FILE(from, to)) { //if(FileNonCapMin[row][board->file[col]] + col <= to&& to <= FileNonCapMax[row][board->file[col]] + col) if(PinNb[row][to_row][colbit] == 0) return true; } } return false; case BlackPawn: if((from + 16) == to) return true; if(SQUARE_COLOUR(from) == Red) { if((from - 1) == to || (from + 1) == to) return true; } return false; case RedPawn: if((from - 16) == to) return true; if(SQUARE_COLOUR(from) == Black) { if((from - 1) == to || (from + 1) == to) return true; } default: return false; } return false; }
static bool gen_evasions(list_t * list, const board_t * board, const attack_t * attack, bool legal, bool stop) { int me, opp; int opp_flag; int king; const inc_t * inc_ptr; int inc; int to; int piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(board_is_check(board)); ASSERT(ATTACK_IN_CHECK(attack)); // init LIST_CLEAR(list); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); king = KING_POS(board,me); for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { if (inc != -attack->di[0] && inc != -attack->di[1]) { // avoid escaping along a check line to = king + inc; piece = board->square[to]; if (piece == Empty || FLAG_IS(piece,opp_flag)) { if (!legal || !is_attacked(board,to,opp)) { if (stop) return true; LIST_ADD(list,MOVE_MAKE(king,to)); } } } } if (attack->dn >= 2) return false; // double check, we are done // single check ASSERT(attack->dn==1); // capture the checking piece if (add_pawn_captures(list,board,attack->ds[0],legal,stop) && stop) return true; if (add_piece_moves(list,board,attack->ds[0],legal,stop) && stop) return true; // interpose a piece inc = attack->di[0]; if (inc != IncNone) { // line for (to = king+inc; to != attack->ds[0]; to += inc) { ASSERT(SQUARE_IS_OK(to)); ASSERT(board->square[to]==Empty); if (add_pawn_moves(list,board,to,legal,stop) && stop) return true; if (add_piece_moves(list,board,to,legal,stop) && stop) return true; } } return false; }
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)); } } } }
bool capture_is_good(int move, const board_t * board, bool in_pv) { #else static bool capture_is_good(int move, const board_t * board, bool in_pv) { #endif int piece, capture; int see_value; // WHM 11/22/08 ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(move_is_tactical(move,board)); // special cases if (MOVE_IS_EN_PASSANT(move)) return true; if (move_is_under_promote(move)) return false; // REMOVE ME? Keep, looks good to me. WHM; // if (MOVE_IS_PROMOTE(move)) return true; // WHM; promote-to-queen, measures a little weaker // too many garbage lines going nuts. // captures and queen promotes capture = board->square[MOVE_TO(move)]; piece = board->square[MOVE_FROM(move)]; if (capture != Empty) { // capture ASSERT(move_is_capture(move,board)); if (MOVE_IS_PROMOTE(move)) return true; // capture a piece on Rank8 and promote to queen if (VALUE_PIECE(capture) >= VALUE_PIECE(piece)) return true; } // return see_move(move,board) >= 0; WHM 11/22/08 // WHM 11/22/08 START see_value = see_move(move,board); if (see_value >= 0) return true; if (TryNodePVQueenPromotes) { if (in_pv && MOVE_IS_PROMOTE(move)) { ASSERT(!move_is_under_promote(move)); return true; // WHM: } } if (TryKingAttackSacs || TryKingBoxSacs || TryPasserSacs) { if (in_pv && see_value > -ValueBishop && capture != Empty) { ASSERT(COLOUR_IS(capture,COLOUR_OPP(board->turn))); // king attack sacs. if (TryKingAttackSacs) { if (narrow_piece_attack_king(board, piece, MOVE_TO(move), KING_POS(board,COLOUR_OPP(board->turn)))) { return true; } } // sacrifice attacks around the narrow/close king box can be examined more fully. Rybka lessons. if (TryKingBoxSacs) { if (DISTANCE(MOVE_TO(move),KING_POS(board,COLOUR_OPP(board->turn))) <= 1) { return true; } } // passer sacrifices... if (TryPasserSacs) { if (PIECE_IS_PAWN(capture) && PAWN_RANK(MOVE_TO(move),COLOUR_OPP(board->turn)) >= Rank6) { return true; } } } } // WHM 11/22/08 END return false; }
void move_do(int move, undo_t * undo) { int me, opp; int from, to; int piece, capture,pos; int piece_key; ASSERT(undo!=NULL); //ASSERT(board_is_legal(board)); // initialise undo undo->capture = false; undo->turn = Turn; undo->opening = Opening; undo->endgame = Endgame; undo->key = Key; undo->lock = Lock; // init me = Turn; opp =COLOUR_OPP(me); from = MOVE_FROM(move); to = MOVE_TO(move); piece = Square[from]; if(piece==0) printf("Error move piece %x\n ",move); pos=piece & 31; // update key stack Stack[Sp++] = Lock; // update turn Turn = opp; Key ^= g_ZobristKeyPlayer; Lock ^= g_ZobristLockPlayer; piece_key=PieceToKey32[pos]; if ((capture=Square[to]) != Empty) { undo->capture = true; undo->capture_square = to; undo->capture_piece = capture; //吃掉的子进行清除 Piece[capture & 31]=0; Piece_size[PIECE_COLOUR(capture)]--; Number[PieceTo32[capture & 31]]--; Key ^= g_ZobristKeyTable[piece_key][to]; Lock ^= g_ZobristLockTable[piece_key][to]; }else { //没有吃子,只更新位行、位列 BitRanks[to>>4] ^= g_BitRankMask[to]; BitFiles[to & 0xf] ^= g_BitFileMask[to]; } Square[from] = Empty; Square[to] = piece; Piece[pos] = to; BitRanks[from>>4] ^= g_BitRankMask[from]; BitFiles[from & 0xf] ^= g_BitFileMask[from]; if (piece_key < 5) { Opening +=g_PST[piece_key][to] - g_PST[piece_key][from]; Endgame +=g_PST[piece_key+5][to] - g_PST[piece_key+5][from]; } else { Opening -=g_PST[piece_key-5][254 - to] - g_PST[piece_key-5][254 - from]; Endgame -=g_PST[piece_key][254 - to] - g_PST[piece_key][254 - from]; } Key ^= g_ZobristKeyTable[piece_key][to] ^ g_ZobristKeyTable[piece_key][from]; Lock ^= g_ZobristLockTable[piece_key][to] ^ g_ZobristLockTable[piece_key][from]; // move the piece }
bool recog_draw(const board_t * board, int ThreadId) { material_info_t mat_info[1]; ASSERT(board!=NULL); // material if (board->piece_nb > 4) return false; material_get_info(mat_info,board,ThreadId); if ((mat_info->flags & DrawNodeFlag) == 0) return false; // recognisers if (false) { } else if (mat_info->recog == MAT_KK) { // KK return true; } else if (mat_info->recog == MAT_KBK) { // KBK (white) return true; } else if (mat_info->recog == MAT_KKB) { // KBK (black) return true; } else if (mat_info->recog == MAT_KNK) { // KNK (white) return true; } else if (mat_info->recog == MAT_KKN) { // KNK (black) return true; } else if (mat_info->recog == MAT_KPK) { // KPK (white) int me, opp; int wp, wk, bk; me = White; opp = COLOUR_OPP(me); wp = board->pawn[me][0]; wk = KING_POS(board,me); bk = KING_POS(board,opp); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wk = SQUARE_FILE_MIRROR(wk); bk = SQUARE_FILE_MIRROR(bk); } if (kpk_draw(wp,wk,bk,board->turn)) { return true; } } else if (mat_info->recog == MAT_KKP) { // KPK (black) int me, opp; int wp, wk, bk; me = Black; opp = COLOUR_OPP(me); wp = SQUARE_RANK_MIRROR(board->pawn[me][0]); wk = SQUARE_RANK_MIRROR(KING_POS(board,me)); bk = SQUARE_RANK_MIRROR(KING_POS(board,opp)); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wk = SQUARE_FILE_MIRROR(wk); bk = SQUARE_FILE_MIRROR(bk); } if (kpk_draw(wp,wk,bk,COLOUR_OPP(board->turn))) { return true; } } else if (mat_info->recog == MAT_KBKB) { // KBKB int wb, bb; wb = board->piece[White][1]; bb = board->piece[Black][1]; if (SQUARE_COLOUR(wb) == SQUARE_COLOUR(bb)) { // bishops on same colour return true; } } else if (mat_info->recog == MAT_KBPK) { // KBPK (white) int me, opp; int wp, wb, bk; me = White; opp = COLOUR_OPP(me); wp = board->pawn[me][0]; wb = board->piece[me][1]; bk = KING_POS(board,opp); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wb = SQUARE_FILE_MIRROR(wb); bk = SQUARE_FILE_MIRROR(bk); } if (kbpk_draw(wp,wb,bk)) return true; } else if (mat_info->recog == MAT_KKBP) { // KBPK (black) int me, opp; int wp, wb, bk; me = Black; opp = COLOUR_OPP(me); wp = SQUARE_RANK_MIRROR(board->pawn[me][0]); wb = SQUARE_RANK_MIRROR(board->piece[me][1]); bk = SQUARE_RANK_MIRROR(KING_POS(board,opp)); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wb = SQUARE_FILE_MIRROR(wb); bk = SQUARE_FILE_MIRROR(bk); } if (kbpk_draw(wp,wb,bk)) return true; } else { ASSERT(false); } return false; }
static void add_captures(list_t * list, const board_t * board) { int me, opp; int opp_flag; const sq_t * ptr; int from, to; int piece, capture; ASSERT(list!=NULL); ASSERT(board!=NULL); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // piece captures for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; switch (PIECE_TYPE(piece)) { case Knight64: to = from - 33; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 31; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 18; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 14; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 14; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 18; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 31; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 33; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case Bishop64: for (to = from-17; (capture=board->square[to]) == Empty; to -= 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-15; (capture=board->square[to]) == Empty; to -= 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+15; (capture=board->square[to]) == Empty; to += 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+17; (capture=board->square[to]) == Empty; to += 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case Rook64: for (to = from-16; (capture=board->square[to]) == Empty; to -= 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-1; (capture=board->square[to]) == Empty; to -= 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+1; (capture=board->square[to]) == Empty; to += 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+16; (capture=board->square[to]) == Empty; to += 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case Queen64: for (to = from-17; (capture=board->square[to]) == Empty; to -= 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-16; (capture=board->square[to]) == Empty; to -= 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-15; (capture=board->square[to]) == Empty; to -= 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-1; (capture=board->square[to]) == Empty; to -= 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+1; (capture=board->square[to]) == Empty; to += 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+15; (capture=board->square[to]) == Empty; to += 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+16; (capture=board->square[to]) == Empty; to += 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+17; (capture=board->square[to]) == Empty; to += 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case King64: to = from - 17; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 16; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 15; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 1; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 1; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 15; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 16; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 17; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; default: ASSERT(false); break; } } // pawn captures if (COLOUR_IS_WHITE(me)) { for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { to = from + 15; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); to = from + 17; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); // promote if (SQUARE_RANK(from) == Rank7) { to = from + 16; if (board->square[to] == Empty) { add_promote(list,MOVE_MAKE(from,to)); } } } } else { // black for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { to = from - 17; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); to = from - 15; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); // promote if (SQUARE_RANK(from) == Rank2) { to = from - 16; if (board->square[to] == Empty) { add_promote(list,MOVE_MAKE(from,to)); } } } } }
int see_move(int move, const board_t * board) { int att, def; int from, to; alists_t alists[1]; int value, piece_value; int piece, capture; alist_t * alist; int pos; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // init from = MOVE_FROM(move); to = MOVE_TO(move); // move the piece piece_value = 0; piece = board->square[from]; ASSERT(piece_is_ok(piece)); att = PIECE_COLOUR(piece); def = COLOUR_OPP(att); // promote if (MOVE_IS_PROMOTE(move)) { ASSERT(PIECE_IS_PAWN(piece)); piece = move_promote(move); ASSERT(piece_is_ok(piece)); ASSERT(COLOUR_IS(piece,att)); } piece_value += VALUE_PIECE(piece); // clear attacker lists ALIST_CLEAR(alists->alist[Black]); ALIST_CLEAR(alists->alist[White]); // find hidden attackers alists_hidden(alists,board,from,to); // capture the piece value = 0; capture = board->square[to]; if (capture != Empty) { ASSERT(piece_is_ok(capture)); ASSERT(COLOUR_IS(capture,def)); value += VALUE_PIECE(capture); } // promote if (MOVE_IS_PROMOTE(move)) { value += VALUE_PIECE(piece) - ValuePawn; } // en-passant if (MOVE_IS_EN_PASSANT(move)) { ASSERT(value==0); ASSERT(PIECE_IS_PAWN(board->square[SQUARE_EP_DUAL(to)])); value += ValuePawn; alists_hidden(alists,board,SQUARE_EP_DUAL(to),to); } // build defender list alist = alists->alist[def]; alist_build(alist,board,to,def); if (alist->size == 0) return value; // no defender => stop SEE // build attacker list alist = alists->alist[att]; alist_build(alist,board,to,att); // remove the moved piece (if it's an attacker) for (pos = 0; pos < alist->size && alist->square[pos] != from; pos++) ; if (pos < alist->size) alist_remove(alist,pos); // SEE search value -= see_rec(alists,board,def,to,piece_value); return value; }
static void pawn_comp_info(pawn_info_t * info, const board_t * board) { int colour; int file, rank; int me, opp; const sq_t * ptr; int sq; bool backward, candidate, doubled, isolated, open, passed; int t1, t2; int n; int bits; int opening[ColourNb], endgame[ColourNb]; int flags[ColourNb]; int file_bits[ColourNb]; int passed_bits[ColourNb]; int single_file[ColourNb]; ASSERT(info!=NULL); ASSERT(board!=NULL); // pawn_file[] #if DEBUG for (colour = 0; colour < ColourNb; colour++) { int pawn_file[FileNb]; me = colour; for (file = 0; file < FileNb; file++) { pawn_file[file] = 0; } for (ptr = &board->pawn[me][0]; (sq=*ptr) != SquareNone; ptr++) { file = SQUARE_FILE(sq); rank = PAWN_RANK(sq,me); ASSERT(file>=FileA&&file<=FileH); ASSERT(rank>=Rank2&&rank<=Rank7); pawn_file[file] |= BIT(rank); } for (file = 0; file < FileNb; file++) { if (board->pawn_file[colour][file] != pawn_file[file]) my_fatal("board->pawn_file[][]\n"); } } #endif // init for (colour = 0; colour < ColourNb; colour++) { opening[colour] = 0; endgame[colour] = 0; flags[colour] = 0; file_bits[colour] = 0; passed_bits[colour] = 0; single_file[colour] = SquareNone; } // features and scoring for (colour = 0; colour < ColourNb; colour++) { me = colour; opp = COLOUR_OPP(me); for (ptr = &board->pawn[me][0]; (sq=*ptr) != SquareNone; ptr++) { // init file = SQUARE_FILE(sq); rank = PAWN_RANK(sq,me); ASSERT(file>=FileA&&file<=FileH); ASSERT(rank>=Rank2&&rank<=Rank7); // flags file_bits[me] |= BIT(file); if (rank == Rank2) flags[me] |= BackRankFlag; // features backward = false; candidate = false; doubled = false; isolated = false; open = false; passed = false; t1 = board->pawn_file[me][file-1] | board->pawn_file[me][file+1]; t2 = board->pawn_file[me][file] | BitRev[board->pawn_file[opp][file]]; // doubled if ((board->pawn_file[me][file] & BitLT[rank]) != 0) { doubled = true; } // isolated and backward if (t1 == 0) { isolated = true; } else if ((t1 & BitLE[rank]) == 0) { backward = true; // really backward? if ((t1 & BitRank1[rank]) != 0) { ASSERT(rank+2<=Rank8); if (((t2 & BitRank1[rank]) | ((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitRank2[rank])) == 0) { backward = false; } } else if (rank == Rank2 && ((t1 & BitEQ[rank+2]) != 0)) { ASSERT(rank+3<=Rank8); if (((t2 & BitRank2[rank]) | ((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitRank3[rank])) == 0) { backward = false; } } } // open, candidate and passed if ((t2 & BitGT[rank]) == 0) { open = true; if (((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitGT[rank]) == 0) { passed = true; passed_bits[me] |= BIT(file); } else { // candidate? n = 0; n += BIT_COUNT(board->pawn_file[me][file-1]&BitLE[rank]); n += BIT_COUNT(board->pawn_file[me][file+1]&BitLE[rank]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file-1]]&BitGT[rank]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file+1]]&BitGT[rank]); if (n >= 0) { // safe? n = 0; n += BIT_COUNT(board->pawn_file[me][file-1]&BitEQ[rank-1]); n += BIT_COUNT(board->pawn_file[me][file+1]&BitEQ[rank-1]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file-1]]&BitEQ[rank+1]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file+1]]&BitEQ[rank+1]); if (n >= 0) candidate = true; } } } // outposts if (me == White) { if (SQUARE_IS_OK(sq+15)) { if (WEAK_SQUARE_BLACK(sq+15)) opening[White] += OutpostMatrix[White][SQUARE_TO_64(sq+15)]; else opening[White] += (OutpostMatrix[White][SQUARE_TO_64(sq+15)]+1)/2; } if (SQUARE_IS_OK(sq+17)) { if (WEAK_SQUARE_BLACK(sq+17)) opening[White] += OutpostMatrix[White][SQUARE_TO_64(sq+17)]; else opening[White] += (OutpostMatrix[White][SQUARE_TO_64(sq+17)]+1)/2; } } else { if (SQUARE_IS_OK(sq-15)) { if (WEAK_SQUARE_WHITE(sq-15)) opening[Black] += OutpostMatrix[Black][SQUARE_TO_64(sq-15)]; else opening[Black] += (OutpostMatrix[Black][SQUARE_TO_64(sq-15)]+1)/2; } if (SQUARE_IS_OK(sq-17)) { if (WEAK_SQUARE_WHITE(sq-17)) opening[Black] += OutpostMatrix[Black][SQUARE_TO_64(sq-17)]; else opening[Black] += (OutpostMatrix[Black][SQUARE_TO_64(sq-17)]+1)/2; } } // score if (doubled) { opening[me] -= DoubledOpening; endgame[me] -= DoubledEndgame; } if (isolated) { if (open) { opening[me] -= IsolatedOpeningOpen; endgame[me] -= IsolatedEndgame; } else { opening[me] -= IsolatedOpening; endgame[me] -= IsolatedEndgame; } } if (backward) { if (open) { opening[me] -= BackwardOpeningOpen; endgame[me] -= BackwardEndgame; } else { opening[me] -= BackwardOpening; endgame[me] -= BackwardEndgame; } } if (candidate) { opening[me] += quad(CandidateOpeningMin,CandidateOpeningMax,rank); endgame[me] += quad(CandidateEndgameMin,CandidateEndgameMax,rank); } // this was moved to the dynamic evaluation /* if (passed) { opening[me] += quad(PassedOpeningMin,PassedOpeningMax,rank); endgame[me] += quad(PassedEndgameMin,PassedEndgameMax,rank); } */ } } // store info info->opening = ((opening[White] - opening[Black]) * PawnStructureWeight) / 256; info->endgame = ((endgame[White] - endgame[Black]) * PawnStructureWeight) / 256; for (colour = 0; colour < ColourNb; colour++) { me = colour; opp = COLOUR_OPP(me); // draw flags bits = file_bits[me]; if (bits != 0 && (bits & (bits-1)) == 0) { // one set bit file = BIT_FIRST(bits); rank = BIT_FIRST(board->pawn_file[me][file]); ASSERT(rank>=Rank2); if (((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitGT[rank]) == 0) { rank = BIT_LAST(board->pawn_file[me][file]); single_file[me] = SQUARE_MAKE(file,rank); } } info->flags[colour] = flags[colour]; info->passed_bits[colour] = passed_bits[colour]; info->single_file[colour] = single_file[colour]; } }
bool move_is_pseudo(int move, board_t * board) { int me, opp; int from, to; int piece, capture; int inc, delta; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); // special cases if (MOVE_IS_SPECIAL(move)) { return move_is_pseudo_debug(move,board); } ASSERT((move&~07777)==0); // init me = board->turn; opp = COLOUR_OPP(board->turn); // from from = MOVE_FROM(move); ASSERT(SQUARE_IS_OK(from)); piece = board->square[from]; if (!COLOUR_IS(piece,me)) return false; ASSERT(piece_is_ok(piece)); // to to = MOVE_TO(move); ASSERT(SQUARE_IS_OK(to)); capture = board->square[to]; if (COLOUR_IS(capture,me)) return false; // move if (PIECE_IS_PAWN(piece)) { if (SQUARE_IS_PROMOTE(to)) return false; inc = PAWN_MOVE_INC(me); delta = to - from; ASSERT(delta_is_ok(delta)); if (capture == Empty) { // pawn push if (delta == inc) return true; if (delta == (2*inc) && PAWN_RANK(from,me) == Rank2 && board->square[from+inc] == Empty) { return true; } } else { // pawn capture if (delta == (inc-1) || delta == (inc+1)) return true; } } else { if (PIECE_ATTACK(board,piece,from,to)) return true; } return false; }
static void add_moves(list_t * list, const board_t * board) { int me, opp; int opp_flag; const sq_t * ptr; int from, to; int piece, capture; const inc_t * inc_ptr; int inc; ASSERT(list!=NULL); ASSERT(board!=NULL); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // piece moves for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) { 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; (capture=board->square[to]) == Empty; to += inc) { LIST_ADD(list,MOVE_MAKE(from,to)); } if (FLAG_IS(capture,opp_flag)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } else { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; capture = board->square[to]; if (capture == Empty || FLAG_IS(capture,opp_flag)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } // pawn moves inc = PAWN_MOVE_INC(me); for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { to = from + (inc-1); if (FLAG_IS(board->square[to],opp_flag)) { add_pawn_move(list,from,to); } to = from + (inc+1); if (FLAG_IS(board->square[to],opp_flag)) { add_pawn_move(list,from,to); } to = from + inc; if (board->square[to] == Empty) { add_pawn_move(list,from,to); if (PAWN_RANK(from,me) == Rank2) { to = from + (2*inc); if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } }
bool board_is_legal(const board_t * board) { ASSERT(board!=NULL); return !IS_IN_CHECK(board,COLOUR_OPP(board->turn)); }
void board_from_fen(board_t * board, const char fen[]) { int pos; int file, rank, sq; int c; int i, len; int piece; int pawn; ASSERT(board!=NULL); ASSERT(fen!=NULL); board_clear(board); pos = 0; c = fen[pos]; // piece placement for (rank = Rank8; rank >= Rank1; rank--) { for (file = FileA; file <= FileH;) { if (c >= '1' && c <= '8') { // empty square(s) len = c - '0'; for (i = 0; i < len; i++) { if (file > FileH) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); board->square[SQUARE_MAKE(file,rank)] = Empty; file++; } } else { // piece piece = piece_from_char(c); if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); board->square[SQUARE_MAKE(file,rank)] = piece; file++; } c = fen[++pos]; } if (rank > Rank1) { if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; } } // active colour if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; switch (c) { case 'w': board->turn = White; break; case 'b': board->turn = Black; break; default: my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); break; } c = fen[++pos]; // castling if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; board->flags = FlagsNone; if (c == '-') { // no castling rights c = fen[++pos]; } else { if (c == 'K') { if (board->square[E1] == WK && board->square[H1] == WR) board->flags |= FlagsWhiteKingCastle; c = fen[++pos]; } if (c == 'Q') { if (board->square[E1] == WK && board->square[A1] == WR) board->flags |= FlagsWhiteQueenCastle; c = fen[++pos]; } if (c == 'k') { if (board->square[E8] == BK && board->square[H8] == BR) board->flags |= FlagsBlackKingCastle; c = fen[++pos]; } if (c == 'q') { if (board->square[E8] == BK && board->square[A8] == BR) board->flags |= FlagsBlackQueenCastle; c = fen[++pos]; } } // en-passant if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; if (c == '-') { // no en-passant sq = SquareNone; c = fen[++pos]; } else { if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); file = file_from_char(c); c = fen[++pos]; if (c != (COLOUR_IS_WHITE(board->turn) ? '6' : '3')) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); rank = rank_from_char(c); c = fen[++pos]; sq = SQUARE_MAKE(file,rank); pawn = SQUARE_EP_DUAL(sq); if (board->square[sq] != Empty || board->square[pawn] != PAWN_MAKE(COLOUR_OPP(board->turn)) || (board->square[pawn-1] != PAWN_MAKE(board->turn) && board->square[pawn+1] != PAWN_MAKE(board->turn))) { sq = SquareNone; } } board->ep_square = sq; // halfmove clock board->ply_nb = 0; if (c != ' ') { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } c = fen[++pos]; if (!isdigit(c)) { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } board->ply_nb = atoi(&fen[pos]); // board update update: board_init_list(board); }
static void note_quiet_moves(list_t * list, const board_t * board, bool in_pv, int ThreadId) { int size; int i, move; int move_piece; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = quiet_move_value(move,board,ThreadId); if (TryQuietKingAttacks && in_pv) { move_piece = MOVE_PIECE(move,board); if (!(PIECE_IS_PAWN(move_piece) || PIECE_IS_KING(move_piece))) { if (narrow_piece_attack_king(board,move_piece,MOVE_TO(move),KING_POS(board,COLOUR_OPP(board->turn)))) { if (see_move(move,board) >= 0) { // if (1 == NumberThreadsInternal) print_board(board); list->value[i] += 16; } } } } } } }