📄 eval.c
字号:
* winning side to attract the search to such positions. * **************************************************************************/{ int s, winer, sq1, sq2; winer = 1^loser; if (board.material[winer] == ValueB+ValueN && nbits(board.b[winer][bishop]) == 1 && nbits(board.b[winer][knight]) == 1) return (ScoreKBNK (side, loser)); sq1 = board.king[winer]; sq2 = board.king[loser]; s = 150 - 6 * taxicab[sq1][sq2] - EndingKing[sq2]; if (side == loser) s = -s; s += MATERIAL; return (s);}int KPK (int side)/************************************************************************** * * A KPK endgame evaluator. Side is the one on the move. * This is not a perfect evaluator, it merely identifies SOME positions * as wins or draw. Some WON positions could be seen as draws; the search * will be able to use the knowledge here to identify more positions. * **************************************************************************/{ int winer, loser, sq, sqw, sql; int s; winer = (board.b[white][pawn] ? white : black); loser = 1 ^ winer; sq = leadz (board.b[winer][pawn]); sqw = board.king[winer]; sql = board.king[loser]; s = ValueP + (ValueQ * Passed[winer][RANK(sq)] / PFACTOR) + 4 * (winer == white ? RANK(sqw) : 7-RANK(sqw));/************************************************************************** * * Pawn is outside the square of the king * **************************************************************************/ if (~SquarePawnMask[winer][sq] & board.b[loser][king]) { if (!(MoveArray[king][sql] & SquarePawnMask[winer][sq])) return (winer == side ? s : -s); if (winer == side) return (s); }/************************************************************************** * * Friendly king is on same or adjacent file to the pawn, and the pawn is * on a file other than a rook file and ... * **************************************************************************/ if (ROW(sq) != 0 && ROW(sq) != 7 && ((IsolaniMask[ROW(sq)] | FileBit[ROW(sq)]) & board.b[winer][king])) {/************************************************************************** * * a. friendly king is 2 ranks more advanced than the pawn * b. friendly king is 1 rank more advanced than the pawn * i. The friendly king is on the sixth rank. * ii. The enemy king does not have direct opposition by being 2 ranks * in front of the friendly king and on the same file. * c. friendly king is same rank as pawn * i. The enemy king is not 2-4 ranks more advanced that the pawn. * ii. The pawn is on the sixth rank and the enemy king does not have * direct opposition. * d. pawn is on the 7th rank, friendly king is on sixth rank and * i. The enemy king is not on the queening square. * ii. The enemy is on the queening square but both kings are in the same * file. * **************************************************************************/ if (winer == white) { if (RANK(sqw) == RANK(sq) + 2) return (winer == side ? s : -s); if (RANK(sqw) == RANK(sq) + 1) { if (RANK(sqw) == 5) return (winer == side ? s : -s); if (sqw < A6) { if (sqw+16 == sql && winer == side) return (0); else return (winer == side ? s : -s); } } if (RANK(sqw) == RANK(sq)) { if ((RANK(sql) - RANK(sq) < 2 || RANK(sql) - RANK(sq) > 4) && winer == side) return (s); if ((RANK(sql) - RANK(sq) < 1 || RANK(sql) - RANK(sq) > 5) && loser == side) return (-s); if (RANK(sq) == 5 && sqw+16 != sql) return (winer == side ? s : 0); } if (RANK(sq) == 6 && RANK(sqw) == 5) { if (sql != sq+8) return (winer == side ? s : 0); if (sql == sq+8 && sql == sqw+16) return (winer == side ? s : 0); } } else { if (RANK(sqw) == RANK(sq) - 2) return (winer == side ? s : -s); if (RANK(sqw) == RANK(sq) - 1) { if (RANK(sqw) == 2) return (winer == side ? s : -s); if (sqw > H3) { if (sqw-16 == sql && winer == side) return (0); else return (winer == side ? s : -s); } } if (RANK(sqw) == RANK(sq)) { if ((RANK(sq) - RANK(sql) < 2 || RANK(sq) - RANK(sql) > 4) && winer == side) return (s); if ((RANK(sq) - RANK(sql) < 1 || RANK(sq) - RANK(sql) > 5) && loser == side) return (-s); if (RANK(sq) == 5 && sqw+16 != sql) return (winer == side ? s : 0); } if (RANK(sq) == 1 && RANK(sqw) == 2) { if (sql != sq-8) return (winer == side ? s : 0); if (sql == sq-8 && sql == sqw-16) return (winer == side ? s : 0); } } } return (0);}int KBNK[64] = { 0, 10, 20, 30, 40, 50, 60, 70, 10, 20, 30, 40, 50, 60, 70, 60, 20, 30, 40, 50, 60, 70, 60, 50, 30, 40, 50, 60, 70, 60, 50, 40, 40, 50, 60, 70, 60, 50, 40, 30, 50, 60, 70, 60, 50, 40, 30, 20, 60, 70, 60, 50, 40, 30, 20, 10, 70, 60, 50, 40, 30, 20, 10, 0};int ScoreKBNK (int side, int loser)/**************************************************************************** * * My very own KBNK routine! * ****************************************************************************/{ int s, winer, sq1, sq2, sqB; winer = 1^loser; sqB = board.king[loser]; if (board.b[winer][bishop] & WHITESQUARES) sqB = RANK(sqB)*8 + 7 - ROW(sqB); sq1 = board.king[winer]; sq2 = board.king[loser]; s = 300 - 6 * taxicab[sq1][sq2]; s -= KBNK[sqB]; s -= EndingKing[sq2]; s -= taxicab[leadz(board.b[winer][knight])][sq2]; s -= taxicab[leadz(board.b[winer][bishop])][sq2]; /* King in the central 4x4 region is good! */ if (board.b[winer][king] & ULL(0x00003C3C3C3C0000)) s += 20; if (side == loser) s = -s; s += MATERIAL; return (s); }static const BitBoard nn[2] = { ULL(0x4200000000000000), ULL(0x0000000000000042) };static const BitBoard bb[2] = { ULL(0x2400000000000000), ULL(0x0000000000000024) };int ScoreDev (short side)/*************************************************************************** * * Calculate the development score for side (for opening only). * Penalize the following. * . Uncastled and cannot castled * . Undeveloped knights and bishops * . Early queen move. * ***************************************************************************/{ int s; int sq; BitBoard c; /* Calculate whether we are developed */ c = (board.b[side][knight] & nn[side]) | (board.b[side][bishop] & bb[side]); s = nbits(c) * -8; /* If we are castled or beyond the 20th move, no more ScoreDev */ if (board.castled[side] || GameCnt >= 38) return (s); s += NOTCASTLED; /* If the king is moved, nail it, otherwise check rooks */ if (Mvboard[board.king[side]] > 0) s += KINGMOVED; /* Discourage rook moves */ c = board.b[side][rook]; while (c) { sq = leadz(c); CLEARBIT(c, sq); if (Mvboard[sq] > 0) s += ROOKMOVED; } /* Penalize a queen that moves at all */ if (board.b[side][queen]) { sq = leadz (board.b[side][queen]); if (Mvboard[sq] > 0) s += EARLYQUEENMOVE; /* s += Mvboard[sq] * EARLYQUEENMOVE; */ } /* Discourage repeat minor piece moves */ c = board.b[side][knight] | board.b[side][bishop]; while (c) { sq = leadz(c); CLEARBIT(c, sq); if (Mvboard[sq] > 1) s += EARLYMINORREPEAT; /* s += Mvboard[sq] * EARLYMINORREPEAT; */ } /* Discourage any wing pawn moves *//* c = board.b[side][pawn] & (FileBit[0]|FileBit[1]|FileBit[6]|FileBit[7]); */ c = board.b[side][pawn] & ULL(0xc3c3c3c3c3c3c3c3); while (c) { sq = leadz(c); CLEARBIT(c, sq); if (Mvboard[sq] > 0) s += EARLYWINGPAWNMOVE; } /* Discourage any repeat center pawn moves *//* c = board.b[side][pawn] & (FileBit[2]|FileBit[3]|FileBit[4]|FileBit[5]); */ c = board.b[side][pawn] & ULL(0x3c3c3c3c3c3c3c3c); while (c) { sq = leadz(c); CLEARBIT(c, sq); if (Mvboard[sq] > 1) s += EARLYCENTERPREPEAT; } return (s);}/* Array of pointer to functions */static int (*ScorePiece[7]) (short) ={ NULL, ScoreP, ScoreN, ScoreB, ScoreR, ScoreQ, ScoreK };int Evaluate (int alpha, int beta)/**************************************************************************** * * First check to see if this position can be specially dealt with. * E.g. if our bounds indicate that we are looking for a mate score, * then just return the material score. Nothing else is important. * If its a KPK endgame, call our KPK routine. * If one side has a lone king & the winning side has no pawns then call * the LoneKing() mating driver routine. Note that there is enough * mating material as we have already check for insufficient mating material * in the call to EvaluateDraw() in search()/quiesce(). * ****************************************************************************/{ int side, xside; int piece, s, s1, score; int npiece[2]; BitBoard *b; side = board.side; xside = 1 ^ side; /* If we are looking for a MATE, just return the material */ if (alpha > MATE-255 || beta < -MATE+255) return (MATERIAL); /* A KPK endgame. */ if (board.material[white]+board.material[black] == ValueP) return (KPK (side)); /* One side has a lone king and other side has no pawns */ if (board.material[xside] == 0 && board.b[side][pawn] == NULLBITBOARD) return LoneKing (side, xside); if (board.material[side] == 0 && board.b[xside][pawn] == NULLBITBOARD) return LoneKing (side, side);/**************************************************************************** * * Lets try a lazy evaluation. In this stage, we should evaluate all those * features that gives big bonus/penalties. E.g. squares around king is * attacked by enemy pieces, 2 rooks on 7th rank, runaway passed pawns etc. * This will be the direction, so things will continue to change in this * section. * ****************************************************************************/ EvalCall++; phase = PHASE; b = board.b[white]; pieces[white] = b[knight] | b[bishop] | b[rook] | b[queen]; npiece[white] = nbits (pieces[white]); b = board.b[black]; pieces[black] = b[knight] | b[bishop] | b[rook] | b[queen]; npiece[black] = nbits (pieces[black]); s1 = MATERIAL; if ((s1 + maxposnscore[side] < alpha || s1 - maxposnscore[xside] > beta) && phase <= 6) { score = s1; goto next; } s = 0; s += ScoreDev (side) - ScoreDev (xside); s += ScoreP (side) - ScoreP (xside); s += ScoreK (side) - ScoreK (xside); s += BishopTrapped (side) - BishopTrapped (xside); s += DoubleQR7 (side) - DoubleQR7 (xside); s1 = s + MATERIAL;/************************************************************************** * * See if we can have a lazy evaluation cut. Otherwise its a slow eval. * **************************************************************************/ if (s1 + lazyscore[side] < alpha || s1 - lazyscore[side] > beta) { score = s1; } else { EvalCnt++; GenAtaks(); s1 = HUNGPENALTY * ( EvalHung(side) - EvalHung(xside) ); FindPins(&pinned); for (piece = knight; piece < king; piece++) { s1 += (*ScorePiece[piece]) (side) - (*ScorePiece[piece]) (xside); } lazyscore[side] = MAX (s1, lazyscore[side]); maxposnscore[side] = MAX (maxposnscore[side], s + s1); score = s + s1 + MATERIAL; }/*************************************************************************** * * Trade down bonus code. When ahead, trade pieces & not pawns; * ***************************************************************************/next: if (MATERIAL >= 200) { score += (RootPieces - nbits(pieces[white] | pieces[black])) * TRADEPIECE; score -= (RootPawns - nbits(board.b[white][pawn] | board.b[black][pawn])) * TRADEPAWNS; } else if (MATERIAL <= -200) { score -= (RootPieces - nbits(pieces[white] | pieces[black])) * TRADEPIECE; score += (RootPawns - nbits(board.b[white][pawn] | board.b[black][pawn])) * TRADEPAWNS; } /*************************************************************************** * * Opposite color bishops is drawish. * ***************************************************************************/ if (ENDING && pieces[white] == board.b[white][bishop] && pieces[black] == board.b[black][bishop] && ((pieces[white] & WHITESQUARES && pieces[black] & BLACKSQUARES) || (pieces[white] & BLACKSQUARES && pieces[black] & WHITESQUARES))) { score /= 2; } /*************************************************************************** * * When one side has no mating material, then his score can never be > 0. * ***************************************************************************/ if (score > 0 && !board.b[side][pawn] && (board.material[side] < ValueR || pieces[side] == board.b[side][knight])) score = 0; if (score < 0 && !board.b[xside][pawn] && (board.material[xside] < ValueR || pieces[xside] == board.b[xside][knight])) score = 0; return (score);}short EvaluateDraw (void)/*************************************************************************** * * This routine is called by search() and quiesce() before anything else * is done. Its purpose it to check if the current position is a draw. * 0. 50-move draw. * 1. If there are any pawns, it is not. * 2. If both sides has anything less than a rook, draw. * 3. If both sides has <= 2 knights only, draw. * 4. If its a KBBK and bishops of same color, draw. * ***************************************************************************/{ BitBoard *w, *b; int wm, bm, wn, bn; /* * Exception - if we are close to a pawn move, promotion * or capture it is possible a forced mate will follow. * So we assume not drawn for 2 moves. */ if ( (GameCnt-Game50) < 5 ) return (false); /* 50 move rule */ if ( (GameCnt-Game50) > 100 ) return (true); w = board.b[white]; b = board.b[black]; if (w[pawn] != 0 || b[pawn] != 0) return (false); wm = board.material[white]; bm = board.material[black]; wn = nbits (w[knight]); bn = nbits (b[knight]); if ((wm<ValueR || (wm==2*ValueN && wn==2)) && (bm<ValueR || (bm==2*ValueN && bn==2))) return (true); if (wm < ValueR) { if (bm == 2*ValueB && ( nbits(board.b[black][bishop] & WHITESQUARES) == 2 || nbits(board.b[black][bishop] & BLACKSQUARES) == 2 )) return (true); } if (bm < ValueR) { if (wm == 2*ValueB && ( nbits(board.b[white][bishop] & WHITESQUARES) == 2 || nbits(board.b[white][bishop] & BLACKSQUARES) == 2 )) return (true); } return (false);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -