Author: Dann Corbit
Date: 12:15:00 04/05/04
Go up one level in this thread
On April 03, 2004 at 10:36:37, Andrew Wagner wrote: >[snip] >>Give a bigger bonus for unstoppable passed pawns. > >How do you define "unstoppable" passed pawns? One way is taxicab distance. If there is no way the pawn can be caught, then it is unstoppable. Here is the code from Beowulf: /* Evaluate and score passed pawns as quickly as possible. * Danger parameters record how much opposition there is. */ int EvalPassedPawns(Board * B, int dangerw, int dangerb) { BITBOARD pieces = PassedMask; int sq, p, x, y, bestw = 8, bestb = 0, bestwx = -1, bestbx = -1; int diff, firstq, qsq, ksq, qx, qy, qsq2, ksq2, qx2, qy2, whiteadv = 0, tpp = 0, cppsc = 0; int nwpp = 0, nbpp = 0, s, wppmod = 0, bppmod = 0, wpieces = 0, bpieces = 0, score = 0; BITBOARD kingmask, mask, moves; BOOL capture; #ifdef DEBUG_EVAL int oldscore; #endif /* Store the pawns which are safe from the opp. king, for later use */ PPKSMask = EMPTY; /* Loop through the passed pawns */ while (pieces) { sq = FirstPiece(pieces); p = B->pieces[sq]; x = File(sq); y = Rank(sq); #ifdef DEBUG_EVAL fprintf(stdout, "Passed Pawn %c%d : ", x + 97, 8 - y); oldscore = score; #endif switch (p) { case (wpawn): score += (s = ScorePassedPawn(sq, B, &tpp)); if (!(FileUpMask[sq] & PassedMask)) whiteadv++; wppmod += s / 2; /* Test if this is totally passed, and if so store the distance * to promotion */ if (tpp) { nwpp++; if (y < bestw) { bestw = y; bestwx = x; } } /* Connected? */ if (FlankMask[sq] & B->WhitePawns) { /* Reward depending on level of danger and the separation. * * First check for pawns on adjacent files touching this one */ if (PairMask[sq] & B->WhitePawns) { switch (dangerw) { case (0): cppsc = ConnectedPP3[y]; break; case (1): cppsc = ConnectedPP2[y]; break; case (2): cppsc = ConnectedPP[y]; break; } /* The touching pawn is also passed - add an extra bonus */ if ((PairMask[sq] & B->WhitePawns) & PassedMask) { score += cppsc * 2; wppmod += (cppsc - ConnectedPP[y]) * 2; } /* The touching pawn is not passed */ else { score += cppsc; wppmod += (cppsc - ConnectedPP[y]); } } else score += DEFENDED_PAWN; #ifdef DEBUG_EVAL fprintf(stdout, "Connected (%d) ", score - oldscore - s); #endif } #ifdef DEBUG_EVAL fprintf(stdout, "[%d]\n", score - oldscore); #endif break; case (bpawn): score -= (s = ScorePassedPawn(sq, B, &tpp)); if (!(FileDownMask[sq] & PassedMask)) whiteadv--; bppmod += s / 2; /* Test if this is totally passed, and if so store the distance * to promotion */ if (tpp) { nbpp++; if (y > bestb) { bestb = y; bestbx = x; } } /* Connected? */ if (FlankMask[sq] & B->BlackPawns) { /* Reward depending on level of danger and the separation. * * First check for pawns on adjacent files touching this one */ if (PairMask[sq] & B->BlackPawns) { switch (dangerb) { case (0): cppsc = ConnectedPP3[7 - y]; break; case (1): cppsc = ConnectedPP2[7 - y]; break; case (2): cppsc = ConnectedPP[7 - y]; break; } /* The touching pawn is also passed - add an extra bonus */ if ((PairMask[sq] & B->BlackPawns) & PassedMask) { score -= (cppsc * 2); bppmod += (cppsc - ConnectedPP[7 - y]) * 2; } /* The touching pawn is not passed */ else { score -= cppsc; bppmod += (cppsc - ConnectedPP[7 - y]); } } else score -= DEFENDED_PAWN; #ifdef DEBUG_EVAL fprintf(stdout, "Connected (%d) ", oldscore - score - s); #endif } #ifdef DEBUG_EVAL fprintf(stdout, "[%d]\n", oldscore - score); #endif break; } RemoveFirst(pieces); } /* Loop through the hidden passed pawns. Consider them as if the * blocking pawn * * in front was not there. */ pieces = HiddenMask; while (pieces) { sq = FirstPiece(pieces); p = B->pieces[sq]; x = File(sq); y = Rank(sq); #ifdef DEBUG_EVAL fprintf(stdout, "Hidden Passed Pawn %c%d : ", x + 97, 8 - y); oldscore = score; #endif switch (p) { case (wpawn): B->All ^= Mask[sq - 8]; B->BlackPieces ^= Mask[sq - 8]; s = ScorePassedPawn(sq, B, &tpp); if (B->BlackRooks || B->BlackQueens) s >>= 1; if (B->BlackBishops || B->BlackKnights) s >>= 1; score += s; B->All ^= Mask[sq - 8]; B->BlackPieces ^= Mask[sq - 8]; /* Test if this is totally passed, and if so store the distance * to promotion */ if (tpp) { nwpp++; if (y < bestw) { bestw = y; bestwx = x; } } #ifdef DEBUG_EVAL fprintf(stdout, "[%d]\n", score - oldscore); #endif break; case (bpawn): B->All ^= Mask[sq + 8]; B->WhitePieces ^= Mask[sq + 8]; s = ScorePassedPawn(sq, B, &tpp); if (B->WhiteRooks || B->WhiteQueens) s >>= 1; if (B->WhiteBishops || B->WhiteKnights) s >>= 1; score -= s; B->All ^= Mask[sq + 8]; B->WhitePieces ^= Mask[sq + 8]; /* Test if this is totally passed, and if so store the distance * to promotion */ if (tpp) { nbpp++; if (y > bestb) { bestb = y; bestbx = x; } } #ifdef DEBUG_EVAL fprintf(stdout, "[%d]\n", oldscore - score); #endif break; } RemoveFirst(pieces); } #ifdef PAWN_STORM /* Bonus if one side has more passers than the other */ score += whiteadv * PP_STORM; #ifdef DEBUG_EVAL if (whiteadv) fprintf(stdout, "Unbalanced Passed Pawn Storm %d\n", whiteadv * PP_STORM); #endif #endif /* See who wins promotion races if both sides have totally passed pawns */ if (bestbx > -1 && bestwx > -1) { bestb = 7 - bestb; /* Sort out queening distances for pawns with initial 2-square moves */ if (bestb == 6) bestb = 5; if (bestw == 6) bestw = 5; /* Work out who is winning the race */ diff = bestb - bestw; /* White wins */ if ((diff > 1) || (diff == 1 && B->side == WHITE)) { nbpp = 0; score += bppmod; #ifdef DEBUG_EVAL fprintf(stdout, "White wins promotion race\n"); #endif } /* Black wins */ else if ((diff < -1) || (diff == -1 && B->side == BLACK)) { nwpp = 0; score -= wppmod; #ifdef DEBUG_EVAL fprintf(stdout, "Black wins promotion race\n"); #endif } /* It's a draw so test to see if the side to queen first gives check */ else { firstq = B->side; if (diff) firstq = Opponent(firstq); /* White queens first */ if (firstq == WHITE) { qsq = qx = bestwx; qsq2 = bestbx + a1; qx2 = bestbx; ksq = B->BlackKing; ksq2 = B->WhiteKing; qy = Rank8; qy2 = Rank1; } /* Black queens first */ else { qsq = bestbx + a1; qx = bestbx; qsq2 = qx2 = bestwx; ksq = B->WhiteKing; ksq2 = B->BlackKing; qy = Rank1; qy2 = Rank8; } /* Test for giving check */ kingmask = Mask[ksq]; moves = EMPTY; if (kingmask & QueenMask[qsq]) { mask = (B->All >> (qy * 8)) & FullRank; moves = MovesRank[qsq][mask]; mask = (B->R90 >> (qx * 8)) & FullRank; moves |= MovesFile[qsq][mask]; mask = ((B->R45 >> DiagShifts_a1h8[qsq]) & DiagonalMask_a1h8[qsq]); moves |= Movesa1h8[qsq][mask]; mask = ((B->L45 >> DiagShifts_a8h1[qsq]) & DiagonalMask_a8h1[qsq]); moves |= Movesa8h1[qsq][mask]; moves &= kingmask; if (moves != EMPTY) { if (firstq == WHITE) nbpp = 0; else nwpp = 0; #ifdef DEBUG_EVAL fprintf(stdout, "First promoting pawn gives check therefore wins race\n"); #endif } } /* If the winner didn't give check then test the losing pawn, but * only * * if the first queen can't capture it. */ if (moves == EMPTY) { capture = FALSE; // Test to see if the first queen will capture the second if (qx == qx2 || ((qsq + qsq2 == a1 + h8) && (qx == FileA || qx == FileH))) { // Same file if (qx == qx2) { if ((FileMask[qx] & B->All & InvMask[bestw] & InvMask[bestb]) == EMPTY) capture = TRUE; } // Same diagonal else { if (qsq == a1 || qsq == h8) { if ((DiagMaska1h8[qsq] & B->All) == EMPTY) capture = TRUE; } else { if ((DiagMaska8h1[qsq] & B->All) == EMPTY) capture = TRUE; } } // Yes, the first queen _can_ capture the second if (capture == TRUE) { // Make sure the second queening square isn't // defended if (firstq == WHITE) { if (!(AttacksTo(B, qsq2) & B->BlackPieces)) { nbpp = 0; score += bppmod; } } else { if (!(AttacksTo(B, qsq2) & B->WhitePieces)) { nwpp = 0; score -= wppmod; } } #ifdef DEBUG_EVAL fprintf(stdout, "First promoting pawn captures the second\n"); #endif } } // If the second queen is safe and the first queen doesn't // give check // then test to see if this one gives check if (capture == FALSE) { kingmask = Mask[ksq2]; if (kingmask & QueenMask[qsq2]) { mask = (B->All >> (qy2 * 8)) & FullRank; moves = MovesRank[qsq2][mask]; mask = (B->R90 >> (qx2 * 8)) & FullRank; moves |= MovesFile[qsq2][mask]; mask = ((B->R45 >> DiagShifts_a1h8[qsq2]) & DiagonalMask_a1h8[qsq2]); moves |= Movesa1h8[qsq2][mask]; mask = ((B->L45 >> DiagShifts_a8h1[qsq2]) & DiagonalMask_a8h1[qsq2]); moves |= Movesa8h1[qsq2][mask]; if (moves & kingmask) { if (firstq == WHITE) score -= DANGEROUS_PP; else score += DANGEROUS_PP; #ifdef DEBUG_EVAL fprintf(stdout, "Second promoting pawn gives check therefore gains advantage\n"); #endif } } } } } } /* Add on the unstoppable pawns (after checking for pawn races) */ if (nwpp != nbpp) { score += (nwpp - nbpp) * UNSTOPPABLE_PP; if (nbpp == 0) { score += bppmod; if (B->BlackQueens || B->BlackRooks || B->BlackBishops || B->BlackKnights) bpieces = 1; else score += bppmod; } if (nwpp == 0) { score -= wppmod; if (B->WhiteQueens || B->WhiteRooks || B->WhiteBishops || B->WhiteKnights) wpieces = 1; else score -= wppmod; } } #ifdef DEBUG_EVAL if (nwpp != nbpp) { fprintf(stdout, "Unstoppable PP Balance = %d\n", (nwpp - nbpp) * UNSTOPPABLE_PP); if (wpieces == 0) wppmod *= 2; if (bpieces == 0) bppmod *= 2; if (nbpp == 0) fprintf(stdout, "White TPP Penalises Black PPs = %d\n", bppmod); if (nwpp == 0) fprintf(stdout, "Black TPP Penalises White PPs = %d\n", -wppmod); } fprintf(stdout, "Passed Pawns [W%d B%d] : Total Score %d\n", Count((HiddenMask | PassedMask) & B->WhitePawns), Count((HiddenMask | PassedMask) & B->BlackPawns), score); #endif return score; } /* Check to see if a game is theoretically won */ int IsWonGame(Board * B) { if (B->WPts > 0 && B->BPts > 0) return 0; if (B->WPts == 0) { if (B->BlackQueens || B->BlackRooks) return -(THEORETICAL_WIN); if ((B->BlackBishops & BlackMask) && (B->BlackBishops & WhiteMask)) return -(THEORETICAL_WIN); } else if (B->BPts == 0) { if (B->WhiteQueens || B->WhiteRooks) return (THEORETICAL_WIN); if ((B->WhiteBishops & WhiteMask) && (B->WhiteBishops & BlackMask)) return (THEORETICAL_WIN); } return 0; } /* Check if a board position is a draw (theoretically) */ BOOL IsDrawnMaterial(Board * B) { int tpts = B->WPts + B->BPts; if (tpts > 13) return FALSE; if (!B->WhitePawns && !B->BlackPawns) { if (B->WPts < 4 && B->BPts < 4) return TRUE; /* Only at most one minor each side on the * board */ if (tpts == 6) { if (B->WPts == 6 && !B->WhiteBishops) return TRUE; /* Must be 2 knights -- drawn */ if (B->BPts == 6 && !B->BlackBishops) return TRUE; /* Must be 2 knights -- drawn */ } if (tpts == 9 && B->BlackKnights && B->WhiteKnights) return TRUE; /* Must be NB vs N or NN vs N -- drawn */ if (tpts == 13 && B->BlackRooks && B->WhiteRooks) return TRUE; /* Must be RB vs R or RN vs R -- drawn */ } return FALSE; } /* Check to see if each side has mating material */ void CheckMatingMaterial(Board * B) { int wpieces = B->WPts - Count(B->WhitePawns), bpieces = B->BPts - Count(B->BlackPawns); int wkingdist, bkingdist; /* Firstly, test for white */ if (B->WPts == 0) wmat = FALSE; else if (wpieces < 7) do { if (wpieces == 3 && !B->WhitePawns) { wmat = FALSE; break; } if (wpieces == 6 && !B->WhitePawns && !B->WhiteBishops) { wmat = FALSE; break; } /* Bad rook pawn(s) & bishop combination */ if (wpieces <= 3 && !B->WhiteKnights && (B->WhitePawns & EdgeMask)) { /* We have (at most) one bishop and several pawns */ /* See if we have non-rook pawns */ if (B->WhitePawns & CentreMask) break; /* See if we have rook pawns on both A and H files */ if ((B->WhitePawns & FileMask[FileA]) && (B->WhitePawns & FileMask[FileH])) break; /* See if either of these two rook pawns are safe from the * opp. king, therefore will queen */ if (B->WhitePawns & PPKSMask) break; /* We only have an A-file pawn plus a dark-square bishop (or * no pieces) */ if ((B->WhitePawns & FileMask[FileA]) && !(B->WhiteBishops & WhiteMask)) { wkingdist = Distance[B->WhiteKing][a8] - (B->side == WHITE ? 1 : 0); bkingdist = Distance[B->BlackKing][a8]; if (bkingdist < wkingdist) wmat = FALSE; } /* We only have an H-file pawn plus a light-square bishop (or * no pieces) */ if ((B->WhitePawns & FileMask[FileH]) && !(B->WhiteBishops & BlackMask)) { wkingdist = Distance[B->WhiteKing][h8] - (B->side == WHITE ? 1 : 0); bkingdist = Distance[B->BlackKing][h8]; if (bkingdist < wkingdist) wmat = FALSE; } } } while (0); /* Now test for black */ if (B->BPts == 0) bmat = FALSE; else if (bpieces < 7) do { if (bpieces == 3 && !B->BlackPawns) { bmat = FALSE; break; } if (bpieces == 6 && !B->BlackPawns && !B->BlackBishops) { bmat = FALSE; break; } /* Bad rook pawn(s) & bishop combination */ if (bpieces <= 3 && !B->BlackKnights && (B->BlackPawns & EdgeMask)) { /* We have (at most) one bishop and several pawns */ /* See if we have non-rook pawns */ if (B->BlackPawns & CentreMask) break; /* See if we have rook pawns on both A and H files */ if ((B->BlackPawns & FileMask[FileA]) && (B->BlackPawns & FileMask[FileH])) break; /* See if either of these two rook pawns are safe from the * opp. king, therefore will queen */ if (B->BlackPawns & PPKSMask) break; /* We only have an A-file pawn plus a light-square bishop (or * no pieces) */ if ((B->BlackPawns & FileMask[FileA]) && !(B->BlackBishops & BlackMask)) { wkingdist = Distance[B->WhiteKing][a1] - (B->side == WHITE ? 1 : 0); bkingdist = Distance[B->BlackKing][a1]; if (wkingdist < bkingdist) bmat = FALSE; } /* We only have an H-file pawn plus a dark-square bishop (or * no pieces) */ if ((B->BlackPawns & FileMask[FileH]) && !(B->BlackBishops & WhiteMask)) { wkingdist = Distance[B->WhiteKing][h1] - (B->side == WHITE ? 1 : 0); bkingdist = Distance[B->BlackKing][h1]; if (wkingdist < bkingdist) bmat = FALSE; } } } while (0); }
This page took 0 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.