From: Fabian Fichter Date: Sun, 20 Sep 2020 10:20:05 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=0ffce83fdd2c7eb447c7a7c10605eea30120d9e1;p=fairystockfish.git Merge official-stockfish/master No functional change. --- 0ffce83fdd2c7eb447c7a7c10605eea30120d9e1 diff --cc src/evaluate.cpp index 0205361,48db2b3..bb2fb73 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -79,15 -78,13 +79,13 @@@ namespace constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type - 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 = 772; - constexpr int RookSafeCheck = 1084; - constexpr int BishopSafeCheck = 645; - constexpr int KnightSafeCheck = 792; - - constexpr int OtherSafeCheck = 600; + // SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type, + // higher if multiple safe checks are possible for that piece type. + constexpr int SafeCheck[][2] = { - {}, {}, {792, 1283}, {645, 967}, {1084, 1897}, {772, 1119} ++ {}, {600, 600}, {792, 1283}, {645, 967}, {1084, 1897}, {772, 1119}, {600, 900} + }; #define S(mg, eg) make_score(mg, eg) @@@ -108,9 -105,19 +106,21 @@@ S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171), S(110,182), S(114,182), S(114,192), S(116,219) } }; + constexpr Score MaxMobility = S(150, 200); + constexpr Score DropMobility = S(10, 10); + // KingProtector[knight/bishop] contains penalty for each distance unit to own king + constexpr Score KingProtector[] = { S(8, 9), S(6, 9) }; + + // Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a + // pawn protected square on rank 4 to 6 which is also safe from a pawn attack. + constexpr Score Outpost[] = { S(56, 36), S(30, 23) }; + + // PassedRank[Rank] contains a bonus according to the rank of a passed pawn + constexpr Score PassedRank[RANK_NB] = { + S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) + }; + // RookOnFile[semiopen/open] contains bonuses for each rook when there is // no (friendly) pawn on the rook file. constexpr Score RookOnFile[] = { S(19, 7), S(48, 29) }; @@@ -165,6 -159,6 +162,13 @@@ constexpr Score WeakQueen = S( 56, 15); ++ // Variant and fairy piece bonuses ++ constexpr Score KingProximity = S(2, 4); ++ constexpr Score EndgameKingProximity = S(0, 10); ++ constexpr Score ConnectedSoldier = S(20, 20); ++ ++ constexpr int VirtualCheck = 600; ++ #undef S // Evaluation class computes and stores attacks tables and other working data @@@ -323,7 -292,7 +327,7 @@@ if (b & kingRing[Them]) { kingAttackersCount[Us]++; - kingAttackersWeight[Us] += KingAttackWeights[std::min(int(Pt), QUEEN + 1)]; - kingAttackersWeight[Us] += KingAttackWeights[Pt]; ++ kingAttackersWeight[Us] += KingAttackWeights[std::min(Pt, FAIRY_PIECES)]; kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); } @@@ -333,39 -302,9 +337,39 @@@ else if (Pt == BISHOP && (attacks_bb(s, pos.pieces(PAWN)) & kingRing[Them])) score += BishopOnKingRing; + if (Pt > QUEEN) + b = (b & pos.pieces()) | (pos.moves_from(Us, Pt, s) & ~pos.pieces() & pos.board_bb()); + int mob = popcount(b & mobilityArea[Us]); - mobility[Us] += MobilityBonus[Pt - 2][mob]; + if (Pt <= QUEEN) + mobility[Us] += MobilityBonus[Pt - 2][mob]; + else + mobility[Us] += MaxMobility * (mob - 2) / (8 + mob); + + // Piece promotion bonus + if (pos.promoted_piece_type(Pt) != NO_PIECE_TYPE) + { + if (promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank()) & (b | s)) + score += make_score(PieceValue[MG][pos.promoted_piece_type(Pt)] - PieceValue[MG][Pt], + PieceValue[EG][pos.promoted_piece_type(Pt)] - PieceValue[EG][Pt]) / 10; + } + else if (pos.piece_demotion() && pos.unpromoted_piece_on(s)) + score -= make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)], + PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 4; + else if (pos.captures_to_hand() && pos.unpromoted_piece_on(s)) + score += make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)], + PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 8; + + // Penalty if the piece is far from the kings in drop variants + if ((pos.captures_to_hand() || pos.two_boards()) && pos.count(Them) && pos.count(Us)) + score -= KingProximity * distance(s, pos.square(Us)) * distance(s, pos.square(Them)); + + else if (pos.count(Us) && (Pt == FERS || Pt == SILVER)) + score -= EndgameKingProximity * (distance(s, pos.square(Us)) - 2); + + if (Pt == SOLDIER && (pos.pieces(Us, SOLDIER) & rank_bb(s) & adjacent_files_bb(s))) - score += make_score(20, 20); ++ score += ConnectedSoldier; if (Pt == BISHOP || Pt == KNIGHT) { @@@ -381,9 -320,7 +385,8 @@@ score += MinorBehindPawn; // Penalty if the piece is far from the king + if (pos.count(Us)) - score -= (Pt == KNIGHT ? KnightKingProtector - : BishopKingProtector) * distance(pos.square(Us), s); + score -= KingProtector[Pt == BISHOP] * distance(pos.square(Us), s); if (Pt == BISHOP) { @@@ -454,41 -391,6 +457,41 @@@ return score; } + // Evaluation::hand() scores pieces of a given color and type in hand + template template + Score Evaluation::hand(PieceType pt) { + + constexpr Color Them = ~Us; + + Score score = SCORE_ZERO; + + if (pos.count_in_hand(Us, pt)) + { + Bitboard b = pos.drop_region(Us, pt) & ~pos.pieces() & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]); + if ((b & kingRing[Them]) && pt != SHOGI_PAWN) + { + kingAttackersCountInHand[Us] += pos.count_in_hand(Us, pt); - kingAttackersWeightInHand[Us] += KingAttackWeights[std::min(int(pt), QUEEN + 1)] * pos.count_in_hand(Us, pt); ++ kingAttackersWeightInHand[Us] += KingAttackWeights[std::min(pt, FAIRY_PIECES)] * pos.count_in_hand(Us, pt); + kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); + } + Bitboard theirHalf = pos.board_bb() & ~forward_ranks_bb(Them, relative_rank(Them, Rank((pos.max_rank() - 1) / 2), pos.max_rank())); + mobility[Us] += DropMobility * popcount(b & theirHalf & ~attackedBy[Them][ALL_PIECES]); + if (pos.promoted_piece_type(pt) != NO_PIECE_TYPE && pos.drop_promoted()) + score += make_score(std::max(PieceValue[MG][pos.promoted_piece_type(pt)] - PieceValue[MG][pt], VALUE_ZERO), + std::max(PieceValue[EG][pos.promoted_piece_type(pt)] - PieceValue[EG][pt], VALUE_ZERO)) / 4 * pos.count_in_hand(Us, pt); + if (pos.enclosing_drop()) + mobility[Us] += make_score(500, 500) * popcount(b); + + // Reduce score if there is a deficit of gates + if (pos.seirawan_gating() && !pos.piece_drops() && pos.count_in_hand(Us, ALL_PIECES) > popcount(pos.gates(Us))) + score -= make_score(200, 900) / pos.count_in_hand(Us, ALL_PIECES) * (pos.count_in_hand(Us, ALL_PIECES) - popcount(pos.gates(Us))); + + if (pt == SHOGI_PAWN && !pos.shogi_doubled_pawn()) + score -= make_score(50, 20) * std::max(pos.count_with_hand(Us, SHOGI_PAWN) - pos.max_file() - 1, 0); + } + + return score; + } // Evaluation::king() assigns bonuses and penalties to a king of a given color @@@ -523,86 -421,44 +526,83 @@@ b1 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); - // Enemy rooks checks - rookChecks = b1 & attackedBy[Them][ROOK] & safe; - if (rookChecks) - kingDanger += SafeCheck[ROOK][more_than_one(rookChecks)]; - else - unsafeChecks |= b1 & attackedBy[Them][ROOK]; - - // Enemy queen safe checks: count them only if the checks are from squares from - // which opponent cannot give a rook check, because rook checks are more valuable. - queenChecks = (b1 | b2) & attackedBy[Them][QUEEN] & safe - & ~(attackedBy[Us][QUEEN] | rookChecks); - if (queenChecks) - kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)]; - - // Enemy bishops checks: count them only if they are from squares from which - // opponent cannot give a queen check, because queen checks are more valuable. - bishopChecks = b2 & attackedBy[Them][BISHOP] & safe - & ~queenChecks; - if (bishopChecks) - kingDanger += SafeCheck[BISHOP][more_than_one(bishopChecks)]; + std::function get_attacks = [this](Color c, PieceType pt) { + return attackedBy[c][pt] | (pos.piece_drops() && pos.count_in_hand(c, pt) ? pos.drop_region(c, pt) & ~pos.pieces() : Bitboard(0)); + }; + for (PieceType pt : pos.piece_types()) + { + switch (pt) + { + case QUEEN: + // Enemy queen safe checks: we count them only if they are from squares from + // which we can't give a rook check, because rook checks are more valuable. + queenChecks = (b1 | b2) + & get_attacks(Them, QUEEN) + & pos.board_bb() + & safe + & ~attackedBy[Us][QUEEN] + & ~(b1 & attackedBy[Them][ROOK]); + + if (queenChecks) - kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 145/100 - : QueenSafeCheck; ++ kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)]; + break; + case ROOK: + case BISHOP: + case KNIGHT: + knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb(); + if (knightChecks & safe) - kingDanger += pt == ROOK ? RookSafeCheck * (more_than_one(knightChecks & safe) ? 175 : 100) / 100 - : pt == BISHOP ? BishopSafeCheck * (more_than_one(knightChecks & safe) ? 150 : 100) / 100 - : KnightSafeCheck * (more_than_one(knightChecks & safe) ? 162 : 100) / 100; ++ kingDanger += SafeCheck[pt][more_than_one(knightChecks & safe)]; + else + unsafeChecks |= knightChecks; + break; + case PAWN: + if (pos.piece_drops() && pos.count_in_hand(Them, pt)) + { + pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb(); + if (pawnChecks & safe) - kingDanger += OtherSafeCheck; ++ kingDanger += SafeCheck[PAWN][more_than_one(pawnChecks & safe)]; + else + unsafeChecks |= pawnChecks; + } + break; + case SHOGI_PAWN: + case KING: + break; + default: + otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb(); + if (otherChecks & safe) - kingDanger += OtherSafeCheck * (more_than_one(otherChecks & safe) ? 3 : 2) / 2; ++ kingDanger += SafeCheck[FAIRY_PIECES][more_than_one(otherChecks & safe)]; + else + unsafeChecks |= otherChecks; + } + } - else - unsafeChecks |= b2 & attackedBy[Them][BISHOP]; + // Virtual piece drops + if (pos.two_boards() && pos.piece_drops()) + { + for (PieceType pt : pos.piece_types()) + if (!pos.count_in_hand(Them, pt) && (attacks_bb(Us, pt, ksq, pos.pieces()) & safe & pos.drop_region(Them, pt) & ~pos.pieces())) + { - kingDanger += OtherSafeCheck * 500 / (500 + PieceValue[MG][pt]); ++ kingDanger += VirtualCheck * 500 / (500 + PieceValue[MG][pt]); + // Presumably a mate threat + if (!(attackedBy[Us][KING] & ~(attackedBy[Them][ALL_PIECES] | pos.pieces(Us)))) + kingDanger += 2000; + } + } - // Enemy knights checks - knightChecks = attacks_bb(ksq) & attackedBy[Them][KNIGHT]; - if (knightChecks & safe) - kingDanger += SafeCheck[KNIGHT][more_than_one(knightChecks & safe)]; - else - unsafeChecks |= knightChecks; + if (pos.check_counting()) + kingDanger += kingDanger * 7 / (3 + pos.checks_remaining(Them)); + + Square s = file_of(ksq) == FILE_A ? ksq + EAST : file_of(ksq) == pos.max_file() ? ksq + WEST : ksq; + Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(s) | adjacent_files_bb(s); // Find the squares that opponent attacks in our king flank, the squares // which they attack twice in that flank, and the squares that we defend. - b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; + b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp; b2 = b1 & attackedBy2[Them]; - b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; + b3 = attackedBy[Us][ALL_PIECES] & kingFlank & Camp; - int kingFlankAttack = popcount(b1) + popcount(b2); + int kingFlankAttack = popcount(b1) + popcount(b2); int kingFlankDefense = popcount(b3); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] diff --cc src/types.h index fb44c7b,c159856..55b92c6 --- a/src/types.h +++ b/src/types.h @@@ -368,25 -190,11 +368,26 @@@ enum Value : int MidgameLimit = 15258, EndgameLimit = 3915 }; +constexpr int PIECE_TYPE_BITS = 6; // PIECE_TYPE_NB = pow(2, PIECE_TYPE_BITS) + enum PieceType { - NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, + NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, + FERS, MET = FERS, ALFIL, FERS_ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS, + ARCHBISHOP, CHANCELLOR, AMAZON, KNIBIS, BISKNI, KNIROO, ROOKNI, + SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, DRAGON_HORSE, + CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, ATAXX_PIECE, QUIET_QUEEN, CANNON, JANGGI_CANNON, + SOLDIER, HORSE, ELEPHANT, JANGGI_ELEPHANT, BANNER, + WAZIR, COMMONER, CENTAUR, KING, ALL_PIECES = 0, - PIECE_TYPE_NB = 8 ++ FAIRY_PIECES = FERS, + + PIECE_TYPE_NB = 1 << PIECE_TYPE_BITS }; +static_assert(KING < PIECE_TYPE_NB, "KING exceeds PIECE_TYPE_NB."); +static_assert(PIECE_TYPE_BITS <= 6, "PIECE_TYPE uses more than 6 bit"); +static_assert(!(PIECE_TYPE_NB & (PIECE_TYPE_NB - 1)), "PIECE_TYPE_NB is not a power of 2"); + +static_assert(2 * SQUARE_BITS + MOVE_TYPE_BITS + 2 * PIECE_TYPE_BITS <= 32, "Move encoding uses more than 32 bits"); enum Piece { NO_PIECE,