Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: transition to endgame

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.