void move_eval(const board_t * board, int eval) { int index; int best_value, value; int move; ASSERT(board!=NULL); ASSERT(value_is_ok(eval)); move = board->move; ASSERT(move_is_ok(move)); // exceptions if ((move & (1 << 15)) != 0) return; if (MOVE_TO(move) == board->cap_sq) return; if (MOVE_IS_CASTLE(move)) return; ASSERT(!MOVE_IS_PROMOTE(move)); ASSERT(!MOVE_IS_EN_PASSANT(move)); ASSERT(board->cap_sq==Empty); ASSERT(!board_is_check(board)); index = PIECE_TO_12(board->square[MOVE_TO(move)]) * 64 + SQUARE_TO_64(MOVE_TO(move)); ASSERT(index>=0&&index<HistorySize); if (eval > ValueQueen) { value = ValueQueen; } else if (eval < -ValueQueen) { value = -ValueQueen; } else { value = eval; } best_value = HistEval[index]; ASSERT(best_value<=HistoryEvalMax); ASSERT(best_value>=-HistoryEvalMax); if (value >= best_value) { if (value == HistoryEvalValue) value++; HistEval[index] = value; } else { if (HistEval[index] > -ValueQueen) { if (best_value == HistoryEvalValue+1) { HistEval[index] -= 2; } else { HistEval[index]--; } } } ASSERT(HistEval[index]!=HistoryEvalValue); ASSERT(HistEval[index]<=HistoryEvalMax); ASSERT(HistEval[index]>=-HistoryEvalMax); }
static bool capture_is_dangerous(int move, const board_t * board) { int piece, capture; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(move_is_tactical(move,board)); piece = MOVE_PIECE(move,board); if (PIECE_IS_PAWN(piece) && PAWN_RANK(MOVE_TO(move),board->turn) >= Rank7) { return true; } capture = move_capture(move,board); if (PIECE_IS_QUEEN(capture)) return true; if (PIECE_IS_PAWN(capture) && PAWN_RANK(MOVE_TO(move),board->turn) <= Rank2) { return true; } return false; }
/** extend_move(): Calculates the search extension to be awarded to the given move. This is based on various information such as whether the move checks, if it is a threat or not, etc. This also determines whether a move should be reduced or not. Created 072007; last modified 081808 **/ int extend_move(SEARCH_BLOCK *sb) { int extension; int lmr_moves; /* First, determine if the move should be extended (rather than reduced). */ extension = 0; if (!(sb->move & MOVE_NOEXTEND)) { /* check extension */ if (in_check()) { extension += zct->check_extension; zct->check_extensions_done++; } /* one-reply extension */ if (sb->check && sb->last_move - sb->first_move == 1) { extension += zct->one_rep_extension; zct->one_rep_extensions_done++; } /* pawn to 7th extension */ if (board.piece[MOVE_TO(sb->move)] == PAWN && RANK_OF(SQ_FLIP_COLOR(MOVE_TO(sb->move), board.side_ntm)) == RANK_7) { extension += zct->passed_pawn_extension; zct->passed_pawn_extensions_done++; } extension = MIN(PLY, extension); } /* Now try to reduce the move. If the move is marked as not reducible, or if the depth is too low, don't bother reducing it. */ if (extension > 0 || sb->depth < 2 * PLY || (sb->move & MOVE_NOREDUCE)) return extension; lmr_moves = 0; switch (sb->node_type) { case NODE_PV: lmr_moves = 5; break; case NODE_CUT: lmr_moves = 2; break; case NODE_ALL: lmr_moves = 3; break; } /* Most LMR conditions are already covered in the move scoring routines. The only "dynamic" factor is the count of moves. */ if (sb->moves > lmr_moves) { sb->move |= MOVE_ISREDUCED; extension -= PLY; } return extension; }
/** moves_are_connected(): This function is used for LMR, testing if a reduced move actually contained a threat. The function tests if the move that refuted null move was connected to the first move. This idea is from Tord Romstad. Created 101707; last modified 101807 **/ BOOL moves_are_connected(MOVE move_1, MOVE move_2) { if (move_1 == NULL_MOVE || move_2 == NULL_MOVE) return FALSE; if (MOVE_TO(move_1) == MOVE_FROM(move_2)) return TRUE; if (MOVE_FROM(move_1) == MOVE_TO(move_2)) return TRUE; if (MASK(MOVE_FROM(move_1)) & in_between_bb[MOVE_FROM(move_2)] [MOVE_TO(move_2)]) return TRUE; return FALSE; }
static int full_new_depth(int depth, int move, board_t * board, bool single_reply, bool in_pv, int height, bool extended, bool * cap_extended, int ThreadId) { int new_depth; ASSERT(depth_is_ok(depth)); ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(single_reply==true||single_reply==false); ASSERT(in_pv==true||in_pv==false); ASSERT(depth>0); new_depth = depth - 1; *cap_extended = false; if (in_pv && board->square[MOVE_TO(move)] != Empty && !PIECE_IS_PAWN(board->square[MOVE_TO(move)])){ if ((board->piece_size[White] + board->piece_size[Black]) == 3){ return new_depth+1; } else if ((board->piece_size[White] == 3 && board->piece_size[Black] == 2) || (board->piece_size[White] == 2 && board->piece_size[Black] == 3)) return new_depth+1; } if ((single_reply && ExtendSingleReply) //|| (in_pv && MOVE_TO(move) == board->cap_sq // recapture // && see_move(move,board) >= -100 /*|| ABS(VALUE_PIECE(board->square[MOVE_TO(move)])-VALUE_PIECE(board->square[MOVE_FROM(move)])) <= 250 )*/) //|| (in_pv && PIECE_IS_PAWN(MOVE_PIECE(move,board)) // && (PAWN_RANK(MOVE_TO(move),board->turn) == Rank7 || PAWN_RANK(MOVE_TO(move),board->turn) == Rank6)) //|| (in_pv && board->square[MOVE_TO(move)] != PieceNone256 && SearchCurrent[ThreadId]->act_iteration-height >= 6 && see_move(move,board) >= -100) //|| (in_pv && board->square[MOVE_TO(move)] != PieceNone256 && !extended && see_move(move,board) >= -100) //|| (in_pv && mate_threat == true) || move_is_check(move,board) && (in_pv || see_move(move,board) >= -100)) { // @tried no check extension in endgame (~ -5 elo) // @tried no bad SEE check extension in PV (~ -5 elo) return new_depth+1; } if (in_pv && PIECE_IS_PAWN(MOVE_PIECE(move,board))){ if (is_passed(board,MOVE_TO(move))) return new_depth+1; } if (in_pv && board->square[MOVE_TO(move)] != PieceNone256 && !extended && see_move(move,board) >= -100){ *cap_extended = true; return new_depth+1; } ASSERT(new_depth>=0&&new_depth<=depth); return new_depth; }
static bool capture_is_good(int move, const board_t * board) { int piece, capture; 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? // captures and queen promotes capture = board->square[MOVE_TO(move)]; if (capture != Empty) { // capture ASSERT(move_is_capture(move,board)); if (MOVE_IS_PROMOTE(move)) return true; // promote-capture piece = board->square[MOVE_FROM(move)]; if (VALUE_PIECE(capture) >= VALUE_PIECE(piece)) return true; } return see_move(move,board,0) >= 0; }
static int mvv_lva(int move, const board_t * board) { int piece, capture, promote; int value; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(move_is_tactical(move,board)); if (MOVE_IS_EN_PASSANT(move)) { // en-passant capture value = 5; // PxP } else if ((capture = board->square[MOVE_TO(move)]) != Empty) { // normal capture piece = board->square[MOVE_FROM(move)]; value = PIECE_ORDER(capture) * 6 - PIECE_ORDER(piece) + 5; ASSERT(value>=0&&value<30); } else { // promote ASSERT(MOVE_IS_PROMOTE(move)); promote = move_promote(move); value = PIECE_ORDER(promote) - 5; ASSERT(value>=-4&&value<0); } ASSERT(value>=-4&&value<+30); return value; }
void str_CSA_move( char *str, unsigned int move ) { int type_c = MOVE_TYPE( move ); int type = type_c & ~mask_piece_color; int from = MOVE_FROM( move ); int to = MOVE_TO( move ); int prom = MOVE_PROMOTE( move ); if( from == move_drop ) { snprintf( str, 7, "%d%d%d%d%s", 0, 0, 5-( to%5), ( to/5 +1 ), ch_piece_csa[ type ] ); } else if( prom ) { snprintf( str, 7, "%d%d%d%d%s", 5-( from%5 ), ( from/5 +1 ), 5-( to%5), ( to/5 +1 ), ch_piece_csa[ type + m_promote ] ); } else { snprintf( str, 7, "%d%d%d%d%s", 5-( from%5 ), ( from/5 +1 ), 5-( to%5), ( to/5 +1 ), ch_piece_csa[ type ] ); } return; }
/** heuristic(): Updates history, killer, and counter tables based on a move that failed high. Created 092906; last modified 081007 **/ void heuristic(MOVE best_move, SEARCH_BLOCK *sb) { int x; /* Update the history table. */ zct->history_table[board.side_tm][MOVE_KEY(best_move)] += sb->depth * sb->depth; zct->history_counter = MAX(zct->history_table[board.side_tm] [MOVE_KEY(best_move)], zct->history_counter); /* Check for an "overflow" of the history table, in which case we scale back all of the values. */ if (zct->history_counter > 1 << 20) { for (x = 0; x < 2 * 4096; x++) /* This is not recommended ;) */ zct->history_table[0][x] >>= 4; zct->history_counter >>= 4; } /* Update killer moves. */ if (board.color[MOVE_TO(best_move)] == EMPTY) { zct->killer_move[sb->ply][1] = MOVE_COMPARE(best_move); zct->counter_move[board.side_tm][MOVE_KEY((sb - 1)->move)][1] = MOVE_COMPARE(best_move); } }
/** move_is_futile(): This function tests whether a move should be pruned using Ernst Heinz's Futility Pruning. The idea is that, at horizon nodes, if a move cannot bring the material score (plus a margin) to alpha, there is no point in even making it, because the next ply in quiescence will have a stand-pat fail high. Created 101707; last modified 101707 **/ BOOL move_is_futile(SEARCH_BLOCK *sb, MOVE move) { return FALSE; return (sb->moves > 0 && sb->extension == 0 && sb->depth <= PLY && material_balance() + piece_value[board.piece[MOVE_TO(sb->move)]] + 100 < sb->alpha); }
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; } } } } } } }
static int full_new_depth(int depth, int move, board_t * board, bool single_reply, bool mate_threat, bool in_pv, int height) { int new_depth; ASSERT(depth_is_ok(depth)); ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(single_reply==true||single_reply==false); ASSERT(in_pv==true||in_pv==false); ASSERT(depth>0); new_depth = depth - 1; if (in_pv && board->square[MOVE_TO(move)] != Empty && !PIECE_IS_PAWN(board->square[MOVE_TO(move)])){ if ((board->piece_size[White] + board->piece_size[Black]) == 3){ return new_depth+1; } else if ((board->piece_size[White] == 3 && board->piece_size[Black] == 2) || (board->piece_size[White] == 2 && board->piece_size[Black] == 3)) return new_depth+1; } //else{ if ((single_reply && ExtendSingleReply) || (in_pv && MOVE_TO(move) == board->cap_sq // recapture /* && (see_move(move,board) > 0 || ABS(VALUE_PIECE(board->square[MOVE_TO(move)])-VALUE_PIECE(board->square[MOVE_FROM(move)])) <= 250 ) */) || (in_pv && PIECE_IS_PAWN(MOVE_PIECE(move,board)) && (PAWN_RANK(MOVE_TO(move),board->turn) == Rank7 || PAWN_RANK(MOVE_TO(move),board->turn) == Rank6) /* && see_move(move,board) >= 0 */) || (in_pv && board->square[MOVE_TO(move)] != PieceNone256 && SearchCurrent->max_extensions-height >= 6) //|| (in_pv && depth <= 1 && height <= SearchCurrent->max_extensions) //|| (in_pv && mate_threat == true) || move_is_check(move,board)) { return new_depth+1; } // else{ if (in_pv && PIECE_IS_PAWN(MOVE_PIECE(move,board))){ if (passed_pawn_move(move,board)) return new_depth+1; } // } // } ASSERT(new_depth>=0&&new_depth<=depth); return new_depth; }
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; }
/* Undoes a move on a board. */ void undo_move(board_t* board, move_t move) { #define UNDO_CASTLE(color, king_side_from, king_side_to, queen_side_from, queen_side_to) \ if (to_square > from_square) { UPDATE_CASTLE_BITBOARDS(color, color##_ROOK, king_side_from, king_side_to); } \ else { UPDATE_CASTLE_BITBOARDS(color, color##_ROOK, queen_side_from, queen_side_to); } #define UNDO_CAPTURE(other_color, square_offset) int captured_square = to_square; \ if (IS_ENPASSANT(move)) { \ captured_square += square_offset; \ } \ board->color_bitboard[other_color] |= SQUARE_MASK[captured_square]; \ board->piece_bitboard[captured_piece] |= SQUARE_MASK[captured_square]; \ board->pieces[captured_square] = captured_piece; #define UNDO_PROMOTION(pawn) board->piece_bitboard[promotion_piece] ^= SQUARE_MASK[to_square]; \ board->piece_bitboard[pawn] |= SQUARE_MASK[to_square]; board->state_index--; board->can_castle = board->state[board->state_index].can_castle; board->passed_square = board->state[board->state_index].passed_square; board->fifty_move_rule_counter = board->state[board->state_index].fifty_move_rule_counter; board->material[WHITE] = board->state[board->state_index].material[WHITE]; board->material[BLACK] = board->state[board->state_index].material[BLACK]; board->hash_key = board->state[board->state_index].hash_key; int from_square = MOVE_FROM(move), to_square = MOVE_TO(move), moving_piece = MOVING_PIECE(move), captured_piece = CAPTURED_PIECE(move), promotion_piece = PROMOTION_PIECE(move); bitboard_t from_to_bitboard = SQUARE_MASK[from_square] | SQUARE_MASK[to_square]; board->pieces[from_square] = moving_piece; board->pieces[to_square] = EMPTY; if (board->to_move == BLACK) { board->color_bitboard[WHITE] ^= from_to_bitboard; if (IS_CASTLE(move)) { UNDO_CASTLE(WHITE, H1, F1, A1, D1); } if (IS_PROMOTION(move)) { UNDO_PROMOTION(WHITE_PAWN); } if (captured_piece) { UNDO_CAPTURE(BLACK, -8); } if (moving_piece == WHITE_KING) board->king_position[WHITE] = from_square; else board->piece_bitboard[moving_piece] ^= from_to_bitboard; board->to_move = WHITE; } else { board->color_bitboard[BLACK] ^= from_to_bitboard; if (IS_CASTLE(move)) { UNDO_CASTLE(BLACK, H8, F8, A8, D8); } if (IS_PROMOTION(move)) { UNDO_PROMOTION(BLACK_PAWN); } if (captured_piece) { UNDO_CAPTURE(WHITE, 8); } if (moving_piece == BLACK_KING) board->king_position[BLACK] = from_square; else board->piece_bitboard[moving_piece] ^= from_to_bitboard; board->to_move = BLACK; } board->all_pieces_bitboard = board->color_bitboard[WHITE] | board->color_bitboard[BLACK]; }
/** heuristic_pv(): Updates killer tables when the pv changes at a pv node. Created 110606; last modified 081007 **/ void heuristic_pv(MOVE best_move, SEARCH_BLOCK *sb) { if (board.color[MOVE_TO(best_move)] == EMPTY) { zct->killer_move[sb->ply][0] = MOVE_COMPARE(best_move); zct->counter_move[board.side_tm][MOVE_KEY((sb - 1)->move)][0] = MOVE_COMPARE(best_move); } }
void move_undo(int move, const undo_t * undo) { int me; int from, to; int piece,pos; ASSERT(move_is_ok(move)); ASSERT(undo!=NULL); // init me = undo->turn; from = MOVE_FROM(move); to = MOVE_TO(move); piece = Square[to]; pos=piece & 31; ASSERT(COLOUR_IS(piece,me)); Square[from]=piece; Piece[pos]=from; BitRanks[from>>4] ^= g_BitRankMask[from]; BitFiles[from & 0xf]^= g_BitFileMask[from]; if(undo->capture)//吃子更新 { Square[to]=undo->capture_piece; Piece[undo->capture_piece & 31]=to; Piece_size[PIECE_COLOUR(undo->capture_piece)]++; Number[PieceTo32[undo->capture_piece & 31]]++; }else { Square[to]=Empty; BitRanks[to>>4] ^= g_BitRankMask[to]; BitFiles[to&0xf]^= g_BitFileMask[to]; } Turn = undo->turn; Opening = undo->opening; Endgame = undo->endgame; Key = undo->key; Lock = undo->lock; Sp--; }
void add_promote(list_t * list, int move) { ASSERT(list!=NULL); ASSERT(move_is_ok(move)); ASSERT((move&~07777)==0); // HACK ASSERT(SQUARE_IS_PROMOTE(MOVE_TO(move))); LIST_ADD(list,move|MovePromoteQueen); LIST_ADD(list,move|MovePromoteKnight); LIST_ADD(list,move|MovePromoteRook); LIST_ADD(list,move|MovePromoteBishop); }
void history_very_bad(int move, const board_t * board) { int index; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); //if (move_is_tactical(move,board)) return; // history index = PIECE_TO_12(board->square[MOVE_TO(move)]) * 64 + SQUARE_TO_64(MOVE_TO(move)); HistTot[index] += 100; if (HistTot[index] >= HistoryMax) { HistHit[index] = (HistHit[index] + 1) / 2; HistTot[index] = (HistTot[index] + 1) / 2; } ASSERT(HistHit[index]<=HistTot[index]); ASSERT(HistTot[index]<HistoryMax); }
static int history_index(int move, const board_t * board) { int index; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!MOVE_IS_TACTICAL(move,board)); index = PIECE_TO_12(board->square[MOVE_FROM(move)]) * 64 + SQUARE_TO_64(MOVE_TO(move)); ASSERT(index>=0&&index<HistorySize); return index; }
int see(Move_t move, Board_t *board) { Board_t temp_board = *global_board(); Board_t *ptr = &temp_board; int attacking_piece = MOVE_PIECE(move); int captured_piece; int gain[32]; int depth = 0; int from = MOVE_FROM(move); int to = MOVE_TO(move); if (ENEMY_PAWNS(ptr) & SQ_MASK(to)) captured_piece = PAWN; else if (ENEMY_KNIGHTS(ptr) & SQ_MASK(to)) captured_piece = KNIGHT; else if (ENEMY_BISHOPS(ptr) & SQ_MASK(to)) captured_piece = BISHOP; else if (ENEMY_ROOKS(ptr) & SQ_MASK(to)) captured_piece = ROOK; else if (ENEMY_QUEENS(ptr) & SQ_MASK(to)) captured_piece = QUEEN; else captured_piece = 0; gain[0] = Piece_Values[captured_piece]; if (MOVE_IS_EN_PASSANT(move)) gain[0] = Piece_Values[PAWN]; do { make_quick_move_on_board(ptr, from, to, captured_piece, attacking_piece); captured_piece = attacking_piece; depth++; gain[depth] = Piece_Values[captured_piece] - gain[depth-1]; if (MAX(-gain[depth-1], gain[depth]) < 0) break; attacking_piece = get_least_valuable_attacker(ptr, to, &from); } while (attacking_piece); while (--depth) gain[depth-1] = -MAX(-gain[depth-1], gain[depth]); return gain[0]; }
bool quiet_is_pseudo( int move, board_t *board ) { int to; ASSERT(move_is_ok(move)); ASSERT(board != NULL); ASSERT(!board_is_check(board)); to = MOVE_TO(move); ASSERT(SQUARE_IS_OK(to)); if( board->square[to] != Empty ) return false; // capture return move_is_pseudo(move, board ); }
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 bool move_is_dangerous(int move, const board_t * board) { int piece; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!move_is_tactical(move,board)); piece = MOVE_PIECE(move,board); if (PIECE_IS_PAWN(piece) && is_passed(board,MOVE_TO(move)) /*PAWN_RANK(MOVE_TO(move),board->turn) >= Rank7*/) { return true; } return false; }
static bool passed_pawn_move(int move, const board_t * board) { int piece, delta, to; ASSERT(board!=NULL); if (board->turn == Black){ piece = WhitePawn256; delta = -16; } else { piece = BlackPawn256; delta = 16; } for (to = MOVE_TO(move) + delta; PAWN_RANK(to,board->turn) <= Rank7; to = to + delta) { if (board->square[to] == piece || board->square[to-1] == piece || board->square[to+1] == piece) return false; } return true; }
static unsigned int history_index(int move, const board_t * board) { unsigned int index; int move_from = MOVE_FROM(move); int piece_12 = PIECE_TO_12(board->square[move_from]); ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!move_is_tactical(move,board)); // index = PIECE_TO_12(board->square[MOVE_FROM(move)]) * 64 + SQUARE_TO_64(MOVE_TO(move)); fruit 2.1 // index = PIECE_TO_12(board->square[MOVE_FROM(move)]) * (64*64) + SQUARE_TO_64(MOVE_FROM(move)) * 64 + SQUARE_TO_64(MOVE_TO(move)); Toga II 1.2.1 (corrected?). index = 64 * piece_12 + SQUARE_TO_64(MOVE_TO(move)); // fruit 2.1 and Toga II 1.4beta5c ASSERT(index >= 0 && index < HistorySize); return index; }
void move_undo(board_t * board, int move, const undo_t * undo) { int me; int from, to; int piece, pos; int rook; ASSERT(board!=NULL); ASSERT(move_is_ok(move)); ASSERT(undo!=NULL); // init me = undo->turn; from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[to]; ASSERT(COLOUR_IS(piece,me)); // castle if (MOVE_IS_CASTLE(move)) { rook = Rook64 | COLOUR_FLAG(me); // HACK if (to == G1) { square_move(board,F1,H1,rook,false); } else if (to == C1) { square_move(board,D1,A1,rook,false); } else if (to == G8) { square_move(board,F8,H8,rook,false); } else if (to == C8) { square_move(board,D8,A8,rook,false); } else { ASSERT(false); } } // move the piece backward if (MOVE_IS_PROMOTE(move)) { // promote ASSERT(piece==move_promote(move)); square_clear(board,to,piece,false); piece = PAWN_MAKE(me); pos = undo->pawn_pos; square_set(board,from,piece,pos,false); } else { // normal move square_move(board,to,from,piece,false); } // put the captured piece back if (undo->capture) { square_set(board,undo->capture_square,undo->capture_piece,undo->capture_pos,false); } // update board info board->turn = undo->turn; board->flags = undo->flags; board->ep_square = undo->ep_square; board->ply_nb = undo->ply_nb; board->cap_sq = undo->cap_sq; board->opening = undo->opening; board->endgame = undo->endgame; board->key = undo->key; board->pawn_key = undo->pawn_key; board->material_key = undo->material_key; // update key stack ASSERT(board->sp>0); board->sp--; // debug ASSERT(board_is_ok(board)); ASSERT(board_is_legal(board)); }
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)); }
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; }
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; }
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; }