From: Fabian Fichter Date: Fri, 25 Oct 2019 09:11:10 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=a5bf77cada0f0c57b072ec27f0fe4d5c839a760f;p=fairystockfish.git Merge official-stockfish/master bench: 4231542 --- a5bf77cada0f0c57b072ec27f0fe4d5c839a760f diff --cc src/evaluate.cpp index 15eb155,a0ad09f..9261d81 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -79,7 -78,7 +79,7 @@@ namespace constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type - constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 77, 55, 44, 10, 40 }; - constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 }; ++ constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10, 40 }; // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; @@@ -400,10 -347,10 +394,10 @@@ // Bonus for rook on an open or semi-open file if (pos.is_on_semiopen_file(Us, s)) - score += RookOnFile[bool(pos.is_on_semiopen_file(Them, s))]; + score += RookOnFile[pos.is_on_semiopen_file(Them, s)]; // Penalty when trapped by the king, even more if the king cannot castle - else if (mob <= 3) + else if (mob <= 3 && pos.count(Us)) { File kf = file_of(pos.square(Us)); if ((kf < FILE_E) == (file_of(s) < kf)) @@@ -552,10 -454,10 +546,10 @@@ - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) + 148 * popcount(unsafeChecks) + 98 * popcount(pos.blockers_for_king(Us)) - - 873 * !pos.count(Them) + - 873 * !(pos.major_pieces(Them) || pos.captures_to_hand()) / (1 + pos.check_counting()) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) - + 5 * kingFlankAttacks * kingFlankAttacks / 16 + + 3 * kingFlankAttacks * kingFlankAttacks / 8 - 7; // Transform the kingDanger units into a Score, and subtract it from the evaluation diff --cc src/movegen.cpp index 92d92dc,fc99ec2..756aeed --- a/src/movegen.cpp +++ b/src/movegen.cpp @@@ -333,43 -239,10 +333,43 @@@ namespace if (Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO))) { if (!pos.castling_impeded(OO) && pos.can_castle(OO)) - *moveList++ = make(ksq, pos.castling_rook_square(OO)); + moveList = make_move_and_gating(pos, moveList, Us, ksq, pos.castling_rook_square(OO)); if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) - *moveList++ = make(ksq, pos.castling_rook_square(OOO)); + moveList = make_move_and_gating(pos, moveList, Us, ksq, pos.castling_rook_square(OOO)); + } + } + + // Castling with non-king piece + if (!pos.count(Us) && Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO))) + { - Square from = make_square(FILE_E, relative_rank(Us, pos.castling_rank(), pos.max_rank())); ++ Square from = make_square(FILE_E, pos.castling_rank(Us)); + if (!pos.castling_impeded(OO) && pos.can_castle(OO)) + moveList = make_move_and_gating(pos, moveList, Us, from, pos.castling_rook_square(OO)); + + if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) + moveList = make_move_and_gating(pos, moveList, Us, from, pos.castling_rook_square(OOO)); + } + + // Special moves + if (pos.cambodian_moves() && pos.gates(Us)) + { + if (Type != CAPTURES && Type != EVASIONS && (pos.pieces(Us, KING) & pos.gates(Us))) + { + Square from = pos.square(Us); + Bitboard b = PseudoAttacks[WHITE][KNIGHT][from] & rank_bb(rank_of(from + (Us == WHITE ? NORTH : SOUTH))) + & target & ~pos.pieces(); + while (b) + moveList = make_move_and_gating(pos, moveList, Us, from, pop_lsb(&b)); + } + + Bitboard b = pos.pieces(Us, FERS) & pos.gates(Us); + while (b) + { + Square from = pop_lsb(&b); + Square to = from + 2 * (Us == WHITE ? NORTH : SOUTH); + if (is_ok(to) && (target & to)) + moveList = make_move_and_gating(pos, moveList, Us, from, to); } } diff --cc src/movepick.cpp index 862aed9,e39f2af..7f35880 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@@ -115,11 -111,11 +115,11 @@@ void MovePicker::score() + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; else if (Type == QUIETS) - m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - + (*continuationHistory[0])[history_slot(pos.moved_piece(m))][to_sq(m)] - + (*continuationHistory[1])[history_slot(pos.moved_piece(m))][to_sq(m)] - + (*continuationHistory[3])[history_slot(pos.moved_piece(m))][to_sq(m)] - + (*continuationHistory[5])[history_slot(pos.moved_piece(m))][to_sq(m)] / 2; + m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] - + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] - + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]; ++ + 2 * (*continuationHistory[0])[history_slot(pos.moved_piece(m))][to_sq(m)] ++ + 2 * (*continuationHistory[1])[history_slot(pos.moved_piece(m))][to_sq(m)] ++ + 2 * (*continuationHistory[3])[history_slot(pos.moved_piece(m))][to_sq(m)] ++ + (*continuationHistory[5])[history_slot(pos.moved_piece(m))][to_sq(m)]; else // Type == EVASIONS { diff --cc src/movepick.h index b42b4c6,105c95d..0ae1214 --- a/src/movepick.h +++ b/src/movepick.h @@@ -79,8 -79,8 +79,8 @@@ template : public std::array, Size> {}; /// In stats table, D=0 means that the template parameter is not used -enum StatsParams { NOT_USED = 0 }; +enum StatsParams { NOT_USED = 0, PIECE_SLOTS = 8 }; - + enum StatsType { NoCaptures, Captures }; /// ButterflyHistory records how often quiet moves have been successful or /// unsuccessful during the current search, and is used for reduction and move diff --cc src/pawns.cpp index 199472b,1825b6e..8746565 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@@ -92,26 -92,27 +92,28 @@@ namespace { assert(pos.piece_on(s) == make_piece(Us, PAWN)); - Rank r = relative_rank(Us, s); + Rank r = relative_rank(Us, s, pos.max_rank()); - e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); - // Flag the pawn opposed = theirPawns & forward_file_bb(Us, s); + blocked = theirPawns & (s + Up); stoppers = theirPawns & passed_pawn_span(Us, s); - lever = theirPawns & PawnAttacks[Us][s]; - leverPush = theirPawns & PawnAttacks[Us][s + Up]; - doubled = ourPawns & (s - Up); + lever = theirPawns & PseudoAttacks[Us][PAWN][s]; + leverPush = relative_rank(Them, s, pos.max_rank()) > RANK_1 ? theirPawns & PseudoAttacks[Us][PAWN][s + Up] : Bitboard(0); + doubled = r > RANK_1 ? ourPawns & (s - Up) : Bitboard(0); neighbours = ourPawns & adjacent_files_bb(s); phalanx = neighbours & rank_bb(s); - support = neighbours & rank_bb(s - Up); + support = r > RANK_1 ? neighbours & rank_bb(s - Up) : Bitboard(0); // A pawn is backward when it is behind all pawns of the same color on - // the adjacent files and cannot safely advance. Phalanx and isolated - // pawns will be excluded when the pawn is scored. - backward = !(neighbours & forward_ranks_bb(Them, s)) - && is_ok(s + Up) - && (stoppers & (leverPush | (s + Up))); + // the adjacent files and cannot safely advance. - backward = !(neighbours & forward_ranks_bb(Them, s + Up)) ++ backward = is_ok(s + Up) ++ && !(neighbours & forward_ranks_bb(Them, s + Up)) + && (stoppers & (leverPush | blocked)); + + // Compute additional span if pawn is not backward nor blocked + if (!backward && !blocked) + e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); // A pawn is passed if one of the three following conditions is true: // (a) there is no stoppers except some levers @@@ -131,18 -132,19 +133,21 @@@ // Score this pawn if (support | phalanx) { - int v = Connected[r] * (phalanx ? 3 : 2) * (r == RANK_2 && pos.captures_to_hand() ? 3 : 1) / (opposed ? 2 : 1) - + 17 * popcount(support); - int v = Connected[r] * (2 + bool(phalanx) - bool(opposed)) ++ int v = Connected[r] * (2 + bool(phalanx) - bool(opposed)) * (r == RANK_2 && pos.captures_to_hand() ? 3 : 1) + + 21 * popcount(support); + if (r >= RANK_4 && pos.count(Us) > popcount(pos.board_bb()) / 4) + v = std::max(v, popcount(support | phalanx) * 50) / (opposed ? 2 : 1); + score += make_score(v, v * (r - 2) / 4); } else if (!neighbours) - score -= Isolated * (1 + 2 * pos.must_capture()) + WeakUnopposed * !opposed; - score -= Isolated ++ score -= Isolated * (1 + 2 * pos.must_capture()) + + WeakUnopposed * !opposed; else if (backward) - score -= Backward + WeakUnopposed * !opposed; + score -= Backward + + WeakUnopposed * !opposed; if (!support) score -= Doubled * doubled @@@ -242,21 -224,17 +247,17 @@@ Score Entry::do_king_safety(const Posit Square ksq = pos.square(Us); kingSquares[Us] = ksq; castlingRights[Us] = pos.castling_rights(Us); + auto compare = [](Score a, Score b) { return mg_value(a) < mg_value(b); }; - Score shelters[3] = { evaluate_shelter(pos, ksq), - make_score(-VALUE_INFINITE, 0), - make_score(-VALUE_INFINITE, 0) }; + Score shelter = evaluate_shelter(pos, ksq); // If we can castle use the bonus after castling if it is bigger + if (pos.can_castle(Us & KING_SIDE)) - shelters[1] = evaluate_shelter(pos, make_square(pos.castling_kingside_file(), Us == WHITE ? RANK_1 : pos.max_rank())); - shelter = std::max(shelter, evaluate_shelter(pos, relative_square(Us, SQ_G1)), compare); ++ shelter = std::max(shelter, evaluate_shelter(pos, make_square(pos.castling_kingside_file(), pos.castling_rank(Us))), compare); if (pos.can_castle(Us & QUEEN_SIDE)) - shelters[2] = evaluate_shelter(pos, make_square(pos.castling_queenside_file(), Us == WHITE ? RANK_1 : pos.max_rank())); - - for (int i : {1, 2}) - if (mg_value(shelters[i]) > mg_value(shelters[0])) - shelters[0] = shelters[i]; - shelter = std::max(shelter, evaluate_shelter(pos, relative_square(Us, SQ_C1)), compare); ++ shelter = std::max(shelter, evaluate_shelter(pos, make_square(pos.castling_queenside_file(), pos.castling_rank(Us))), compare); // In endgame we like to bring our king near our closest pawn Bitboard pawns = pos.pieces(Us, PAWN); diff --cc src/position.cpp index 88c71ea,6336a5e..36565d8 --- a/src/position.cpp +++ b/src/position.cpp @@@ -338,136 -264,57 +338,136 @@@ Position& Position::set(const Variant* // 2. Active color ss >> token; sideToMove = (token == 'w' ? WHITE : BLACK); + // Invert side to move for SFEN + if (sfen) + sideToMove = ~sideToMove; ss >> token; - // 3. Castling availability. Compatible with 3 standards: Normal FEN standard, - // Shredder-FEN that uses the letters of the columns on which the rooks began - // the game instead of KQkq and also X-FEN standard that, in case of Chess960, - // if an inner rook is associated with the castling right, the castling tag is - // replaced by the file letter of the involved rook, as for the Shredder-FEN. - while ((ss >> token) && !isspace(token)) + // 3-4. Skip parsing castling and en passant flags if not present + st->epSquare = SQ_NONE; + if (!isdigit(ss.peek()) && !sfen) { - Square rsq; - Color c = islower(token) ? BLACK : WHITE; - Piece rook = make_piece(c, ROOK); + // 3. Castling availability. Compatible with 3 standards: Normal FEN standard, + // Shredder-FEN that uses the letters of the columns on which the rooks began + // the game instead of KQkq and also X-FEN standard that, in case of Chess960, + // if an inner rook is associated with the castling right, the castling tag is + // replaced by the file letter of the involved rook, as for the Shredder-FEN. + while ((ss >> token) && !isspace(token)) + { + Square rsq; + Color c = islower(token) ? BLACK : WHITE; + Piece rook = make_piece(c, ROOK); - token = char(toupper(token)); + token = char(toupper(token)); - if (token == 'K') - for (rsq = relative_square(c, SQ_H1); piece_on(rsq) != rook; --rsq) {} + if (token == 'K') - for (rsq = make_square(FILE_MAX, relative_rank(c, castling_rank(), max_rank())); piece_on(rsq) != rook; --rsq) {} ++ for (rsq = make_square(FILE_MAX, castling_rank(c)); piece_on(rsq) != rook; --rsq) {} - else if (token == 'Q') - for (rsq = relative_square(c, SQ_A1); piece_on(rsq) != rook; ++rsq) {} + else if (token == 'Q') - for (rsq = make_square(FILE_A, relative_rank(c, castling_rank(), max_rank())); piece_on(rsq) != rook; ++rsq) {} ++ for (rsq = make_square(FILE_A, castling_rank(c)); piece_on(rsq) != rook; ++rsq) {} - else if (token >= 'A' && token <= 'H') - rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1)); + else if (token >= 'A' && token <= 'A' + max_file()) - rsq = make_square(File(token - 'A'), relative_rank(c, castling_rank(), max_rank())); ++ rsq = make_square(File(token - 'A'), castling_rank(c)); - else - continue; + else + continue; - set_castling_right(c, rsq); + // Set gates (and skip castling rights) + if (gating()) + { + st->gatesBB[c] |= rsq; + if (token == 'K' || token == 'Q') - st->gatesBB[c] |= count(c) ? square(c) : make_square(FILE_E, relative_rank(c, castling_rank(), max_rank())); ++ st->gatesBB[c] |= count(c) ? square(c) : make_square(FILE_E, castling_rank(c)); + // Do not set castling rights for gates unless there are no pieces in hand, + // which means that the file is referring to a chess960 castling right. + else if (!seirawan_gating() || count_in_hand(c, ALL_PIECES) || captures_to_hand()) + continue; + } + + if (castling_enabled()) + set_castling_right(c, rsq); + } + + // Set castling rights for 960 gating variants + if (gating() && castling_enabled()) + for (Color c : {WHITE, BLACK}) + if ((gates(c) & pieces(KING)) && !castling_rights(c) && (!seirawan_gating() || count_in_hand(c, ALL_PIECES) || captures_to_hand())) + { + Bitboard castling_rooks = gates(c) & pieces(ROOK); + while (castling_rooks) + set_castling_right(c, pop_lsb(&castling_rooks)); + } + + // counting limit + if (counting_rule() && isdigit(ss.peek())) + ss >> st->countingLimit; + + // 4. En passant square. Ignore if no pawn capture is possible + else if ( ((ss >> col) && (col >= 'a' && col <= 'a' + max_file())) + && ((ss >> row) && (row >= '1' && row <= '1' + max_rank()))) + { + st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); + + if ( !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)) + || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))) + st->epSquare = SQ_NONE; + } } - // 4. En passant square. Ignore if no pawn capture is possible - if ( ((ss >> col) && (col >= 'a' && col <= 'h')) - && ((ss >> row) && (row == '3' || row == '6'))) - { - st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); + // Check counter for nCheck + ss >> std::skipws >> token >> std::noskipws; - if ( !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)) - || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))) - st->epSquare = SQ_NONE; + if (check_counting()) + { + if (ss.peek() == '+') + { + st->checksRemaining[WHITE] = CheckCount(std::max(token - '0', 0)); + ss >> token >> token; + st->checksRemaining[BLACK] = CheckCount(std::max(token - '0', 0)); + } + else + { + // If check count is not provided, assume that the next check wins + st->checksRemaining[WHITE] = CheckCount(1); + st->checksRemaining[BLACK] = CheckCount(1); + ss.putback(token); + } } else - st->epSquare = SQ_NONE; + ss.putback(token); // 5-6. Halfmove clock and fullmove number - ss >> std::skipws >> st->rule50 >> gamePly; + if (sfen) + { + // Pieces in hand for SFEN + while ((ss >> token) && !isspace(token)) + { + if (token == '-') + continue; + else if ((idx = piece_to_char().find(token)) != string::npos) + add_to_hand(Piece(idx)); + } + // Move count is in ply for SFEN + ss >> std::skipws >> gamePly; + gamePly = std::max(gamePly - 1, 0); + } + else + { + ss >> std::skipws >> st->rule50 >> gamePly; - // Convert from fullmove starting from 1 to gamePly starting from 0, - // handle also common incorrect FEN with fullmove = 0. - gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK); + // Convert from fullmove starting from 1 to gamePly starting from 0, + // handle also common incorrect FEN with fullmove = 0. + gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK); + } - chess960 = isChess960; + // counting rules + if (st->countingLimit && st->rule50) + { + st->countingPly = st->rule50; + st->rule50 = 0; + } + + chess960 = isChess960 || v->chess960; thisThread = th; set_state(st); @@@ -482,7 -329,7 +482,7 @@@ void Position::set_castling_right(Color c, Square rfrom) { - Square kfrom = count(c) ? square(c) : make_square(FILE_E, relative_rank(c, castling_rank(), max_rank())); - Square kfrom = square(c); ++ Square kfrom = count(c) ? square(c) : make_square(FILE_E, castling_rank(c)); CastlingRights cr = c & (kfrom < rfrom ? KING_SIDE: QUEEN_SIDE); st->castlingRights |= cr; @@@ -490,9 -337,8 +490,8 @@@ castlingRightsMask[rfrom] |= cr; castlingRookSquare[cr] = rfrom; - Square kto = make_square(cr & KING_SIDE ? castling_kingside_file() : castling_queenside_file(), - relative_rank(c, castling_rank(), max_rank())); - Square kto = relative_square(c, cr & KING_SIDE ? SQ_G1 : SQ_C1); - Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1); ++ Square kto = make_square(cr & KING_SIDE ? castling_kingside_file() : castling_queenside_file(), castling_rank(c)); + Square rto = kto + (cr & KING_SIDE ? WEST : EAST); castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto) & ~(square_bb(kfrom) | rfrom); @@@ -863,13 -557,9 +862,13 @@@ bool Position::legal(Move m) const // enemy attacks, it is delayed at a later time: now! if (type_of(m) == CASTLING) { + // Non-royal pieces can not be impeded from castling + if (type_of(piece_on(from)) != KING) + return true; + // After castling, the rook and king final positions are the same in // Chess960 as they would be in standard chess. - to = make_square(to > from ? castling_kingside_file() : castling_queenside_file(), relative_rank(us, castling_rank(), max_rank())); - to = relative_square(us, to > from ? SQ_G1 : SQ_C1); ++ to = make_square(to > from ? castling_kingside_file() : castling_queenside_file(), castling_rank(us)); Direction step = to > from ? WEST : EAST; for (Square s = to; s != from; s += step) @@@ -1049,11 -700,10 +1048,10 @@@ bool Position::gives_check(Move m) cons { Square kfrom = from; Square rfrom = to; // Castling is encoded as 'King captures the rook' - Square kto = make_square(rfrom > kfrom ? castling_kingside_file() : castling_queenside_file(), - relative_rank(sideToMove, castling_rank(), max_rank())); - Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1); - Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1); ++ Square kto = make_square(rfrom > kfrom ? castling_kingside_file() : castling_queenside_file(), castling_rank(sideToMove)); + Square rto = kto + (rfrom > kfrom ? WEST : EAST); - return (PseudoAttacks[ROOK][rto] & square(~sideToMove)) + return (PseudoAttacks[sideToMove][ROOK][rto] & square(~sideToMove)) && (attacks_bb(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square(~sideToMove)); } default: @@@ -1199,32 -818,7 +1197,32 @@@ void Position::do_move(Move m, StateInf } // Move the piece. The tricky Chess960 castling is handled earlier - if (type_of(m) != CASTLING) + if (type_of(m) == DROP) + { + drop_piece(make_piece(us, in_hand_piece_type(m)), pc, to); + st->materialKey ^= Zobrist::psq[pc][pieceCount[pc]-1]; + if (type_of(pc) != PAWN) + st->nonPawnMaterial[us] += PieceValue[MG][pc]; + // Set castling rights for dropped king or rook - if (castling_dropped_piece() && relative_rank(us, to, max_rank()) == castling_rank()) ++ if (castling_dropped_piece() && rank_of(to) == castling_rank(us)) + { + if (type_of(pc) == KING && file_of(to) == FILE_E) + { + Bitboard castling_rooks = pieces(us, ROOK) - & rank_bb(relative_rank(us, castling_rank(), max_rank())) ++ & rank_bb(castling_rank(us)) + & (file_bb(FILE_A) | file_bb(max_file())); + while (castling_rooks) + set_castling_right(us, pop_lsb(&castling_rooks)); + } + else if (type_of(pc) == ROOK) + { + if ( (file_of(to) == FILE_A || file_of(to) == max_file()) - && piece_on(make_square(FILE_E, relative_rank(us, castling_rank(), max_rank()))) == make_piece(us, KING)) ++ && piece_on(make_square(FILE_E, castling_rank(us))) == make_piece(us, KING)) + set_castling_right(us, to); + } + } + } + else if (type_of(m) != CASTLING) move_piece(pc, from, to); // If the moving piece is a pawn do some special extra work @@@ -1515,16 -967,14 +1513,15 @@@ void Position::do_castling(Color us, Sq bool kingSide = to > from; rfrom = to; // Castling is encoded as "king captures friendly rook" - to = make_square(kingSide ? castling_kingside_file() : castling_queenside_file(), - relative_rank(us, castling_rank(), max_rank())); - rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1); - to = relative_square(us, kingSide ? SQ_G1 : SQ_C1); ++ to = make_square(kingSide ? castling_kingside_file() : castling_queenside_file(), castling_rank(us)); + rto = to + (kingSide ? WEST : EAST); // Remove both pieces first since squares could overlap in Chess960 - remove_piece(make_piece(us, KING), Do ? from : to); + Piece castling_piece = piece_on(Do ? from : to); + remove_piece(castling_piece, Do ? from : to); remove_piece(make_piece(us, ROOK), Do ? rfrom : rto); board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us - put_piece(make_piece(us, KING), Do ? to : from); + put_piece(castling_piece, Do ? to : from); put_piece(make_piece(us, ROOK), Do ? rto : rfrom); } diff --cc src/position.h index 5e962ba,a0a9a30..3de568e --- a/src/position.h +++ b/src/position.h @@@ -87,72 -78,9 +87,72 @@@ public Position& operator=(const Position&) = delete; // FEN string input/output - Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th); + Position& set(const Variant* v, const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th, bool sfen = false); Position& set(const std::string& code, Color c, StateInfo* si); - const std::string fen() const; + const std::string fen(bool sfen = false) const; + + // Variant rule properties + const Variant* variant() const; + Rank max_rank() const; + File max_file() const; + Bitboard board_bb() const; + const std::set& piece_types() const; + const std::string piece_to_char() const; + Rank promotion_rank() const; + const std::set >& promotion_piece_types() const; + bool sittuyin_promotion() const; + int promotion_limit(PieceType pt) const; + PieceType promoted_piece_type(PieceType pt) const; + bool piece_promotion_on_capture() const; + bool mandatory_pawn_promotion() const; + bool mandatory_piece_promotion() const; + bool piece_demotion() const; + bool endgame_eval() const; + bool double_step_enabled() const; + Rank double_step_rank() const; + bool first_rank_double_steps() const; + bool castling_enabled() const; + bool castling_dropped_piece() const; + File castling_kingside_file() const; + File castling_queenside_file() const; - Rank castling_rank() const; ++ Rank castling_rank(Color c) const; + bool checking_permitted() const; + bool must_capture() const; + bool must_drop() const; + bool piece_drops() const; + bool drop_loop() const; + bool captures_to_hand() const; + bool first_rank_drops() const; + bool drop_on_top() const; + Bitboard drop_region(Color c) const; + Bitboard drop_region(Color c, PieceType pt) const; + bool sittuyin_rook_drop() const; + bool drop_opposite_colored_bishop() const; + bool drop_promoted() const; + bool shogi_doubled_pawn() const; + bool immobility_illegal() const; + bool gating() const; + bool seirawan_gating() const; + bool cambodian_moves() const; + // winning conditions + int n_move_rule() const; + int n_fold_rule() const; + Value stalemate_value(int ply = 0) const; + Value checkmate_value(int ply = 0) const; + Value bare_king_value(int ply = 0) const; + Value extinction_value(int ply = 0) const; + bool bare_king_move() const; + const std::set& extinction_piece_types() const; + PieceType capture_the_flag_piece() const; + Bitboard capture_the_flag(Color c) const; + bool flag_move() const; + bool check_counting() const; + int connect_n() const; + CheckCount checks_remaining(Color c) const; + CountingRule counting_rule() const; + + // Variant-specific properties + int count_in_hand(Color c, PieceType pt) const; // Position representation Bitboard pieces() const; @@@ -297,351 -203,6 +297,351 @@@ namespace PSQT extern std::ostream& operator<<(std::ostream& os, const Position& pos); +inline const Variant* Position::variant() const { + assert(var != nullptr); + return var; +} + +inline Rank Position::max_rank() const { + assert(var != nullptr); + return var->maxRank; +} + +inline File Position::max_file() const { + assert(var != nullptr); + return var->maxFile; +} + +inline Bitboard Position::board_bb() const { + assert(var != nullptr); + return board_size_bb(var->maxFile, var->maxRank); +} + +inline const std::set& Position::piece_types() const { + assert(var != nullptr); + return var->pieceTypes; +} + +inline const std::string Position::piece_to_char() const { + assert(var != nullptr); + return var->pieceToChar; +} + +inline Rank Position::promotion_rank() const { + assert(var != nullptr); + return var->promotionRank; +} + +inline const std::set >& Position::promotion_piece_types() const { + assert(var != nullptr); + return var->promotionPieceTypes; +} + +inline bool Position::sittuyin_promotion() const { + assert(var != nullptr); + return var->sittuyinPromotion; +} + +inline int Position::promotion_limit(PieceType pt) const { + assert(var != nullptr); + return var->promotionLimit[pt]; +} + +inline PieceType Position::promoted_piece_type(PieceType pt) const { + assert(var != nullptr); + return var->promotedPieceType[pt]; +} + +inline bool Position::piece_promotion_on_capture() const { + assert(var != nullptr); + return var->piecePromotionOnCapture; +} + +inline bool Position::mandatory_pawn_promotion() const { + assert(var != nullptr); + return var->mandatoryPawnPromotion; +} + +inline bool Position::mandatory_piece_promotion() const { + assert(var != nullptr); + return var->mandatoryPiecePromotion; +} + +inline bool Position::piece_demotion() const { + assert(var != nullptr); + return var->pieceDemotion; +} + +inline bool Position::endgame_eval() const { + assert(var != nullptr); + return var->endgameEval; +} + +inline bool Position::double_step_enabled() const { + assert(var != nullptr); + return var->doubleStep; +} + +inline Rank Position::double_step_rank() const { + assert(var != nullptr); + return var->doubleStepRank; +} + +inline bool Position::first_rank_double_steps() const { + assert(var != nullptr); + return var->firstRankDoubleSteps; +} + +inline bool Position::castling_enabled() const { + assert(var != nullptr); + return var->castling; +} + +inline bool Position::castling_dropped_piece() const { + assert(var != nullptr); + return var->castlingDroppedPiece; +} + +inline File Position::castling_kingside_file() const { + assert(var != nullptr); + return var->castlingKingsideFile; +} + +inline File Position::castling_queenside_file() const { + assert(var != nullptr); + return var->castlingQueensideFile; +} + - inline Rank Position::castling_rank() const { ++inline Rank Position::castling_rank(Color c) const { + assert(var != nullptr); - return var->castlingRank; ++ return relative_rank(c, var->castlingRank, max_rank()); +} + +inline bool Position::checking_permitted() const { + assert(var != nullptr); + return var->checking; +} + +inline bool Position::must_capture() const { + assert(var != nullptr); + return var->mustCapture; +} + +inline bool Position::must_drop() const { + assert(var != nullptr); + return var->mustDrop; +} + +inline bool Position::piece_drops() const { + assert(var != nullptr); + return var->pieceDrops; +} + +inline bool Position::drop_loop() const { + assert(var != nullptr); + return var->dropLoop; +} + +inline bool Position::captures_to_hand() const { + assert(var != nullptr); + return var->capturesToHand; +} + +inline bool Position::first_rank_drops() const { + assert(var != nullptr); + return var->firstRankDrops; +} + +inline bool Position::drop_on_top() const { + assert(var != nullptr); + return var->dropOnTop; +} + +inline Bitboard Position::drop_region(Color c) const { + assert(var != nullptr); + return c == WHITE ? var->whiteDropRegion : var->blackDropRegion; +} + +inline Bitboard Position::drop_region(Color c, PieceType pt) const { + Bitboard b = drop_region(c) & board_bb(); + + // Connect4-style drops + if (drop_on_top()) + b &= shift(pieces()) | Rank1BB; + // Pawns on back ranks + if (pt == PAWN) + { + b &= ~promotion_zone_bb(c, promotion_rank(), max_rank()); + if (!first_rank_drops()) + b &= ~rank_bb(relative_rank(c, RANK_1, max_rank())); + } + // Doubled shogi pawns + if (pt == SHOGI_PAWN && !shogi_doubled_pawn()) + for (File f = FILE_A; f <= max_file(); ++f) + if (file_bb(f) & pieces(c, pt)) + b &= ~file_bb(f); + // Sittuyin rook drops + if (pt == ROOK && sittuyin_rook_drop()) + b &= rank_bb(relative_rank(c, RANK_1, max_rank())); + + return b; +} + +inline bool Position::sittuyin_rook_drop() const { + assert(var != nullptr); + return var->sittuyinRookDrop; +} + +inline bool Position::drop_opposite_colored_bishop() const { + assert(var != nullptr); + return var->dropOppositeColoredBishop; +} + +inline bool Position::drop_promoted() const { + assert(var != nullptr); + return var->dropPromoted; +} + +inline bool Position::shogi_doubled_pawn() const { + assert(var != nullptr); + return var->shogiDoubledPawn; +} + +inline bool Position::immobility_illegal() const { + assert(var != nullptr); + return var->immobilityIllegal; +} + +inline bool Position::gating() const { + assert(var != nullptr); + return var->gating; +} + +inline bool Position::seirawan_gating() const { + assert(var != nullptr); + return var->seirawanGating; +} + +inline bool Position::cambodian_moves() const { + assert(var != nullptr); + return var->cambodianMoves; +} + +inline int Position::n_move_rule() const { + assert(var != nullptr); + return var->nMoveRule; +} + +inline int Position::n_fold_rule() const { + assert(var != nullptr); + return var->nFoldRule; +} + +inline Value Position::stalemate_value(int ply) const { + assert(var != nullptr); + return convert_mate_value(var->stalemateValue, ply); +} + +inline Value Position::checkmate_value(int ply) const { + assert(var != nullptr); + // Check for illegal mate by shogi pawn drop + if ( var->shogiPawnDropMateIllegal + && !(checkers() & ~pieces(SHOGI_PAWN)) + && !st->capturedPiece + && st->pliesFromNull > 0 + && (st->materialKey != st->previous->materialKey)) + { + return mate_in(ply); + } + // Check for shatar mate rule + if (var->shatarMateRule) + { + // Mate by knight is illegal + if (!(checkers() & ~pieces(KNIGHT))) + return mate_in(ply); + + StateInfo* stp = st; + while (stp->checkersBB) + { + // Return mate score if there is at least one shak in series of checks + if (stp->shak) + return convert_mate_value(var->checkmateValue, ply); + + if (stp->pliesFromNull < 2) + break; + + stp = stp->previous->previous; + } + // Niol + return VALUE_DRAW; + } + // Return mate value + return convert_mate_value(var->checkmateValue, ply); +} + +inline Value Position::bare_king_value(int ply) const { + assert(var != nullptr); + return convert_mate_value(var->bareKingValue, ply); +} + +inline Value Position::extinction_value(int ply) const { + assert(var != nullptr); + return convert_mate_value(var->extinctionValue, ply); +} + +inline bool Position::bare_king_move() const { + assert(var != nullptr); + return var->bareKingMove; +} + +inline const std::set& Position::extinction_piece_types() const { + assert(var != nullptr); + return var->extinctionPieceTypes; +} + +inline PieceType Position::capture_the_flag_piece() const { + assert(var != nullptr); + return var->flagPiece; +} + +inline Bitboard Position::capture_the_flag(Color c) const { + assert(var != nullptr); + return c == WHITE ? var->whiteFlag : var->blackFlag; +} + +inline bool Position::flag_move() const { + assert(var != nullptr); + return var->flagMove; +} + +inline bool Position::check_counting() const { + assert(var != nullptr); + return var->checkCounting; +} + +inline int Position::connect_n() const { + assert(var != nullptr); + return var->connectN; +} + +inline CheckCount Position::checks_remaining(Color c) const { + return st->checksRemaining[c]; +} + +inline CountingRule Position::counting_rule() const { + assert(var != nullptr); + return var->countingRule; +} + +inline bool Position::is_immediate_game_end() const { + Value result; + return is_immediate_game_end(result); +} + +inline bool Position::is_game_end(Value& result, int ply) const { + return is_immediate_game_end(result, ply) || is_optional_game_end(result, ply); +} + inline Color Position::side_to_move() const { return sideToMove; } diff --cc src/search.cpp index 46ca3fb,c70fbf6..af82089 --- a/src/search.cpp +++ b/src/search.cpp @@@ -169,8 -167,7 +167,8 @@@ namespace for (const auto& m : MoveList(pos)) { + assert(pos.pseudo_legal(m)); - if (Root && depth <= ONE_PLY) + if (Root && depth <= 1) cnt = 1, nodes++; else { @@@ -622,15 -618,12 +621,15 @@@ namespace if (!rootNode) { + Value variantResult; + if (pos.is_game_end(variantResult, ss->ply)) + return variantResult; + // Step 2. Check for aborted search and immediate draw if ( Threads.stop.load(std::memory_order_relaxed) - || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) - : value_draw(depth, pos.this_thread()); + : value_draw(pos.this_thread()); // Step 3. Mate distance pruning. Even if we mate at the next move our score // would be at best mate_in(ss->ply+1), but if alpha is already bigger because @@@ -790,27 -785,17 +792,27 @@@ // Step 7. Razoring (~2 Elo) if ( !rootNode // The required rootNode PV handling is not available in qsearch - && depth < 2 * ONE_PLY + && depth < 2 + && !pos.must_capture() + && !pos.capture_the_flag_piece() + && !pos.check_counting() && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); improving = ss->staticEval >= (ss-2)->staticEval || (ss-2)->staticEval == VALUE_NONE; + // Skip early pruning in case of mandatory capture + if (pos.must_capture() && MoveList(pos).size()) + goto moves_loop; + // Step 8. Futility pruning: child node (~30 Elo) if ( !PvNode - && depth < 7 * ONE_PLY + && depth < 7 - && eval - futility_margin(depth, improving) >= beta + && !( pos.extinction_value() == -VALUE_MATE + && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end()) + && (pos.checking_permitted() || !pos.capture_the_flag_piece()) + && eval - futility_margin(depth, improving) * (1 + pos.check_counting()) >= beta && eval < VALUE_KNOWN_WIN) // Do not return unproven wins return eval; @@@ -820,20 -805,18 +822,20 @@@ && (ss-1)->statScore < 22661 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 - improving * 30 + && ss->staticEval >= beta - 33 * depth + 299 - improving * 30 && !excludedMove && pos.non_pawn_material(us) + && (pos.pieces(~us) ^ pos.pieces(~us, PAWN)) + && (pos.pieces() ^ pos.pieces(BREAKTHROUGH_PIECE) ^ pos.pieces(CLOBBER_PIECE)) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = ((835 - 150 * !pos.checking_permitted() + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY; - Depth R = (835 + 70 * depth) / 256 + std::min(int(eval - beta) / 185, 3); ++ Depth R = (835 - 150 * !pos.checking_permitted() + 70 * depth) / 256 + std::min(int(eval - beta) / 185, 3); ss->currentMove = MOVE_NULL; - ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; + ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; pos.do_null_move(st); @@@ -870,11 -853,10 +872,11 @@@ // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode - && depth >= 5 * ONE_PLY + && depth >= 5 + && (pos.pieces() ^ pos.pieces(CLOBBER_PIECE)) && abs(beta) < VALUE_MATE_IN_MAX_PLY) { - Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE); + Value raisedBeta = std::min(beta + 191 * (1 + pos.check_counting() + (pos.extinction_value() != VALUE_NONE)) - 46 * improving, VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); int probCutCount = 0; @@@ -885,9 -871,10 +891,10 @@@ probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[history_slot(pos.moved_piece(move))][to_sq(move)]; - - assert(depth >= 5 * ONE_PLY); + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] - [pos.moved_piece(move)] ++ [history_slot(pos.moved_piece(move))] + [to_sq(move)]; pos.do_move(move, st); @@@ -906,9 -893,9 +913,9 @@@ } // Step 11. Internal iterative deepening (~2 Elo) - if (depth >= (7 - 2 * pos.captures_to_hand()) * ONE_PLY && !ttMove) - if (depth >= 7 && !ttMove) ++ if (depth >= (7 - 2 * pos.captures_to_hand()) && !ttMove) { - search(pos, ss, alpha, beta, depth - (7 - 2 * pos.captures_to_hand()) * ONE_PLY, cutNode); - search(pos, ss, alpha, beta, depth - 7, cutNode); ++ search(pos, ss, alpha, beta, depth - (7 - 2 * pos.captures_to_hand()), cutNode); tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; @@@ -956,8 -943,8 +963,8 @@@ moves_loop: // When in check, search st ss->moveCount = ++moveCount; if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000) - sync_cout << "info depth " << depth / ONE_PLY + sync_cout << "info depth " << depth - << " currmove " << UCI::move(move, pos.is_chess960()) + << " currmove " << UCI::move(pos, move) << " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl; if (PvNode) (ss+1)->pv = nullptr; @@@ -1020,26 -1000,23 +1020,30 @@@ // Shuffle extension else if ( PvNode + && pos.n_move_rule() && pos.rule50_count() > 18 - && depth < 3 * ONE_PLY + && depth < 3 && ++thisThread->shuffleExts < thisThread->nodes.load(std::memory_order_relaxed) / 4) // To avoid too many extensions - extension = ONE_PLY; + extension = 1; // Passed pawn extension else if ( move == ss->killers[0] && pos.advanced_pawn_push(move) && pos.pawn_passed(us, to_sq(move))) - extension = ONE_PLY; + extension = 1; + + // Castling extension + if (type_of(move) == CASTLING) + extension = 1; + // Losing chess capture extension + else if ( pos.must_capture() + && pos.capture(move) + && MoveList(pos).size() == 1) - extension = ONE_PLY; ++ extension = 1; + // Calculate new depth for this move - newDepth = depth - ONE_PLY + extension; + newDepth = depth - 1 + extension; // Step 14. Pruning at shallow depth (~170 Elo) if ( !rootNode @@@ -1047,8 -1024,7 +1051,8 @@@ && bestValue > VALUE_MATED_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold - moveCountPruning = moveCount >= futility_move_count(improving, depth / ONE_PLY) - moveCountPruning = moveCount >= futility_move_count(improving, depth); ++ moveCountPruning = moveCount >= futility_move_count(improving, depth) + || (pos.must_capture() && (moveCountPruning || (pos.capture(move) && pos.legal(move)))); if ( !captureOrPromotion && !givesCheck @@@ -1082,8 -1054,7 +1085,8 @@@ continue; } else if ( !(givesCheck && extension) - && !pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) + && !pos.must_capture() - && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * (depth / ONE_PLY))) // (~20 Elo) ++ && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * depth)) // (~20 Elo) continue; } @@@ -1099,7 -1070,10 +1102,10 @@@ // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[history_slot(movedPiece)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] - [movedPiece] ++ [history_slot(movedPiece)] + [to_sq(move)]; // Step 15. Make the move pos.do_move(move, st, givesCheck); @@@ -1127,12 -1100,13 +1133,13 @@@ // Decrease reduction if opponent's move count is high (~10 Elo) if ((ss-1)->moveCount > 15) - r -= ONE_PLY; + r--; // Decrease reduction if ttMove has been singularly extended - r -= singularLMR * ONE_PLY; + if (singularLMR) + r -= 2; - if (!captureOrPromotion) + if (!captureOrPromotion && !(pos.must_capture() && MoveList(pos).size())) { // Increase reduction if ttMove is a capture (~0 Elo) if (ttCapture) @@@ -1147,12 -1121,12 +1154,12 @@@ // hence break make_move(). (~5 Elo) else if ( type_of(move) == NORMAL && !pos.see_ge(reverse_move(move))) - r -= 2 * ONE_PLY; + r -= 2; ss->statScore = thisThread->mainHistory[us][from_to(move)] - + (*contHist[0])[movedPiece][to_sq(move)] - + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] + + (*contHist[0])[history_slot(movedPiece)][to_sq(move)] + + (*contHist[1])[history_slot(movedPiece)][to_sq(move)] + + (*contHist[3])[history_slot(movedPiece)][to_sq(move)] - 4729; // Reset statScore to zero if negative and most stats shows >= 0 @@@ -1516,7 -1481,10 +1523,10 @@@ } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[history_slot(pos.moved_piece(move))][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] - [pos.moved_piece(move)] ++ [history_slot(pos.moved_piece(move))] + [to_sq(move)]; // Make and search the move pos.do_move(move, st, givesCheck); diff --cc src/thread.cpp index f4ad4c8,476f1d6..5b4decd --- a/src/thread.cpp +++ b/src/thread.cpp @@@ -201,9 -208,9 +208,9 @@@ void ThreadPool::start_thinking(Positio for (Thread* th : *this) { th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0; - th->rootDepth = th->completedDepth = DEPTH_ZERO; + th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; - th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); + th->rootPos.set(pos.variant(), pos.fen(), pos.is_chess960(), &setupStates->back(), th); } setupStates->back() = tmp; diff --cc src/tt.cpp index 50264b6,d3cd094..376e6c2 --- a/src/tt.cpp +++ b/src/tt.cpp @@@ -35,11 -35,9 +35,9 @@@ TranspositionTable TT; // Our global tr void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) { - assert(d / ONE_PLY * ONE_PLY == d); - // Preserve any existing move for the same position if (m || (k >> 48) != key16) - move16 = (uint16_t)m; + move32 = (uint32_t)m; // Overwrite less valuable entries if ( (k >> 48) != key16 diff --cc src/tt.h index 1877f1d,d087cc3..ab47874 --- a/src/tt.h +++ b/src/tt.h @@@ -37,10 -37,10 +37,10 @@@ struct TTEntry { - Move move() const { return (Move )move16; } + Move move() const { return (Move )move32; } Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } - Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)) + DEPTH_OFFSET; } + Depth depth() const { return (Depth)depth8 + DEPTH_OFFSET; } bool is_pv() const { return (bool)(genBound8 & 0x4); } Bound bound() const { return (Bound)(genBound8 & 0x3); } void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev); diff --cc src/types.h index 87d10f7,cc4008b..be57825 --- a/src/types.h +++ b/src/types.h @@@ -374,35 -203,19 +375,31 @@@ enum RiderType extern Value PieceValue[PHASE_NB][PIECE_NB]; - enum Depth : int { + typedef int Depth; - ONE_PLY = 1, + enum : int { - DEPTH_ZERO = 0 * ONE_PLY, - DEPTH_QS_CHECKS = 0 * ONE_PLY, - DEPTH_QS_NO_CHECKS = -1 * ONE_PLY, - DEPTH_QS_RECAPTURES = -5 * ONE_PLY, + DEPTH_QS_CHECKS = 0, + DEPTH_QS_NO_CHECKS = -1, + DEPTH_QS_RECAPTURES = -5, - DEPTH_NONE = -6 * ONE_PLY, + DEPTH_NONE = -6, DEPTH_OFFSET = DEPTH_NONE, - DEPTH_MAX = MAX_PLY * ONE_PLY }; - static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2"); - enum Square : int { +#ifdef LARGEBOARDS + SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_I1, SQ_J1, SQ_K1, SQ_L1, + SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, SQ_I2, SQ_J2, SQ_K2, SQ_L2, + SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3, SQ_I3, SQ_J3, SQ_K3, SQ_L3, + SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4, SQ_I4, SQ_J4, SQ_K4, SQ_L4, + SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5, SQ_I5, SQ_J5, SQ_K5, SQ_L5, + SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6, SQ_I6, SQ_J6, SQ_K6, SQ_L6, + SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7, SQ_I7, SQ_J7, SQ_K7, SQ_L7, + SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, SQ_I8, SQ_J8, SQ_K8, SQ_L8, + SQ_A9, SQ_B9, SQ_C9, SQ_D9, SQ_E9, SQ_F9, SQ_G9, SQ_H9, SQ_I9, SQ_J9, SQ_K9, SQ_L9, + SQ_A10, SQ_B10, SQ_C10, SQ_D10, SQ_E10, SQ_F10, SQ_G10, SQ_H10, SQ_I10, SQ_J10, SQ_K10, SQ_L10, +#else SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3, @@@ -577,25 -351,17 +572,21 @@@ constexpr Color operator~(Color c) } constexpr Square operator~(Square s) { +#ifdef LARGEBOARDS + return Square(s - FILE_NB * (s / FILE_NB * 2 - RANK_MAX)); // Vertical flip SQ_A1 -> SQ_A10 +#else return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8 +#endif } - constexpr File operator~(File f) { - return File(FILE_MAX - f); // Horizontal flip FILE_A -> FILE_H - } - - constexpr Rank operator~(Rank r) { - return Rank(RANK_MAX - r); // Vertical flip Rank_1 -> Rank_8 - } - constexpr Piece operator~(Piece pc) { - return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT + return Piece(pc ^ PIECE_TYPE_NB); // Swap color of piece BLACK KNIGHT -> WHITE KNIGHT } + inline File map_to_queenside(File f) { + return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA + } + constexpr CastlingRights operator&(Color c, CastlingRights cr) { return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } diff --cc src/uci.cpp index 2f6aea1,99bf1a1..21970f2 --- a/src/uci.cpp +++ b/src/uci.cpp @@@ -199,10 -191,8 +199,9 @@@ void UCI::loop(int argc, char* argv[]) Position pos; string token, cmd; StateListPtr states(new std::deque(1)); - auto uiThread = std::make_shared(0); - pos.set(StartFEN, false, &states->back(), Threads.main()); + assert(variants.find(Options["UCI_Variant"])->second != nullptr); - pos.set(variants.find(Options["UCI_Variant"])->second, variants.find(Options["UCI_Variant"])->second->startFen, false, &states->back(), uiThread.get()); ++ pos.set(variants.find(Options["UCI_Variant"])->second, variants.find(Options["UCI_Variant"])->second->startFen, false, &states->back(), Threads.main()); for (int i = 1; i < argc; ++i) cmd += std::string(argv[i]) + " "; @@@ -238,10 -225,11 +237,11 @@@ else if (token == "setoption") setoption(is); else if (token == "go") go(pos, is, states); else if (token == "position") position(pos, is, states); - else if (token == "ucinewgame") Search::clear(); + else if (token == "ucinewgame" || token == "usinewgame") Search::clear(); else if (token == "isready") sync_cout << "readyok" << sync_endl; - // Additional custom non-UCI commands, mainly for debugging + // Additional custom non-UCI commands, mainly for debugging. + // Do not use these commands during a search! else if (token == "flip") pos.flip(); else if (token == "bench") bench(pos, is, states); else if (token == "d") sync_cout << pos << sync_endl;