diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ea802709..69f226dd 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -111,7 +111,8 @@ namespace { Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO }; // attackedBy[color][piece type] is a bitboard representing all squares - // attacked by a given color and piece type (can be also ALL_PIECES). + // attacked by a given color and piece type. Special "piece types" which are + // also calculated are QUEEN_DIAGONAL and ALL_PIECES. Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB]; // attackedBy2[color] are the squares attacked by 2 pieces of a given color, @@ -553,7 +554,6 @@ namespace { const Score RookOnPawn = S( 8, 24); const Score TrappedRook = S( 92, 0); const Score WeakQueen = S( 50, 10); - const Score OtherCheck = S( 10, 10); const Score CloseEnemies[VARIANT_NB] = { S( 7, 0), #ifdef ANTI @@ -690,10 +690,10 @@ namespace { }; // Penalties for enemy's safe checks - const int QueenCheck = 780; - const int RookCheck = 880; - const int BishopCheck = 435; - const int KnightCheck = 790; + const int QueenSafeCheck = 780; + const int RookSafeCheck = 880; + const int BishopSafeCheck = 435; + const int KnightSafeCheck = 790; #ifdef ATOMIC const int IndirectKingAttack = 883; #endif @@ -971,7 +971,7 @@ namespace { : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); const Square ksq = pos.square(Us); - Bitboard weak, b, b1, b2, safe, other; + Bitboard weak, b, b1, b2, safe, unsafeChecks; int kingDanger; // King shelter and enemy pawns storm @@ -995,32 +995,11 @@ namespace { & ~attackedBy2[Us] & (attackedBy[Us][KING] | attackedBy[Us][QUEEN] | ~attackedBy[Us][ALL_PIECES]); - // Initialize the 'kingDanger' variable, which will be transformed - // later into a king danger score. The initial value is based on the - // number and types of the enemy's attacking pieces, the number of - // attacked and weak squares around our king, the absence of queen and - // the quality of the pawn shelter (current 'score' value). - const auto KDP = KingDangerParams[pos.variant()]; - kingDanger = kingAttackersCount[Them] * kingAttackersWeight[Them] - + KDP[0] * kingAdjacentZoneAttacksCount[Them] - + KDP[1] * popcount(kingRing[Us] & weak) - + KDP[2] * bool(pos.pinned_pieces(Us)) - + KDP[3] * !pos.count(Them) - + KDP[4] * mg_value(score) / 8 - + KDP[5]; Bitboard h = 0; - + kingDanger = unsafeChecks = 0; #ifdef CRAZYHOUSE if (pos.is_house()) - { - kingDanger += KingDangerInHand[ALL_PIECES] * pos.count_in_hand(Them); - kingDanger += KingDangerInHand[PAWN] * pos.count_in_hand(Them); - kingDanger += KingDangerInHand[KNIGHT] * pos.count_in_hand(Them); - kingDanger += KingDangerInHand[BISHOP] * pos.count_in_hand(Them); - kingDanger += KingDangerInHand[ROOK] * pos.count_in_hand(Them); - kingDanger += KingDangerInHand[QUEEN] * pos.count_in_hand(Them); h = pos.count_in_hand(Them) ? weak & ~pos.pieces() : 0; - } #endif // Analyse the safe enemy's checks which are possible on next move @@ -1035,59 +1014,69 @@ namespace { b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); // Enemy queen safe checks - if ((b1 | b2) & (h | attackedBy[Them][QUEEN]) & safe & ~attackedBy[Us][QUEEN]) - kingDanger += QueenCheck; - - // Defended by our queen only - Bitboard dqo = attackedBy2[Them] - & ~(attackedBy2[Us] | pos.pieces(Them)) - & attackedBy[Us][QUEEN]; - // For minors and rooks, also consider the square safe if attacked twice, - // and only defended by our queen. - Bitboard dropSafe = (safe | (attackedBy[Them][ALL_PIECES] & dqo)) & ~pos.pieces(Us); - safe |= dqo; - - // Some other potential checks are also analysed, even from squares - // currently occupied by the opponent own pieces, as long as the square - // is not attacked by our pawns, and is not occupied by a blocked pawn. - other = ~( attackedBy[Us][PAWN] - | (pos.pieces(Them, PAWN) & shift(pos.pieces(PAWN)))); + if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN]) + kingDanger += QueenSafeCheck; + + b1 &= attackedBy[Them][ROOK]; + b2 &= attackedBy[Them][BISHOP]; #ifdef THREECHECK if (pos.is_three_check() && pos.checks_given(Them)) - other = safe = ~pos.pieces(Them); + safe = ~pos.pieces(Them); #endif - // Enemy rooks safe and other checks + // Enemy rooks checks #ifdef CRAZYHOUSE h = pos.is_house() && pos.count_in_hand(Them) ? ~pos.pieces() : 0; #endif - if (b1 & ((attackedBy[Them][ROOK] & safe) | (h & dropSafe))) - kingDanger += RookCheck; - - else if (b1 & (h | attackedBy[Them][ROOK]) & other) - score -= OtherCheck; + if (b1 & safe) + kingDanger += RookSafeCheck; + else + unsafeChecks |= b1; - // Enemy bishops safe and other checks + // Enemy bishops checks #ifdef CRAZYHOUSE h = pos.is_house() && pos.count_in_hand(Them) ? ~pos.pieces() : 0; #endif - if (b2 & ((attackedBy[Them][BISHOP] & safe) | (h & dropSafe))) - kingDanger += BishopCheck; - - else if (b2 & (h | attackedBy[Them][BISHOP]) & other) - score -= OtherCheck; + if (b2 & safe) + kingDanger += BishopSafeCheck; + else + unsafeChecks |= b2; - // Enemy knights safe and other checks + // Enemy knights checks #ifdef CRAZYHOUSE h = pos.is_house() && pos.count_in_hand(Them) ? ~pos.pieces() : 0; #endif - Bitboard k = pos.attacks_from(ksq); - b = k & attackedBy[Them][KNIGHT]; - if ((b & safe) | (k & h & dropSafe)) - kingDanger += KnightCheck; + b = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; + if (b & safe) + kingDanger += KnightSafeCheck; + else + unsafeChecks |= b; + + // Unsafe or occupied checking squares will also be considered, as long as + // the square is not defended by our pawns or occupied by a blocked pawn. + unsafeChecks &= ~( attackedBy[Us][PAWN] + | (pos.pieces(Them, PAWN) & shift(pos.pieces(PAWN)))); - else if ((b | (k & h)) & other) - score -= OtherCheck; + const auto KDP = KingDangerParams[pos.variant()]; + kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] + + KDP[0] * kingAdjacentZoneAttacksCount[Them] + + KDP[1] * popcount(kingRing[Us] & weak) + + KDP[2] * popcount(pos.pinned_pieces(Us) | unsafeChecks) + + KDP[3] * !pos.count(Them) + + KDP[4] * mg_value(score) / 8 + + KDP[5]; +#ifdef CRAZYHOUSE + if (pos.is_house()) + { + kingDanger += KingDangerInHand[ALL_PIECES] * pos.count_in_hand(Them); + kingDanger += KingDangerInHand[PAWN] * pos.count_in_hand(Them); + kingDanger += KingDangerInHand[KNIGHT] * pos.count_in_hand(Them); + kingDanger += KingDangerInHand[BISHOP] * pos.count_in_hand(Them); + kingDanger += KingDangerInHand[ROOK] * pos.count_in_hand(Them); + kingDanger += KingDangerInHand[QUEEN] * pos.count_in_hand(Them); + h = pos.count_in_hand(Them) ? weak & ~pos.pieces() : 0; + } +#endif #ifdef ATOMIC if (pos.is_atomic()) diff --git a/src/position.cpp b/src/position.cpp index a6071f13..1d6ad4f0 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -228,11 +228,11 @@ Position& Position::set(const string& fenStr, bool isChess960, Variant v, StateI else if (token == '/') { + sq += 2 * SOUTH; #ifdef CRAZYHOUSE - if (is_house() && sq < Square(SQ_A3)) + if (is_house() && sq < SQ_A1) break; #endif - sq += 2 * SOUTH; } else if ((idx = PieceToChar.find(token)) != string::npos) @@ -247,22 +247,23 @@ Position& Position::set(const string& fenStr, bool isChess960, Variant v, StateI #else else if (is_house() && token == '~') #endif - promotedPieces |= sq - 1; + promotedPieces |= SquareBB[sq - 1]; // Stop before pieces in hand else if (is_house() && token == '[') - { - // Pieces in hand - while ((ss >> token) && !isspace(token)) - { - if (token == ']') - continue; - else if ((idx = PieceToChar.find(token)) != string::npos) - add_to_hand(color_of(Piece(idx)), type_of(Piece(idx))); - } break; - } #endif } +#ifdef CRAZYHOUSE + // Pieces in hand + if (!isspace(token)) + while ((ss >> token) && !isspace(token)) + { + if (token == ']') + continue; + else if ((idx = PieceToChar.find(token)) != string::npos) + add_to_hand(color_of(Piece(idx)), type_of(Piece(idx))); + } +#endif // 2. Active color ss >> token; @@ -354,7 +355,7 @@ Position& Position::set(const string& fenStr, bool isChess960, Variant v, StateI else if (sideToMove == BLACK && !(shift(SquareBB[st->epSquare]) & pieces(WHITE, PAWN))) st->epSquare = SQ_NONE; #ifdef ATOMIC - else if (attacks_from(st->epSquare) && square(sideToMove)) + else if (is_atomic() && (attacks_from(st->epSquare) && square(sideToMove))) st->epSquare = SQ_NONE; #endif } diff --git a/src/uci.cpp b/src/uci.cpp index f33d7973..d23c1ca4 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -122,6 +122,7 @@ namespace { states = StateListPtr(new std::deque(1)); // Drop old and create a new one pos.set(fen, Options["UCI_Chess960"], variant, &states->back(), Threads.main()); + assert(pos.is_chess960() || (pos.fen() + " ").find(fen) == 0); // Parse move list (if any) while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)