private int kingSafetyKPPart(Position pos) { ulong key = pos.pawnZobristHash() ^ pos.kingZobristHash(); KingSafetyHashData ksh = kingSafetyHash[(int)key & (kingSafetyHash.Length - 1)]; if (ksh.key != key) { int score = 0; ulong wPawns = pos.pieceTypeBB[Piece.WPAWN]; ulong bPawns = pos.pieceTypeBB[Piece.BPAWN]; { int safety = 0; int halfOpenFiles = 0; if (Position.getY(pos.wKingSq) < 2) { ulong shelter = 1UL << Position.getX(pos.wKingSq); shelter |= ((shelter & BitBoard.maskBToHFiles) >> 1) | ((shelter & BitBoard.maskAToGFiles) << 1); shelter <<= 8; safety += 3 * BITS.bitCount(wPawns & shelter); safety -= 2 * BITS.bitCount(bPawns & (shelter | (shelter << 8))); shelter <<= 8; safety += 2 * BITS.bitCount(wPawns & shelter); shelter <<= 8; safety -= BITS.bitCount(bPawns & shelter); ulong wOpen = BitBoard.southFill(shelter) & (~BitBoard.southFill(wPawns)) & 0xff; if (wOpen != 0) { halfOpenFiles += 25 * BITS.bitCount(wOpen & 0xe7); halfOpenFiles += 10 * BITS.bitCount(wOpen & 0x18); } ulong bOpen = BitBoard.southFill(shelter) & (~BitBoard.southFill(bPawns)) & 0xff; if (bOpen != 0) { halfOpenFiles += 25 * BITS.bitCount(bOpen & 0xe7); halfOpenFiles += 10 * BITS.bitCount(bOpen & 0x18); } safety = Math.Min(safety, 8); } int kSafety = (safety - 9) * 15 - halfOpenFiles; score += kSafety; } { int safety = 0; int halfOpenFiles = 0; if (Position.getY(pos.bKingSq) >= 6) { ulong shelter = 1UL << (56 + Position.getX(pos.bKingSq)); shelter |= ((shelter & BitBoard.maskBToHFiles) >> 1) | ((shelter & BitBoard.maskAToGFiles) << 1); shelter >>= 8; safety += 3 * BITS.bitCount(bPawns & shelter); safety -= 2 * BITS.bitCount(wPawns & (shelter | (shelter >> 8))); shelter >>= 8; safety += 2 * BITS.bitCount(bPawns & shelter); shelter >>= 8; safety -= BITS.bitCount(wPawns & shelter); ulong wOpen = BitBoard.southFill(shelter) & (~BitBoard.southFill(wPawns)) & 0xff; if (wOpen != 0) { halfOpenFiles += 25 * BITS.bitCount(wOpen & 0xe7); halfOpenFiles += 10 * BITS.bitCount(wOpen & 0x18); } ulong bOpen = BitBoard.southFill(shelter) & (~BitBoard.southFill(bPawns)) & 0xff; if (bOpen != 0) { halfOpenFiles += 25 * BITS.bitCount(bOpen & 0xe7); halfOpenFiles += 10 * BITS.bitCount(bOpen & 0x18); } safety = Math.Min(safety, 8); } int kSafety = (safety - 9) * 15 - halfOpenFiles; score -= kSafety; } ksh.key = key; ksh.score = score; } return ksh.score; }
private int pawnBonus(Position pos) { ulong key = pos.pawnZobristHash(); PawnHashData phd = pawnHash[(int)key & (pawnHash.Length - 1)]; if (phd.key != key) computePawnHashData(pos, phd); int score = phd.score; int hiMtrl = qV + rV; score += interpolate(pos.bMtrl - pos.bMtrlPawns, 0, 2 * phd.passedBonusW, hiMtrl, phd.passedBonusW); score -= interpolate(pos.wMtrl - pos.wMtrlPawns, 0, 2 * phd.passedBonusB, hiMtrl, phd.passedBonusB); // Passed pawns are more dangerous if enemy king is far away int mtrlNoPawns; int highMtrl = qV + rV; ulong m = phd.passedPawnsW; if (m != 0) { mtrlNoPawns = pos.bMtrl - pos.bMtrlPawns; if (mtrlNoPawns < highMtrl) { int kingPos = pos.getKingSq(false); int kingX = Position.getX(kingPos); int kingY = Position.getY(kingPos); while (m != 0) { int sq = BitBoard.numberOfTrailingZeros(m); int x = Position.getX(sq); int y = Position.getY(sq); int pawnDist = Math.Min(5, 7 - y); int kingDistX = Math.Abs(kingX - x); int kingDistY = Math.Abs(kingY - 7); int kingDist = Math.Max(kingDistX, kingDistY); int kScore = kingDist * 4; if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist); score += interpolate(mtrlNoPawns, 0, kScore, highMtrl, 0); if (!pos.whiteMove) kingDist--; if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) score += 500; // King can't stop pawn m &= m-1; } } } m = phd.passedPawnsB; if (m != 0) { mtrlNoPawns = pos.wMtrl - pos.wMtrlPawns; if (mtrlNoPawns < highMtrl) { int kingPos = pos.getKingSq(true); int kingX = Position.getX(kingPos); int kingY = Position.getY(kingPos); while (m != 0) { int sq = BitBoard.numberOfTrailingZeros(m); int x = Position.getX(sq); int y = Position.getY(sq); int pawnDist = Math.Min(5, y); int kingDistX = Math.Abs(kingX - x); int kingDistY = Math.Abs(kingY - 0); int kingDist = Math.Max(kingDistX, kingDistY); int kScore = kingDist * 4; if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist); score -= interpolate(mtrlNoPawns, 0, kScore, highMtrl, 0); if (pos.whiteMove) kingDist--; if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) score -= 500; // King can't stop pawn m &= m-1; } } } return score; }
/** Compute pawn hash data for pos. */ private void computePawnHashData(Position pos, PawnHashData ph) { int score = 0; // Evaluate double pawns and pawn islands ulong wPawns = pos.pieceTypeBB[Piece.WPAWN]; ulong wPawnFiles = BitBoard.southFill(wPawns) & 0xff; int wDouble = BITS.bitCount(wPawns) - BITS.bitCount(wPawnFiles); int wIslands = BITS.bitCount(((~wPawnFiles) >> 1) & wPawnFiles); int wIsolated = BITS.bitCount(~(wPawnFiles<<1) & wPawnFiles & ~(wPawnFiles>>1)); ulong bPawns = pos.pieceTypeBB[Piece.BPAWN]; ulong bPawnFiles = BitBoard.southFill(bPawns) & 0xff; int bDouble = BITS.bitCount(bPawns) - BITS.bitCount(bPawnFiles); int bIslands = BITS.bitCount(((~bPawnFiles) >> 1) & bPawnFiles); int bIsolated = BITS.bitCount(~(bPawnFiles<<1) & bPawnFiles & ~(bPawnFiles>>1)); score -= (wDouble - bDouble) * 25; score -= (wIslands - bIslands) * 15; score -= (wIsolated - bIsolated) * 15; // Evaluate backward pawns, defined as a pawn that guards a friendly pawn, // can't be guarded by friendly pawns, can advance, but can't advance without // being captured by an enemy pawn. ulong wPawnAttacks = (((wPawns & BitBoard.maskBToHFiles) << 7) | ((wPawns & BitBoard.maskAToGFiles) << 9)); ulong bPawnAttacks = (((bPawns & BitBoard.maskBToHFiles) >> 9) | ((bPawns & BitBoard.maskAToGFiles) >> 7)); ulong wBackward = wPawns & ~((wPawns | bPawns) >> 8) & (bPawnAttacks >> 8) & ~BitBoard.northFill(wPawnAttacks); wBackward &= (((wPawns & BitBoard.maskBToHFiles) >> 9) | ((wPawns & BitBoard.maskAToGFiles) >> 7)); wBackward &= ~BitBoard.northFill(bPawnFiles); ulong bBackward = bPawns & ~((wPawns | bPawns) << 8) & (wPawnAttacks << 8) & ~BitBoard.southFill(bPawnAttacks); bBackward &= (((bPawns & BitBoard.maskBToHFiles) << 7) | ((bPawns & BitBoard.maskAToGFiles) << 9)); bBackward &= ~BitBoard.northFill(wPawnFiles); score -= (BITS.bitCount(wBackward) - BITS.bitCount(bBackward)) * 15; // Evaluate passed pawn bonus, white ulong passedPawnsW = wPawns & ~BitBoard.southFill(bPawns | bPawnAttacks | (wPawns >> 8)); int[] ppBonus = {-1,24,26,30,36,47,64,-1}; int passedBonusW = 0; if (passedPawnsW != 0) { ulong guardedPassedW = passedPawnsW & (((wPawns & BitBoard.maskBToHFiles) << 7) | ((wPawns & BitBoard.maskAToGFiles) << 9)); passedBonusW += 15 * BITS.bitCount(guardedPassedW); ulong m = passedPawnsW; while (m != 0) { int sq = /*long.numberOfTrailingZeros(m) */ BitBoard.numberOfTrailingZeros(m); int y = Position.getY(sq); passedBonusW += ppBonus[y]; m &= m-1; } } // Evaluate passed pawn bonus, black ulong passedPawnsB = bPawns & ~BitBoard.northFill(wPawns | wPawnAttacks | (bPawns << 8)); int passedBonusB = 0; if (passedPawnsB != 0) { ulong guardedPassedB = passedPawnsB & (((bPawns & BitBoard.maskBToHFiles) >> 9) | ((bPawns & BitBoard.maskAToGFiles) >> 7)); passedBonusB += 15 * BITS.bitCount(guardedPassedB); ulong m = passedPawnsB; while (m != 0) { int sq = /*long.numberOfTrailingZeros(m) */ BitBoard.numberOfTrailingZeros(m); int y = Position.getY(sq); passedBonusB += ppBonus[7-y]; m &= m-1; } } // Connected passed pawn bonus. Seems logical but doesn't help in tests // if (passedPawnsW != 0) // passedBonusW += 15 * BITS.bitCount(passedPawnsW & ((passedPawnsW & BitBoard.maskBToHFiles) >> 1)); // if (passedPawnsB != 0) // passedBonusB += 15 * BITS.bitCount(passedPawnsB & ((passedPawnsB & BitBoard.maskBToHFiles) >> 1)); ph.key = pos.pawnZobristHash(); ph.score = score; ph.passedBonusW = (short)passedBonusW; ph.passedBonusB = (short)passedBonusB; ph.passedPawnsW = passedPawnsW; ph.passedPawnsB = passedPawnsB; }