?? 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 + -