📄 eval.c
字号:
/* GNU Chess 5.0 - eval.c - evaluation code Copyright (c) 1999-2002 Free Software Foundation, Inc. GNU Chess is based on the two research programs Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft. GNU Chess is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Chess is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Chess; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Contact Info: bug-gnu-chess@gnu.org cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net*//**************************************************************************** * * * *****************************************************************************/#include <stdio.h>#include <string.h>#include <stdlib.h>#include "common.h"#include "eval.h"int LoneKing (int, int);int ScoreKBNK (int, int);int KPK (int);int BishopTrapped (short);int DoubleQR7 (short);BitBoard passed[2];BitBoard weaked[2];static int PawnSq[2][64] = {{ 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5,-10,-10, 5, 5, 5, -2, -2, -2, 6, 6, -2, -2, -2, 0, 0, 0, 25, 25, 0, 0, 0, 2, 2, 12, 16, 16, 12, 2, 2, 4, 8, 12, 16, 16, 12, 4, 4, 4, 8, 12, 16, 16, 12, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 16, 12, 4, 4, 4, 8, 12, 16, 16, 12, 4, 4, 2, 2, 12, 16, 16, 12, 2, 2, 0, 0, 0, 25, 25, 0, 0, 0, -2, -2, -2, 6, 6, -2, -2, -2, 5, 5, 5,-10,-10, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0}};static const int Passed[2][8] ={ { 0, 48, 48, 120, 144, 192, 240, 0}, {0, 240, 192, 144, 120, 48, 48, 0} };/* Penalties for one or more isolated pawns on a given file */static const int isolani_normal[8] = { -8, -10, -12, -14, -14, -12, -10, -8};/* Penalties if the file is half-open (i.e. no enemy pawns on it) */static const int isolani_weaker[8] = { -22, -24, -26, -28, -28, -26, -24, -22};static const BitBoard d2e2[2] = { ULL(0x0018000000000000), ULL(0x0000000000001800) };static const BitBoard brank7[2] = { ULL(0x000000000000FF00), ULL(0x00FF000000000000) };static const BitBoard brank8[2] = { ULL(0x00000000000000FF), ULL(0xFF00000000000000) };static const BitBoard brank67[2] = { ULL(0x0000000000FFFF00), ULL(0x00FFFF0000000000) };static const BitBoard brank58[2] = { ULL(0x00000000FFFFFFFF), ULL(0xFFFFFFFF00000000) };int ScoreP (short side)/*************************************************************************** * * Pawn evaluation is based on the following factors (which is being * constantly updated!). * * 1. Pawn square tables. * 2. Passed pawns. * 3. Backward pawns. * 4. Pawn base under attack. * 5. Doubled pawns * 6. Isolated pawns * 7. Connected passed pawns on 6/7th rank. * 8. Unmoved & blocked d, e pawn * 9. Passed pawn which cannot be caught. * 10. Pawn storms. * ***************************************************************************/{ int xside; int s, sq, i, i1; int n1, n2, backward; int nfile[8]; int EnemyKing; BitBoard c, t, p, blocker, *e; PawnSlot *ptable; if (board.b[side][pawn] == NULLBITBOARD) return (0); xside = 1^side; EnemyKing = board.king[xside]; p = board.b[xside][pawn]; c = t = board.b[side][pawn]; ptable = PawnTab[side] + (PawnHashKey & PHashMask); TotalPawnHashCnt++; if (ptable->phase == phase && ptable->pkey == KEY(PawnHashKey)) { GoodPawnHashCnt++; s = ptable->score; passed[side] = ptable->passed; weaked[side] = ptable->weaked; goto phase2; } s = 0; passed[side] = NULLBITBOARD; weaked[side] = NULLBITBOARD; memset (nfile, 0, sizeof (nfile)); while (t) { sq = leadz (t); CLEARBIT (t, sq); s += PawnSq[side][sq]; /* Passed pawns */ if ((p & PassedPawnMask[side][sq]) == NULLBITBOARD) { if ((side == white && (FromToRay[sq][sq|56] & c) == 0) || (side == black && (FromToRay[sq][sq&7] & c) == 0)) { passed[side] |= BitPosArray[sq]; s += (Passed[side][RANK(sq)] * phase) / 12; } } /* Backward pawns */ backward = false; /* i = sq + (side == white ? 8 : -8); */ if ( side == white ) { i = sq + 8; } else { i= sq - 8; } if (!(PassedPawnMask[xside][i] & ~FileBit[ROW(sq)] & c) && cboard[i] != pawn) { n1 = nbits (c & MoveArray[ptype[xside]][i]); n2 = nbits (p & MoveArray[ptype[side]][i]); if (n1 < n2) backward = true; } if (!backward && (BitPosArray[sq] & brank7[xside])) { i1 = 1; i = i + (side == white ? 8 : -8); if (!(PassedPawnMask[xside][i] & ~FileBit[ROW(i1)] & c)) { n1 = nbits (c & MoveArray[ptype[xside]][i]); n2 = nbits (p & MoveArray[ptype[side]][i]); if (n1 < n2) backward = true; } } if (backward) { weaked[side] |= BitPosArray[sq]; s += BACKWARDPAWN; } /* Pawn base under attack */ if ((MoveArray[ptype[side]][sq] & p) && (MoveArray[ptype[side]][sq] & c)) s += PAWNBASEATAK; /* Increment file count for isolani & doubled pawn evaluation */ nfile[ROW(sq)]++; } for (i = 0; i <= 7; i++) { /* Doubled pawns */ if (nfile[i] > 1) s += DOUBLEDPAWN; /* Isolated pawns */ if (nfile[i] && (!(c & IsolaniMask[i]))) { /* Isolated on a half-open file */ if (!(FileBit[i] & board.b[xside][pawn])) s += isolani_weaker[i] * nfile[i]; else /* Normal isolated pawn */ s += isolani_normal[i] * nfile[i]; weaked[side] |= (c & FileBit[i]); } } if (computerplays == side) { /* Penalize having eight pawns */ if (nbits(board.b[computerplays][pawn]) == 8) s += EIGHT_PAWNS; /* Detect stonewall formation in enemy */ if (nbits(stonewall[xside] & board.b[xside][pawn]) == 3) s += STONEWALL; /* Locked pawns */ n = 0; if (side == white) n = nbits((c >> 8) & board.b[xside][pawn] & boxes[1]); else n = nbits((c << 8) & board.b[xside][pawn] & boxes[1]); if (n > 1) s += n * LOCKEDPAWNS; } /* Save the score into the pawn hash table */ ptable->pkey = KEY(PawnHashKey); ptable->passed = passed[side]; ptable->weaked = weaked[side]; ptable->score = s; ptable->phase = phase;/*************************************************************************** * * This section of the pawn code cannot be saved into the pawn hash as * they depend on the position of other pieces. So they have to be * calculated again. * ***************************************************************************/phase2: /* Pawn on f6/c6 with Queen against castled king is very strong */ c = board.b[side][pawn]; sq = board.king[xside]; if (side == white && board.b[side][queen] && (BitPosArray[C6] | BitPosArray[F6]) & c) { if (c & BitPosArray[F6] && sq > H6 && distance[sq][G7]==1) s += PAWNNEARKING; if (c & BitPosArray[C6] && sq > H6 && distance[sq][B7]==1) s += PAWNNEARKING; } else if (side == black && board.b[side][queen] && (BitPosArray[C3] | BitPosArray[F3]) & c) { if (c & BitPosArray[F3] && sq < A3 && distance[sq][G2]==1) s += PAWNNEARKING; if (c & BitPosArray[C3] && sq < A3 && distance[sq][B2]==1) s += PAWNNEARKING; } /* Connected passed pawns on 6th or 7th rank */ t = passed[side] & brank67[side]; if (t && (board.pmaterial[xside] == ValueR || (board.pmaterial[xside] == ValueN && pieces[xside] == board.b[xside][knight]))) { n1 = ROW(board.king[xside]); n2 = RANK(board.king[xside]); for (i = 0; i <= 6; i++) { if (t & FileBit[i] && t & FileBit[i+1] && (n1 < i-1 || n1 > i+1 || (side == white && n2 < 4) || (side == black && n2 > 3))) s += CONNECTEDPP; } } /* Pawn on d2,e2/d7,e7 is blocked */ blocker = board.friends[side] | board.friends[xside]; if (side == white && (((c & d2e2[white]) >> 8) & blocker)) s += BLOCKDEPAWN; if (side == black && (((c & d2e2[black]) << 8) & blocker)) s += BLOCKDEPAWN; /* Enemy has no pieces & King is outside of passed pawn square */ if (passed[side] && board.pmaterial[xside]==0) { e = board.b[xside]; i1 = board.king[xside]; p = passed[side]; while (p) { sq = leadz (p); CLEARBIT (p, sq); if (board.side == side) { if (!(SquarePawnMask[side][sq] & board.b[xside][king])) s += ValueQ * Passed[side][RANK(sq)] / PFACTOR; } else if (!(MoveArray[king][i1] & SquarePawnMask[side][sq])) s += ValueQ * Passed[side][RANK(sq)] / PFACTOR; } } /* If both sides are castled on different sides, bonus for pawn storms */ c = board.b[side][pawn]; if (abs (ROW (board.king[side]) - ROW (board.king[xside])) >= 4 && PHASE < 6) { n1 = ROW (board.king[xside]); p = (IsolaniMask[n1] | FileBit[n1]) & c; while (p) { sq = leadz (p); CLEARBIT (p, sq); s += 10 * (5 - distance[sq][board.king[xside]]); } } return (s);}static const int Outpost[2][64] ={ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};static inline int CTL(short sq, short piece __attribute__ ((unused)), short side)/*************************************************************************** * * Return a score corresponding to the number of squares in the bitboard * target multiplied by a specified bonus for controlling each square. * * Can be used for control of the center and attacks around the king. * ***************************************************************************/{ int s, n, EnemyKing, FriendlyKing; BitBoard controlled; s = 0; EnemyKing = board.king[1^side]; FriendlyKing = board.king[side]; controlled = AttackXFrom (sq, side); /* Center control */ n = nbits (controlled & boxes[0]); s += 4*n; /* Attacks against enemy king */ n = nbits (controlled & DistMap[EnemyKing][2]); s += n; /* Defenses for friendly king */ n = nbits (controlled & DistMap[FriendlyKing][2]); s += n; /* Mobility */ n = nbits(controlled); s += 4*n; return (s);}int ScoreN (short side)/*************************************************************************** * * 1. central knight - distance from enemy king. * 2. mobility/control/attack * 3. outpost knight protected by pawn. * 4. knight attacking weak pawns. * ***************************************************************************/{ int xside; int s, s1, sq; int EnemyKing; BitBoard c, t; if (board.b[side][knight] == NULLBITBOARD) return (0); xside = side^1; s = s1 = 0; c = board.b[side][knight]; t = board.b[xside][pawn]; EnemyKing = board.king[xside]; if ( c & pinned ) { s += PINNEDKNIGHT * nbits(c & pinned); } while (c) { sq = leadz (c); CLEARBIT (c, sq); /* Control */ s1 = CTL(sq,knight,side); if ( (BitPosArray[sq] & rings[3]) != NULLBITBOARD) s1 += KNIGHTONRIM; if (Outpost[side][sq] && !(t & IsolaniMask[ROW(sq)] & PassedPawnMask[side][sq]) ) { s1 += OUTPOSTKNIGHT; /* Knight defended by own pawn */ if (MoveArray[ptype[xside]][sq] & board.b[side][pawn]) s1 += OUTPOSTKNIGHT; } /* Attack on weak opponent pawns */ if (MoveArray[knight][sq] & weaked[xside]) s1 += ATAKWEAKPAWN; s += s1; } return (s);}int ScoreB (short side)/**************************************************************************** * * 1. double bishops. * 2. mobility/control/attack * 3. outpost bishop * 4. fianchetto bishop * 5. Bishop pair * ****************************************************************************/{ int xside; int s, s1, n, sq, EnemyKing; BitBoard c, t; if (board.b[side][bishop] == NULLBITBOARD) return (0); s = s1 = 0; c = board.b[side][bishop]; xside = side ^ 1; EnemyKing = board.king[xside]; n = 0; t = board.b[xside][pawn]; if ( c & pinned ) { s += PINNEDBISHOP * nbits(c & pinned); } while (c) { sq = leadz (c); CLEARBIT (c, sq); n++; /* Control */ s1 = CTL(sq,bishop,side); /* Outpost bishop */ if (Outpost[side][sq] && !(t & IsolaniMask[ROW(sq)] & PassedPawnMask[side][sq])) { s1 += OUTPOSTBISHOP;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -