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 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; }
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; }
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)); }