/*
Protector -- a UCI chess engine
Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com)
This program 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 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdlib.h>
#include "position.h"
#include "fen.h"
#include "io.h"
#ifdef INCLUDE_TABLEBASE_ACCESS
#include "tablebase.h"
#endif
#define dumpPos dumpPosition(position);
#define KNIGHT_VS_PASSED_WING_PAWNS /* */
#define BISHOP_BLOCKERS /* */
#define PINNED_KNIGHT_BONUS /* */
#define MALUS_PASSED_PAWN_LACK_OF_SUPPORT /* */
#define MALUS_ROOK_BLOCKING_PASSER /* */
#define BONUS_SPACE_ATTACKS /* */
#define MALUS_QUEEN_DEFENDER_DISTANCE /* */
#define MALUS_BLOCKABLE_PASSERS /* */
#define BONUS_HIDDEN_PASSER /* */
#define BONUS_WINNING_PASSER /* */
#define BONUS_EXCHANGE_UP /* */
#define BONUS_SPECIAL_PASSED_PAWNS /* */
#define BONUS_PASSER_CLEAR_PATH /* */
/* #define BONUS_SLIDER_ATTACKS /* */
/* #define HOMELAND_SECURITY_BONUS /* */
/* #define MALUS_UNDEFENDED_KINGATTACKS /* */
/* #define BONUS_TARGETS /* */
/* #define MALUS_OFFSIDE_KING /* */
/* #define BONUS_CONNECTED_DISTANT_PASSERS /* */
/* #define GENERATE_TABLES /* */
/* #define MALUS_UNDEFENDED_KINGATTACKS /* */
/* #define ADAPTIVE_DELTA /* */
#include "evaluation.h"
/* -------------------------------------------------------------------------- */
const int PAWN_MALUS_DOUBLED_OPENING = 10;
const int PAWN_MALUS_DOUBLED_ENDGAME = 20;
const int PAWN_MALUS_ISOLATED_OPENING = 10;
const int PAWN_MALUS_ISOLATED_ON_OPEN_FILE = 20;
const int PAWN_MALUS_ISOLATED_ENDGAME = 20;
const int PAWN_MALUS_ISOLATED_FIXED_OPENING = 6;
const int PAWN_MALUS_ISOLATED_FIXED_ENDGAME = 6;
const int PAWN_MALUS_BACKWARD_OPENING = 8;
const int PAWN_MALUS_BACKWARD_ON_OPEN_FILE = 16;
const int PAWN_MALUS_BACKWARD_ENDGAME = 10;
const int PAWN_MALUS_BACKWARD_FIXED_OPENING = 4;
const int PAWN_MALUS_BACKWARD_FIXED_ENDGAME = 4;
const int PAWN_CANDIDATE_OPENING_MIN = 5;
const int PAWN_CANDIDATE_OPENING_MAX = 55;
const int PAWN_CANDIDATE_ENDGAME_MIN = 10;
const int PAWN_CANDIDATE_ENDGAME_MAX = 110;
const int PASSED_PAWN_BONUS_OPENING_MIN = 10;
const int PASSED_PAWN_BONUS_OPENING_MAX = 70;
const int PASSED_PAWN_BONUS_ENDGAME_MIN = 20;
const int PASSED_PAWN_BONUS_ENDGAME_MAX = 140;
const int PASSED_PAWN_BONUS_UNSTOPPABLE = 800;
const int PASSED_PAWN_BONUS_NOT_BLOCKED = 60;
const int PASSED_PAWN_BONUS_ACCOMPANIED = 4;
const int PASSED_PAWN_MALUS_LACK_OF_SUPPORT = 30;
const int PASSED_PAWN_ATTACKERDIST_WEIGHT = 15;
const int PASSED_PAWN_DEFENDERDIST_WEIGHT = 20;
const int PASSED_PAWN_BONUS_OUTSIDE_OPENING = 8;
const int PASSED_PAWN_BONUS_OUTSIDE_ENDGAME = 14;
const int PASSED_PAWN_BONUS_PROTECTED_OPENING = 10;
const int PASSED_PAWN_BONUS_PROTECTED_ENDGAME = 16;
const int PASSED_PAWN_BONUS_CONNECTED_OPENING = 16;
const int PASSED_PAWN_BONUS_CONNECTED_ENDGAME = 24;
const int KNIGHT_BONUS_ATTACK = 20;
const int KNIGHT_MALUS_VS_BOTH_WINGS = 10;
const int KNIGHT_MALUS_VS_OUTSIDE_PASSED = 15;
const int BISHOP_MALUS_BLOCKER[3] = { 0, 8, 20 };
const int BISHOP_BONUS_ATTACK = 20;
const int BISHOP_MALUS_BLOCKED = 50;
const int BISHOP_MALUS_TRAPPED = 100;
const int BISHOP_BONUS_PINNING_KNIGHT_OPENING = 15;
const int BISHOP_BONUS_PINNING_KNIGHT_ENDGAME = 10;
const int ROOK_BONUS_ON_SEMIOPEN_FILE = 10;
const int ROOK_BONUS_ON_OPEN_FILE = 20;
const int ROOK_MALUS_BLOCKED = 48;
const int ROOK_MALUS_SQUEEZED = 12;
const int ROOK_BONUS_KING_FILE = 20;
const int ROOK_BONUS_LATERAL_KING_FILE = 10;
const int ROOK_BONUS_ON_SEVENTH_RANK_OPENING = 20;
const int ROOK_BONUS_ON_SEVENTH_RANK_ENDGAME = 40;
const int ROOK_BONUS_ATTACK = 40;
const int ROOK_MALUS_BLOCKING_PASSER = 90;
const int QUEEN_BONUS_ON_SEVENTH_RANK_OPENING = 10;
const int QUEEN_BONUS_ON_SEVENTH_RANK_ENDGAME = 20;
const int QUEEN_BONUS_ATTACK = 80;
#ifdef BONUS_SPACE_ATTACKS
const int KING_MALUS_PAWN_ATTACK[8] = { 0, 0, 30, 20, 10, 0, 0, 0 };
#else
const int KING_MALUS_PAWN_ATTACK[8] = { 0, 0, 60, 30, 10, 0, 0, 0 };
#endif
const int KING_ATTACK_WEIGHT[17] = { 0, 0, 128, 192, 224, 240, 248,
252, 254, 255, 256, 256, 256, 256, 256, 256, 256
};
const int KING_MALUS_TRAPPED_OPENING = 20;
const int KING_MALUS_TRAPPED_ENDGAME = 20;
static const int SPACE_BONUS_WEIGHT[16] = {
0, 2, 5, 8, 11, 14, 17, 20, 20, 20, 20, 20, 20, 20, 20, 20
};
const int STD_BONUS_COUNT = 2;
#define KPKP_TABLESIZE (2*32*49*49)
/* -------------------------------------------------------------------------- */
/*
#define PAWN_PHASE 0
#define KNIGHT_PHASE 1
#define BISHOP_PHASE 1
#define ROOK_PHASE 2
#define QUEEN_PHASE 4
const int PHASE_MAX = 16 * PAWN_PHASE + 4 * KNIGHT_PHASE + 4 * BISHOP_PHASE +
4 * ROOK_PHASE + 2 * QUEEN_PHASE;
*/
#define NUM_EXPO_FACTORS 128
int centerDistance[_64_], centerTaxiDistance[_64_];
int attackPoints[16];
Bitboard weakOutpostSquareCandidates[2];
Bitboard butterflySquares[_64_];
Bitboard lateralSquares[_64_];
Bitboard companionFiles[_64_];
Bitboard passedPawnRectangle[2][_64_];
Bitboard passedPawnCorridor[2][_64_];
int passedPawnDefenderMalus[2][2][_64_][_64_];
Bitboard candidateDefenders[2][_64_];
Bitboard candidateSupporters[2][_64_];
Bitboard pawnOpponents[2][_64_];
Bitboard rookTraps[2];
Bitboard rookBlockers[_64_];
Bitboard centralFiles;
Bitboard kingRealm[2][_64_][_64_];
Bitboard attackingRealm[2];
Bitboard homeland[2];
Bitboard troitzkyArea[2];
Bitboard krprkDrawFiles;
Bitboard A1C1, F1H1, A1B1, G1H1;
KingAttacks kingAttacks[_64_];
UINT64 numEvals = 0, sumDiff = 0, sumDiffSquare = 0;
int expoFactor[NUM_EXPO_FACTORS];
int expoValue[NUM_EXPO_FACTORS];
int kingChaseMalus[3][_64_];
int sliderAttackPoints[16][16];
MaterialInfo materialInfo[MATERIALINFO_TABLE_SIZE];
#ifdef ADAPTIVE_DELTA
int maxDelta = 180;
#else
const int maxDelta = 180;
#endif
#ifdef GENERATE_TABLES
UINT64 kpkpTempTable[KPKP_TABLESIZE];
#endif
#ifndef NDEBUG
bool debugEval = FALSE;
#endif
int getWhiteKingTableIndex(const Square whiteKingSquare)
{
const File fileCount = file(whiteKingSquare);
const Rank rankCount = rank(whiteKingSquare);
return 4 * rankCount + fileCount;
}
static INLINE unsigned int getKpkpIndexFromSquares(const Square wk,
const Square bk,
const Square wp,
const Square bp)
{
const unsigned int M1 = 2;
const unsigned int M2 = 32 * M1;
const unsigned int M3 = 64 * M2;
const unsigned int M4 = 49 * M3;
unsigned int index;
index = getWhiteKingTableIndex(wk) * M1 + (bk * M2) +
((wp - A2) * M3) + ((bp - A2) * M4);
assert((wp - A2) >= 0);
assert((bp - A2) >= 0);
assert((wp - A2) < 49);
assert((bp - A2) < 49);
assert(index < (KPKP_TABLESIZE << 6));
return index;
}
static INLINE unsigned int getKpkpIndex(const Position * position)
{
Square wk = position->king[WHITE];
Square bk = position->king[BLACK];
Square wp = A8, bp = A8;
if (position->piecesOfType[WHITE_PAWN] != EMPTY_BITBOARD)
{
Bitboard whitePawns = position->piecesOfType[WHITE_PAWN];
wp = getNextSquare(&whitePawns);
}
if (position->piecesOfType[BLACK_PAWN] != EMPTY_BITBOARD)
{
Bitboard blackPawns = position->piecesOfType[BLACK_PAWN];
bp = getNextSquare(&blackPawns);
}
if (position->activeColor == BLACK)
{
const Square tmpWk = wk;
const Square tmpWp = wp;
#ifndef NDEBUG
if (debugEval)
{
logDebug("before vertical flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
wk = getFlippedSquare(bk);
bk = getFlippedSquare(tmpWk);
wp = (bp == A8 ? bp : getFlippedSquare(bp));
bp = (tmpWp == A8 ? tmpWp : getFlippedSquare(tmpWp));
#ifndef NDEBUG
if (debugEval)
{
logDebug("after vertical flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
}
if (file(wk) >= FILE_E)
{
#ifndef NDEBUG
if (debugEval)
{
logDebug("before horizontal flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
wk = getHflippedSquare(wk);
bk = getHflippedSquare(bk);
wp = (wp == A8 ? wp : getHflippedSquare(wp));
bp = (bp == A8 ? bp : getHflippedSquare(bp));
#ifndef NDEBUG
if (debugEval)
{
logDebug("after horizontal flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
}
return getKpkpIndexFromSquares(wk, bk, wp, bp);
}
#ifndef NDEBUG
void dumpTableAccess(const Position * position, const int egtbValue,
const int internalValue)
{
int index;
debugEval = TRUE;
index = getKpkpIndex(position);
logDebug("\n### egtbValue=%d internalValue=%d\n\n", egtbValue,
internalValue);
dumpPosition(position);
}
#endif
/**
* Return a tablebase value for a kpkp position.
*
* return 0 for draw, 1 for white winning, 2 for black winning
*/
static INLINE int getKpkpValue(const Position * position)
{
const int WIN_VALUE = 800;
const unsigned int index = getKpkpIndex(position);
const unsigned int bucketIndex = index >> 6;
const unsigned int shiftIndex = index - 64 * bucketIndex;
const int value = (int) (3 & (kpkpTable[bucketIndex] >> shiftIndex));
assert((shiftIndex % 2) == 0);
assert(value >= 0 && value <= 2);
#ifdef INCLUDE_TABLEBASE_ACCESS
#ifndef NDEBUG
{
const int tbValue = probeTablebase(position);
statCount1++;
if (tbValue == 0)
{
if (value != 0)
{
dumpTableAccess(position, tbValue, value);
}
/* assert(value == 0); */
}
if (tbValue > 0)
{
if (value != 1)
{
dumpTableAccess(position, tbValue, value);
}
/* assert(value == 1); */
}
if (tbValue < 0)
{
if (value != 2)
{
dumpTableAccess(position, tbValue, value);
}
/* assert(value == 2); */
}
}
#endif
#endif
if (value != 0)
{
#ifndef NDEBUG
if (debugEval)
{
logDebug("tablevalue=%d\n", value);
dumpPosition(position);
}
#endif
return (value == 1 ? WIN_VALUE : -WIN_VALUE);
}
else
{
return value;
}
}
#ifdef GENERATE_TABLES
void cleanPosition(Position * position)
{
Square square;
ITERATE(square)
{
position->piece[square] = NO_PIECE;
}
position->activeColor = WHITE;
position->enPassantSquare = NO_SQUARE;
}
INLINE static UINT64 getTableValue(int dtmValue)
{
if (dtmValue == 0)
{
return 0;
}
return (dtmValue > 0 ? 1 : 2);
}
void updateKpkpValue(const Position * position)
{
const UINT64 tableValue = getTableValue(probeTablebase(position));
const unsigned int index = getKpkpIndex(position);
const unsigned int bucketIndex = index >> 6;
const unsigned int shiftIndex = index - 64 * bucketIndex;
const UINT64 mask = ~(((UINT64) 3) << shiftIndex);
const UINT64 oldBucket = kpkpTempTable[bucketIndex];
const UINT64 newBucket = (oldBucket & mask) | (tableValue << shiftIndex);
assert((shiftIndex % 2) == 0);
assert(tableValue >= 0 && tableValue <= 2);
assert(bucketIndex < KPKP_TABLESIZE);
assert(shiftIndex <= 62);
kpkpTempTable[bucketIndex] = newBucket;
}
void generateKpkpTable()
{
int i;
Square wk, bk, wp, bp;
Position position;
long count = 0;
for (i = 0; i < KPKP_TABLESIZE; i++)
{
kpkpTempTable[i] = ULONG_ZERO;
}
for (wk = A1; wk <= H8; wk++)
{
if (file(wk) >= FILE_E)
{
continue; /* assume wk 2b at the queenside */
}
for (bk = A1; bk <= H8; bk++)
{
if (distance(bk, wk) < 2)
{
continue;
}
for (wp = A2; wp <= A8; wp++)
{
if (wp != A8)
{
if (wp == wk || wp == bk)
{
continue;
}
}
for (bp = A2; bp <= A8; bp++)
{
if (bp != A8)
{
if (bp == wk || bp == bk || bp == wp)
{
continue;
}
}
cleanPosition(&position);
position.piece[wk] = WHITE_KING;
position.piece[bk] = BLACK_KING;
if (wp >= A2 && wp <= H7)
{
position.piece[wp] = WHITE_PAWN;
}
if (bp >= A2 && bp <= H7)
{
position.piece[bp] = BLACK_PAWN;
}
initializePosition(&position);
updateKpkpValue(&position);
count++;
if ((count & 0xffff) == 0)
{
logDebug("%ld done.\n", count);
}
}
}
}
}
writeTableToFile(&kpkpTempTable[0], KPKP_TABLESIZE, "kpkp.c", "kpkpTable");
}
#endif
void dumpEvalStats()
{
logReport("numEvals: %llu sumDiff: %llu sumDiffSquare: %llu",
numEvals, sumDiff, sumDiffSquare);
}
INLINE static int quad(int y_min, int y_max, int rank)
{
const int bonusPerRank[8] = { 0, 0, 0, 26, 77, 154, 256, 0 };
return y_min + ((y_max - y_min) * bonusPerRank[rank] + 128) / 256;
}
INLINE static int getHomeSecurityWeight(const Position * position)
{
const int count = getPieceCount(position, WHITE_KNIGHT) +
getPieceCount(position, WHITE_BISHOP) +
getPieceCount(position, BLACK_KNIGHT) +
getPieceCount(position, BLACK_BISHOP);
return count * count;
}
INLINE static bool squareIsPawnSafe(const EvaluationBase * base,
const Color color, const Square square)
{
return testSquare(base->pawnAttackableSquares[opponent(color)],
square) == FALSE;
}
INLINE static bool hasAttackingBishop(const Position * position,
const Color attackingColor,
const Square square)
{
const Bitboard attackers =
((lightSquares & minValue[square]) != EMPTY_BITBOARD ?
lightSquares : darkSquares);
return (bool)
((attackers & position->piecesOfType[BISHOP | attackingColor]) !=
EMPTY_BITBOARD);
}
INLINE static bool pieceIsPinnedByBishop(const Position * position,
const Square pinnedPiece,
const Square pinningPiece,
const Bitboard targets)
{
return (bool)
((getDiaSquaresBehind(position, pinnedPiece, pinningPiece) & targets) !=
EMPTY_BITBOARD);
}
INLINE static bool pieceIsPinnedByRook(const Position * position,
const Square pinnedPiece,
const Square pinningPiece,
const Bitboard targets)
{
return (bool)
((getOrthoSquaresBehind(position, pinnedPiece, pinningPiece) & targets)
!= EMPTY_BITBOARD);
}
INLINE static void getPawnInfo(const Position * position,
EvaluationBase * base)
{
Bitboard white = position->piecesOfType[WHITE_PAWN];
Bitboard black = position->piecesOfType[BLACK_PAWN];
Bitboard whiteLateralSquares, blackLateralSquares;
Bitboard whiteSwamp, blackSwamp;
Bitboard pawnAttackableSquaresWhite, pawnAttackableSquaresBlack;
register Bitboard tmp1, tmp2;
/* Calculate upward and downward realms */
tmp1 = (white << 8) | (white << 16) | (white << 24);
tmp1 |= (tmp1 << 24);
tmp2 = (white >> 8) | (white >> 16) | (white >> 24);
tmp2 |= (tmp2 >> 24);
base->doubledPawns[WHITE] = white & tmp2;
base->upwardRealm[WHITE] = (tmp1 = tmp1 | white);
pawnAttackableSquaresWhite = ((tmp1 & nonA) << 7) | ((tmp1 & nonH) << 9);
base->downwardRealm[WHITE] = tmp2;
/* Calculate upward and downward realms */
tmp1 = (black >> 8) | (black >> 16) | (black >> 24);
tmp1 |= (tmp1 >> 24);
tmp2 = (black << 8) | (black << 16) | (black << 24);
tmp2 |= (tmp2 << 24);
base->doubledPawns[BLACK] = black & tmp2;
base->upwardRealm[BLACK] = (tmp1 = tmp1 | black);
pawnAttackableSquaresBlack = ((tmp1 & nonA) >> 9) | ((tmp1 & nonH) >> 7);
base->downwardRealm[BLACK] = tmp2;
/* Calculate the squares protected by a pawn */
whiteLateralSquares = ((white & nonA) >> 1) | ((white & nonH) << 1);
base->pawnProtectedSquares[WHITE] = whiteLateralSquares << 8;
blackLateralSquares = ((black & nonA) >> 1) | ((black & nonH) << 1);
base->pawnProtectedSquares[BLACK] = blackLateralSquares >> 8;
/* Identify the passed pawns */
whiteSwamp = base->downwardRealm[BLACK] | base->upwardRealm[WHITE] |
pawnAttackableSquaresWhite;
blackSwamp = base->downwardRealm[WHITE] | base->upwardRealm[BLACK] |
pawnAttackableSquaresBlack;
base->passedPawns[WHITE] = white & ~blackSwamp;
base->passedPawns[BLACK] = black & ~whiteSwamp;
/* Calculate the weak pawns */
tmp2 = ~(white | black | base->pawnProtectedSquares[BLACK]);
tmp1 = (whiteLateralSquares & tmp2) >> 8;
tmp1 |= (tmp1 & squaresOfRank[RANK_3] & tmp2) >> 8;
base->weakPawns[WHITE] =
(white & ~(pawnAttackableSquaresWhite | whiteLateralSquares | tmp1));
tmp2 = ~(white | black | base->pawnProtectedSquares[WHITE]);
tmp1 = (blackLateralSquares & tmp2) << 8;
tmp1 |= (tmp1 & squaresOfRank[RANK_6] & tmp2) << 8;
base->weakPawns[BLACK] =
(black & ~(pawnAttackableSquaresBlack | blackLateralSquares | tmp1));
base->weakOutpostSquares[WHITE] = base->upwardRealm[WHITE] &
~(pawnAttackableSquaresWhite |
base->downwardRealm[BLACK] | white | black) &
weakOutpostSquareCandidates[WHITE];
base->weakOutpostSquares[BLACK] = base->upwardRealm[BLACK] &
~(pawnAttackableSquaresBlack |
base->downwardRealm[WHITE] | white | black) &
weakOutpostSquareCandidates[BLACK];
/* Calculate the candidates */
base->candidatePawns[WHITE] = white & ~base->passedPawns[WHITE] &
(pawnAttackableSquaresWhite | whiteLateralSquares) &
~(base->upwardRealm[BLACK] | base->downwardRealm[WHITE]);
base->candidatePawns[BLACK] = black & ~base->passedPawns[BLACK] &
(pawnAttackableSquaresBlack | blackLateralSquares) &
~(base->upwardRealm[WHITE] | base->downwardRealm[BLACK]);
#ifdef BONUS_HIDDEN_PASSER
/* Calculate the hidden candidates */
base->hiddenCandidatePawns[WHITE] = white & (black >> 8) &
~pawnAttackableSquaresBlack & ~(blackLateralSquares) &
(squaresOfRank[RANK_5] | squaresOfRank[RANK_6]) &
base->pawnProtectedSquares[WHITE];
base->hiddenCandidatePawns[BLACK] = black & (white << 8) &
~pawnAttackableSquaresWhite & ~(whiteLateralSquares) &
(squaresOfRank[RANK_4] | squaresOfRank[RANK_3]) &
base->pawnProtectedSquares[BLACK];
#endif
tmp1 = black & base->pawnProtectedSquares[BLACK];
tmp2 = ((tmp1 & nonA) >> 9) & ((tmp1 & nonH) >> 7);
tmp2 &= ~pawnAttackableSquaresWhite;
tmp1 = tmp2 | (tmp2 >> 8);
base->fixedPawns[WHITE] = tmp1 | (tmp1 >> 16) | (tmp1 >> 32);
tmp1 = white & base->pawnProtectedSquares[WHITE];
tmp2 = ((tmp1 & nonA) << 7) & ((tmp1 & nonH) << 9);
tmp2 &= ~pawnAttackableSquaresBlack;
tmp1 = tmp2 | (tmp2 << 8);
base->fixedPawns[BLACK] = tmp1 | (tmp1 << 16) | (tmp1 << 32);
#ifdef BONUS_HIDDEN_PASSER
base->hasPassersOrCandidates[WHITE] = (bool)
(base->passedPawns[WHITE] != EMPTY_BITBOARD ||
base->candidatePawns[WHITE] != EMPTY_BITBOARD ||
base->hiddenCandidatePawns[WHITE] != EMPTY_BITBOARD);
base->hasPassersOrCandidates[BLACK] = (bool)
(base->passedPawns[BLACK] != EMPTY_BITBOARD ||
base->candidatePawns[BLACK] != EMPTY_BITBOARD ||
base->hiddenCandidatePawns[BLACK] != EMPTY_BITBOARD);
#endif
tmp1 = (white << 8) & ~(white | black);
tmp2 = white | (tmp1 & ~base->pawnProtectedSquares[BLACK]);
tmp2 |= tmp1 & base->pawnProtectedSquares[WHITE];
tmp1 &= squaresOfRank[RANK_3] & ~base->pawnProtectedSquares[BLACK];
tmp1 = (tmp1 << 8) & ~(white | black);
tmp2 |= tmp1 & ~base->pawnProtectedSquares[BLACK];
tmp2 |= tmp1 & base->pawnProtectedSquares[WHITE];
base->pawnAttackableSquares[WHITE] =
((tmp2 & nonA) << 7) | ((tmp2 & nonH) << 9);
/*dumpBitboard(base->pawnAttackableSquares[WHITE], "pawnAttackable white");
dumpPosition(position); */
tmp1 = (black >> 8) & ~(white | black);
tmp2 = black | (tmp1 & ~base->pawnProtectedSquares[WHITE]);
tmp2 |= tmp1 & base->pawnProtectedSquares[BLACK];
tmp1 &= squaresOfRank[RANK_6] & ~base->pawnProtectedSquares[WHITE];
tmp1 = (tmp1 >> 8) & ~(white | black);
tmp2 |= tmp1 & ~base->pawnProtectedSquares[WHITE];
tmp2 |= tmp1 & base->pawnProtectedSquares[BLACK];
base->pawnAttackableSquares[BLACK] =
((tmp2 & nonA) >> 9) | ((tmp2 & nonH) >> 7);
}
bool pawnIsPassed(const Position * position, const Square pawnSquare,
const Color pawnColor)
{
const Color defenderColor = opponent(pawnColor);
const Bitboard blockers = position->piecesOfType[PAWN | defenderColor] &
(candidateDefenders[pawnColor][pawnSquare] |
passedPawnCorridor[pawnColor][pawnSquare]);
return (bool) (blockers == EMPTY_BITBOARD);
}
static int getPassedPawnDefenderMalus(const Color pawnColor,
const Color activeColor,
const Square passedPawnSquare,
const Square defenderSquare)
{
const int pawnDirection = (pawnColor == WHITE ? 8 : -8);
const Square stopSquare = (Square) (passedPawnSquare + pawnDirection);
const Square rectangleSquare =
(pawnColor == activeColor ?
passedPawnSquare : (Square) (passedPawnSquare - pawnDirection));
const bool kingInRectangle =
testSquare(passedPawnRectangle[pawnColor][rectangleSquare],
defenderSquare);
const int defenderDistWeight =
(kingInRectangle ? (2 * PASSED_PAWN_DEFENDERDIST_WEIGHT) / 3 :
PASSED_PAWN_DEFENDERDIST_WEIGHT);
return distance(stopSquare, defenderSquare) * defenderDistWeight;
}
INLINE bool passerWalks(const Position * position, const Square passerSquare,
const Color passerColor)
{
const Square attackerKingSquare = position->king[passerColor];
const Square defenderKingSquare = position->king[opponent(passerColor)];
const int attackerDistance = distance(attackerKingSquare, passerSquare);
const Rank kingRank = colorRank(passerColor, attackerKingSquare);
const File passerFile = file(passerSquare);
if (passerFile >= FILE_B && passerFile <= FILE_G)
{
if ((kingRank == RANK_6 || kingRank == RANK_7) &&
kingRank > colorRank(passerColor, passerSquare) &&
abs(file(attackerKingSquare) - passerFile) <= 1 &&
attackerDistance <= 2)
{
if (position->activeColor == passerColor ||
attackerDistance == 1 ||
distance(defenderKingSquare, passerSquare) > 1)
{
return TRUE;
}
}
/*
if (kingRank == colorRank(passerColor, passerSquare) + 2 &&
abs(file(attackerKingSquare) - passerFile) <= 1 &&
attackerDistance <= 2)
{
if (position->activeColor == passerColor ||
attackerDistance == 1 ||
distance(defenderKingSquare, passerSquare) > 1)
{
return TRUE;
}
}
*/
}
else if ((kingRank == RANK_7 || kingRank == RANK_8) &&
abs(file(attackerKingSquare) - passerFile) == 1 &&
attackerDistance <= 2)
{
if (position->activeColor == passerColor ||
attackerDistance == 1 ||
distance(defenderKingSquare, passerSquare) > 1)
{
return TRUE;
}
}
return FALSE;
}
INLINE static void evaluatePassedPawns(Position * position,
EvaluationBase * base)
{
Square square;
Bitboard pieces = base->passedPawns[WHITE] | base->passedPawns[BLACK];
ITERATE_BITBOARD(&pieces, square)
{
const Piece currentPiece = position->piece[square];
const Color pawnColor = pieceColor(currentPiece);
const Color oppColor = opponent(pawnColor);
const Rank pawnRank = colorRank(pawnColor, square);
const int pawnDirection = (pawnColor == WHITE ? 8 : -8);
const Square stopSquare = (Square) (square + pawnDirection);
const int numDefenders = position->numberOfPieces[oppColor] -
position->numberOfPawns[oppColor];
int opDelta = 0;
int egDelta = PASSED_PAWN_BONUS_ENDGAME_MAX -
PASSED_PAWN_BONUS_ENDGAME_MIN;
bool blocked = TRUE;
#ifdef MALUS_BLOCKABLE_PASSERS
const bool hasSupportingBishop =
hasAttackingBishop(position, pawnColor, stopSquare);
const bool oppHasBlockingBishop =
hasAttackingBishop(position, oppColor, stopSquare);
#endif
#ifdef BONUS_SPECIAL_PASSED_PAWNS
Bitboard companions = candidateSupporters[oppColor][square] &
base->passedPawns[pawnColor];
Square companionSquare;
const Bitboard oppPawns = position->piecesOfType[PAWN | oppColor];
#endif
base->openingPoints[pawnColor] +=
quad(PASSED_PAWN_BONUS_OPENING_MIN, PASSED_PAWN_BONUS_OPENING_MAX,
pawnRank);
if (numDefenders == 1)
{
const int kingDistance = distance(square, position->king[pawnColor]);
const Square rectangleSquare =
(pawnColor == position->activeColor ?
square : (Square) (square - pawnDirection));
const bool kingInRectangle =
testSquare(passedPawnRectangle[pawnColor][rectangleSquare],
position->king[oppColor]);
if ((kingInRectangle == FALSE &&
(passedPawnCorridor[pawnColor][square] &
position->piecesOfColor[pawnColor]) == EMPTY_BITBOARD))
{
egDelta += PASSED_PAWN_BONUS_UNSTOPPABLE;
}
else if (kingDistance == 1)
{
const File pawnFile = file(square);
const File kingFile = file(position->king[pawnColor]);
const Square promotionSquare =
(pawnColor == WHITE ? getSquare(pawnFile, RANK_8) :
getSquare(pawnFile, RANK_1));
const bool clearPath = (bool)
(kingFile != pawnFile ||
(kingFile != FILE_A && kingFile != FILE_H));
if (clearPath &&
distance(promotionSquare, position->king[pawnColor]) <= 1)
{
egDelta += PASSED_PAWN_BONUS_UNSTOPPABLE;
}
}
#ifdef BONUS_WINNING_PASSER
if (egDelta < PASSED_PAWN_BONUS_UNSTOPPABLE &&
base->hasPassersOrCandidates[oppColor] == FALSE &&
passerWalks(position, square, pawnColor))
{
egDelta += PASSED_PAWN_BONUS_UNSTOPPABLE;
}
#endif
}
if (position->piece[stopSquare] == NO_PIECE &&
egDelta < PASSED_PAWN_BONUS_UNSTOPPABLE)
{
const Piece newPiece = (pawnRank == RANK_7 ? WHITE_QUEEN : NO_PIECE);
const Move move = getPackedMove(square, stopSquare,
newPiece);
int exValue = seeMove(position, move);
#ifndef NDEBUG
{
Move flippedMove = getPackedMove(getFlippedSquare(square),
getFlippedSquare
(stopSquare), newPiece);
Position flippedPosition = *position;
flipPosition(&flippedPosition);
initializePosition(&flippedPosition);
if (seeMove(&flippedPosition, flippedMove) != exValue)
{
exValue = -100;
}
}
#endif
if (exValue >= 0)
{
egDelta += PASSED_PAWN_BONUS_NOT_BLOCKED;
blocked = FALSE;
}
}
egDelta -=
distance(stopSquare, position->king[pawnColor]) *
PASSED_PAWN_ATTACKERDIST_WEIGHT;
egDelta +=
passedPawnDefenderMalus[pawnColor]
[position->activeColor][square][position->king[oppColor]];
base->endgamePoints[pawnColor] += PASSED_PAWN_BONUS_ENDGAME_MIN;
#ifdef MALUS_PASSED_PAWN_LACK_OF_SUPPORT
if (numberOfNonPawnPieces(position, pawnColor) <=
numberOfNonPawnPieces(position, oppColor) &&
((hasOrthoPieces(position, oppColor) &&
hasOrthoPieces(position, pawnColor) == FALSE) ||
(numberOfNonPawnPieces(position, pawnColor) <
numberOfNonPawnPieces(position, oppColor))))
{
egDelta -= 10;
}
#endif
#ifdef MALUS_BLOCKABLE_PASSERS
if (numberOfNonPawnPieces(position, pawnColor) <=
numberOfNonPawnPieces(position, oppColor) && oppHasBlockingBishop)
{
if (hasSupportingBishop)
{
egDelta -= 5;
}
else
{
egDelta -= 20;
}
}
if (blocked &&
numberOfNonPawnPieces(position, pawnColor) <=
numberOfNonPawnPieces(position, oppColor) &&
getPieceCount(position, (Piece) (BISHOP | pawnColor)) > 0 &&
hasSupportingBishop == FALSE)
{
egDelta -= 10;
}
#endif
#ifdef BONUS_SPECIAL_PASSED_PAWNS
if (pawnRank >= RANK_5)
{
if (testSquare(base->pawnProtectedSquares[pawnColor], square))
{
opDelta += PASSED_PAWN_BONUS_PROTECTED_OPENING;
egDelta += PASSED_PAWN_BONUS_PROTECTED_ENDGAME;
}
ITERATE_BITBOARD(&companions, companionSquare)
{
const Rank rank = colorRank(pawnColor, companionSquare);
opDelta += PASSED_PAWN_BONUS_CONNECTED_OPENING +
quad(0, PASSED_PAWN_BONUS_CONNECTED_OPENING, rank);
egDelta +=
PASSED_PAWN_BONUS_CONNECTED_ENDGAME +
quad(0, PASSED_PAWN_BONUS_CONNECTED_ENDGAME, rank);
}
if ((squaresLeftOf[square] & oppPawns) == EMPTY_BITBOARD ||
(squaresRightOf[square] & oppPawns) == EMPTY_BITBOARD)
{
opDelta += PASSED_PAWN_BONUS_OUTSIDE_OPENING;
egDelta += PASSED_PAWN_BONUS_OUTSIDE_ENDGAME;
}
}
#else
if ((base->passedPawns[pawnColor] & butterflySquares[square]) !=
EMPTY_BITBOARD)
{
const int attackerDist = distance(position->king[pawnColor], square);
const int defenderDist = distance(position->king[oppColor], square);
egDelta += max(0, 5 * (defenderDist - attackerDist));
if (oppHasBlockingBishop)
{
if (hasSupportingBishop)
{
egDelta += 10;
}
else
if (getPieceCount(position, (Piece) (KNIGHT | pawnColor)) > 0)
{
egDelta += 5;
}
}
else
{
egDelta += 20;
}
}
#endif
#ifdef BONUS_PASSER_CLEAR_PATH
{
const Bitboard ownAttacks = base->attackedSquares[pawnColor] |
getKingMoves(position->king[pawnColor]);
const Bitboard oppAttacks = base->attackedSquares[oppColor] |
getKingMoves(position->king[oppColor]);
const Bitboard path = passedPawnCorridor[pawnColor][square];
const Bitboard ownBlockers =
path & position->piecesOfColor[pawnColor];
const Bitboard oppBlockers =
path & position->piecesOfColor[oppColor];
Bitboard obstacles = path & oppAttacks;
const int bonus = (blocked == FALSE ?
PASSED_PAWN_BONUS_ACCOMPANIED :
PASSED_PAWN_BONUS_ACCOMPANIED / 4);
if (testSquare(base->attackedSquares[oppColor], square))
{
const Bitboard candidates =
(position->piecesOfType[ROOK | oppColor] |
position->piecesOfType[QUEEN | oppColor]) &
passedPawnCorridor[oppColor][square] &
getMagicRookMoves(square, position->allPieces);
if (candidates != EMPTY_BITBOARD)
{
obstacles = path;
}
}
if (ownBlockers != EMPTY_BITBOARD)
{
egDelta -= PASSED_PAWN_BONUS_ACCOMPANIED;
}
obstacles |= oppBlockers;
if ((obstacles & ~ownAttacks) == EMPTY_BITBOARD)
{
egDelta += 6 * bonus;
if (obstacles == EMPTY_BITBOARD)
{
const Bitboard uncoveredPathSquares = path & ~ownAttacks;
egDelta += (uncoveredPathSquares == EMPTY_BITBOARD ?
4 * bonus : 2 * bonus);
}
}
}
#endif
if (opDelta > 0)
{
base->openingPoints[pawnColor] += quad(0, opDelta, pawnRank);
}
if (egDelta > 0)
{
base->endgamePoints[pawnColor] += quad(0, egDelta, pawnRank);
}
}
}
INLINE static void evaluatePawns(const Position * position,
EvaluationBase * base)
{
Square square;
Bitboard pieces = (base->weakPawns[WHITE] | base->weakPawns[BLACK]);
const int whiteDoubles = getNumberOfSetSquares(base->doubledPawns[WHITE]);
const int blackDoubles = getNumberOfSetSquares(base->doubledPawns[BLACK]);
base->openingPoints[WHITE] -= whiteDoubles * PAWN_MALUS_DOUBLED_OPENING;
base->endgamePoints[WHITE] -= whiteDoubles * PAWN_MALUS_DOUBLED_ENDGAME;
base->openingPoints[BLACK] -= blackDoubles * PAWN_MALUS_DOUBLED_OPENING;
base->endgamePoints[BLACK] -= blackDoubles * PAWN_MALUS_DOUBLED_ENDGAME;
ITERATE_BITBOARD(&pieces, square)
{
const Color pawnColor = pieceColor(position->piece[square]);
const Color oppColor = opponent(pawnColor);
const bool isolated = (bool)
((companionFiles[square] &
position->piecesOfType[position->piece[square]]) ==
EMPTY_BITBOARD);
const bool onOpenFile = (bool)
(testSquare(base->upwardRealm[oppColor], square) == FALSE &&
testSquare(base->doubledPawns[pawnColor], square) == FALSE);
if (isolated)
{
if (onOpenFile)
{
base->openingPoints[pawnColor] -=
PAWN_MALUS_ISOLATED_ON_OPEN_FILE;
}
else
{
base->openingPoints[pawnColor] -= PAWN_MALUS_ISOLATED_OPENING;
}
base->endgamePoints[pawnColor] -= PAWN_MALUS_ISOLATED_ENDGAME;
if (testSquare(base->fixedPawns[pawnColor], square))
{
base->openingPoints[pawnColor] -=
PAWN_MALUS_ISOLATED_FIXED_OPENING;
base->endgamePoints[pawnColor] -=
PAWN_MALUS_ISOLATED_FIXED_ENDGAME;
}
}
else /* backward */
{
if (onOpenFile)
{
base->openingPoints[pawnColor] -=
PAWN_MALUS_BACKWARD_ON_OPEN_FILE;
}
else
{
base->openingPoints[pawnColor] -= PAWN_MALUS_BACKWARD_OPENING;
}
base->endgamePoints[pawnColor] -= PAWN_MALUS_BACKWARD_ENDGAME;
if (testSquare(base->fixedPawns[pawnColor], square))
{
base->openingPoints[pawnColor] -=
PAWN_MALUS_BACKWARD_FIXED_OPENING;
base->endgamePoints[pawnColor] -=
PAWN_MALUS_BACKWARD_FIXED_ENDGAME;
}
}
}
pieces = (base->candidatePawns[WHITE] | base->candidatePawns[BLACK]);
ITERATE_BITBOARD(&pieces, square)
{
const Color pawnColor = pieceColor(position->piece[square]);
const Bitboard supporters = candidateSupporters[pawnColor][square] &
position->piecesOfType[PAWN | pawnColor];
const Bitboard defenders = candidateDefenders[pawnColor][square] &
position->piecesOfType[PAWN | opponent(pawnColor)];
if (getNumberOfSetSquares(supporters) >=
getNumberOfSetSquares(defenders))
{
const Bitboard ownDefenders =
generalMoves[PAWN | opponent(pawnColor)][square] &
position->piecesOfType[PAWN | pawnColor];
const Bitboard attackers =
generalMoves[PAWN | pawnColor][square] &
position->piecesOfType[PAWN | opponent(pawnColor)];
if (getNumberOfSetSquares(ownDefenders) >=
getNumberOfSetSquares(attackers))
{
const Rank pawnRank = colorRank(pawnColor, square);
base->openingPoints[pawnColor] +=
quad(PAWN_CANDIDATE_OPENING_MIN,
PAWN_CANDIDATE_OPENING_MAX, pawnRank);
base->endgamePoints[pawnColor] +=
quad(PAWN_CANDIDATE_ENDGAME_MIN,
PAWN_CANDIDATE_ENDGAME_MAX, pawnRank);
}
}
}
}
INLINE bool isBlockingSquare(const Position * position,
const EvaluationBase * base, const Square square,
const Color blockingColor)
{
const Square blockedSquare = (Square)
(blockingColor == WHITE ? square + 8 : square - 8);
const Piece blockedPawn = (Piece) (PAWN | opponent(blockingColor));
return (bool) (position->piece[blockedSquare] == blockedPawn &&
squareIsPawnSafe(base, blockingColor, square));
}
INLINE int pawnDefenderDistance(const Square defenderSquare,
const Color defenderColor,
const Square pawnSquare)
{
const int defenderRank = rank(defenderSquare);
const int pawnRank = rank(pawnSquare);
if (defenderColor == WHITE)
{
return (defenderRank <= pawnRank ?
abs(file(defenderSquare) - file(pawnSquare)) :
distance(defenderSquare, pawnSquare));
}
else
{
return (defenderRank >= pawnRank ?
abs(file(defenderSquare) - file(pawnSquare)) :
distance(defenderSquare, pawnSquare));
}
}
#ifdef BONUS_TARGETS
INLINE void evaluateTargets(const Bitboard openingTargets,
const Bitboard endgameTargets,
const Bitboard moves, int *opCount, int *egCount)
{
*opCount +=
STD_BONUS_COUNT * getNumberOfSetSquares(moves & openingTargets);
*egCount +=
STD_BONUS_COUNT * getNumberOfSetSquares(moves & endgameTargets);
}
#endif
INLINE static int getMobilityCount(const EvaluationBase * base,
const Bitboard moves, const Color color)
{
return getNumberOfSetSquares(moves & base->countedSquares[color]) +
getNumberOfSetSquares(moves & base->unprotectedPieces[opponent(color)]);
}
INLINE static void addSliderAttackCount(const Position * position,
EvaluationBase * base,
const Bitboard moves,
const Square attackerSquare,
const Piece attacker,
const Color color)
{
const Color oppColor = opponent(color);
const Square kingSquare = position->king[oppColor];
Bitboard middlePiece = EMPTY_BITBOARD;
if (testSquare(generalMoves[ROOK][kingSquare], attackerSquare) &&
(pieceType(attacker) == ROOK || pieceType(attacker) == QUEEN))
{
middlePiece = generalMoves[ROOK][attackerSquare] &
moves & getMagicRookMoves(kingSquare, position->allPieces);
}
else if (testSquare(generalMoves[BISHOP][kingSquare], attackerSquare) &&
(pieceType(attacker) == BISHOP || pieceType(attacker) == QUEEN))
{
middlePiece = generalMoves[BISHOP][attackerSquare] &
moves & getMagicBishopMoves(kingSquare, position->allPieces);
}
if (middlePiece != EMPTY_BITBOARD)
{
const Square pieceSquare = getNextSquare(&middlePiece);
const Piece middlePieceKind = position->piece[pieceSquare];
const int bonus = sliderAttackPoints[attacker][middlePieceKind];
assert(middlePiece == EMPTY_BITBOARD);
base->openingPoints[color] += bonus;
base->endgamePoints[color] += bonus;
/*
if (base->evaluateKingSafety[oppColor])
{
base->openingPoints[color] += bonus;
}
*/
}
}
#define MOBN 13
#define MEBN 6
INLINE static void evaluateKnight(const Position * position,
EvaluationBase * base, const Square square)
{
const static int mobOpBonus[17] =
{ -(14 + 8), -(8 + 6), -8, -4, 0, 4, 8, (8 + 3), (11 + 2),
MOBN, MOBN, MOBN, MOBN, MOBN, MOBN, MOBN, MOBN
};
const static int mobEgBonus[17] =
{ -(14 + 8), -(8 + 6), -8, -4, 0, 3, (3 + 2), (5 + 1), (6 + 0),
MEBN, MEBN, MEBN, MEBN, MEBN, MEBN, MEBN, MEBN
};
const Piece piece = position->piece[square];
const Color color = pieceColor(piece);
const Color oppColor = opponent(color);
const Bitboard moves = getKnightMoves(square);
const int mobilityCount = getMobilityCount(base, moves, color);
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor];
int opCount = 0, egCount = 0;
base->attackedSquares[color] |= moves;
if (position->piecesOfType[KNIGHT | oppColor] == EMPTY_BITBOARD &&
position->piecesOfType[BISHOP | oppColor] != EMPTY_BITBOARD &&
hasAttackingBishop(position, oppColor, square) == FALSE)
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
if (squareIsPawnSafe(base, color, square))
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
if (testSquare(base->pawnProtectedSquares[color], square))
{
const Bitboard protectors =
generalMoves[PAWN | oppColor][square] &
position->piecesOfType[PAWN | color];
const int numProtectors = getNumberOfSetSquares(protectors);
opCount += numProtectors * 2 * STD_BONUS_COUNT;
egCount += numProtectors * 2 * STD_BONUS_COUNT;
}
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
opCount += count * STD_BONUS_COUNT;
egCount += count * STD_BONUS_COUNT;
}
else if (testSquare(base->weakOutpostSquares[oppColor], square))
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
opCount = min(opCount, NUM_EXPO_FACTORS - 1);
egCount = min(egCount, NUM_EXPO_FACTORS - 1);
base->openingPoints[color] +=
mobOpBonus[mobilityCount] + expoValue[opCount];
base->endgamePoints[color] +=
mobEgBonus[mobilityCount] + expoValue[egCount];
if (base->evaluateKingSafety[oppColor] &&
(moves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD)
{
base->numAttackers[color]++;
base->attackPoints[color] += KNIGHT_BONUS_ATTACK;
}
#ifdef KNIGHT_VS_PASSED_WING_PAWNS
if (base->passedPawns[oppColor] != EMPTY_BITBOARD)
{
const static int malus[8] = { 12, 8, 5, 3, 3, 5, 8, 12 };
Bitboard passers = base->passedPawns[oppColor];
Square pawnSquare;
ITERATE_BITBOARD(&passers, pawnSquare)
{
base->endgamePoints[color] -= malus[file(pawnSquare)] +
pawnDefenderDistance(position->king[color], color, pawnSquare);
}
}
#endif
}
#define MOBB 30
#define MEBB 30
INLINE static void evaluateBishop(const Position * position,
EvaluationBase * base, const Square square)
{
const static int mobOpBonus[18] =
{ -(35 + 10), -(26 + 9), -(18 + 8), -(11 + 7), -(5 + 6), -5, 0,
5, 10, 15, (20 + 4), (24 + 3), (27 + 2), (29 + 1),
MOBB, MOBB, MOBB, MOBB
};
const static int mobEgBonus[18] =
{ -(40 + 11), -(30 + 10), -(21 + 9), -(13 + 8), -(6 + 7), -6, 0,
5, 10, 15, (20 + 4), (24 + 3), (27 + 2), (29 + 1),
MEBB, MEBB, MEBB, MEBB
};
const Piece piece = position->piece[square];
const Color color = pieceColor(piece);
const Color oppColor = opponent(color);
const Bitboard xrayPieces = position->piecesOfType[QUEEN | color];
const Bitboard moves =
getMagicBishopMoves(square, position->allPieces & ~xrayPieces);
const int mobilityCount = getMobilityCount(base, moves, color);
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor];
int opCount = 0, egCount = 0;
#ifdef PINNED_KNIGHT_BONUS
Bitboard pinnedKnights = moves & position->piecesOfType[oppColor | KNIGHT];
#endif
#ifdef BISHOP_BLOCKERS
const Bitboard blockers = squaresAbove[color][square] & moves &
(position->piecesOfType[PAWN | color] |
(position->piecesOfType[PAWN | opponent(color)] &
base->pawnProtectedSquares[opponent(color)]));
#endif
base->attackedSquares[color] |= moves;
if (squareIsPawnSafe(base, color, square))
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
if (testSquare(base->pawnProtectedSquares[color], square))
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
opCount += count * STD_BONUS_COUNT;
egCount += count * STD_BONUS_COUNT;
}
else if (testSquare(base->weakOutpostSquares[oppColor], square))
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
#ifdef PINNED_KNIGHT_BONUS
if (pinnedKnights != EMPTY_BITBOARD)
{
Square knightSquare;
const Bitboard targets = position->piecesOfType[oppColor | QUEEN] |
position->piecesOfType[oppColor | ROOK] |
minValue[position->king[oppColor]];
ITERATE_BITBOARD(&pinnedKnights, knightSquare)
{
if (squareIsPawnSafe(base, color, knightSquare) &&
pieceIsPinnedByBishop(position, knightSquare, square, targets))
{
opCount += 2 * STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
}
}
#endif
#ifdef BONUS_SLIDER_ATTACKS
addSliderAttackCount(position, base, moves, square, piece, color);
#endif
opCount = min(opCount, NUM_EXPO_FACTORS - 1);
egCount = min(egCount, NUM_EXPO_FACTORS - 1);
base->openingPoints[color] +=
mobOpBonus[mobilityCount] + expoValue[opCount];
base->endgamePoints[color] +=
mobEgBonus[mobilityCount] + expoValue[egCount];
if (base->evaluateKingSafety[oppColor] &&
(moves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD)
{
base->numAttackers[color]++;
base->attackPoints[color] += BISHOP_BONUS_ATTACK;
}
#ifdef BISHOP_BLOCKERS
if (blockers != EMPTY_BITBOARD)
{
const int numBlockers = getNumberOfSetSquares(blockers);
assert(numBlockers >= 1 && numBlockers <= 2);
base->openingPoints[color] -= BISHOP_MALUS_BLOCKER[numBlockers];
base->endgamePoints[color] -= BISHOP_MALUS_BLOCKER[numBlockers];
}
#endif
}
INLINE static void evaluateWhiteTrappedBishops(const Position * position,
EvaluationBase * base)
{
if ((position->piece[A7] == WHITE_BISHOP &&
position->piece[B6] == BLACK_PAWN) ||
(position->piece[B8] == WHITE_BISHOP &&
position->piece[C7] == BLACK_PAWN) ||
(position->piece[H7] == WHITE_BISHOP &&
position->piece[G6] == BLACK_PAWN) ||
(position->piece[G8] == WHITE_BISHOP &&
position->piece[F7] == BLACK_PAWN))
{
base->openingPoints[WHITE] -= BISHOP_MALUS_TRAPPED;
base->endgamePoints[WHITE] -= BISHOP_MALUS_TRAPPED;
}
if ((position->piece[A6] == WHITE_BISHOP &&
position->piece[B5] == BLACK_PAWN) ||
(position->piece[H6] == WHITE_BISHOP &&
position->piece[G5] == BLACK_PAWN))
{
base->openingPoints[WHITE] -= BISHOP_MALUS_TRAPPED / 2;
base->endgamePoints[WHITE] -= BISHOP_MALUS_TRAPPED / 2;
}
if ((position->piece[C1] == WHITE_BISHOP &&
position->piece[D2] == WHITE_PAWN &&
position->piece[D3] != NO_PIECE) ||
(position->piece[F1] == WHITE_BISHOP &&
position->piece[E2] == WHITE_PAWN && position->piece[E3] != NO_PIECE))
{
base->openingPoints[WHITE] -= BISHOP_MALUS_BLOCKED;
base->endgamePoints[WHITE] -= BISHOP_MALUS_BLOCKED;
}
}
INLINE static void evaluateBlackTrappedBishops(const Position * position,
EvaluationBase * base)
{
if ((position->piece[A2] == BLACK_BISHOP &&
position->piece[B3] == WHITE_PAWN) ||
(position->piece[B1] == BLACK_BISHOP &&
position->piece[C2] == WHITE_PAWN) ||
(position->piece[H2] == BLACK_BISHOP &&
position->piece[G3] == WHITE_PAWN) ||
(position->piece[G1] == BLACK_BISHOP &&
position->piece[F2] == WHITE_PAWN))
{
base->openingPoints[BLACK] -= BISHOP_MALUS_TRAPPED;
base->endgamePoints[BLACK] -= BISHOP_MALUS_TRAPPED;
}
if ((position->piece[A3] == BLACK_BISHOP &&
position->piece[B4] == WHITE_PAWN) ||
(position->piece[H3] == BLACK_BISHOP &&
position->piece[G4] == WHITE_PAWN))
{
base->openingPoints[BLACK] -= BISHOP_MALUS_TRAPPED / 2;
base->endgamePoints[BLACK] -= BISHOP_MALUS_TRAPPED / 2;
}
if ((position->piece[C8] == BLACK_BISHOP &&
position->piece[D7] == BLACK_PAWN &&
position->piece[D6] != NO_PIECE) ||
(position->piece[F8] == BLACK_BISHOP &&
position->piece[E7] == BLACK_PAWN && position->piece[E6] != NO_PIECE))
{
base->openingPoints[BLACK] -= BISHOP_MALUS_BLOCKED;
base->endgamePoints[BLACK] -= BISHOP_MALUS_BLOCKED;
}
}
INLINE static bool grantSeventhRankBonus(const Position * position,
const Color color,
const Color oppColor,
const Square pieceSquare)
{
if (colorRank(color, pieceSquare) == RANK_7)
{
const static Rank seventhRankByColor[2] = { RANK_7, RANK_2 };
const Bitboard seventhRank = squaresOfRank[seventhRankByColor[color]];
if (((seventhRank & position->piecesOfType[PAWN | oppColor]) ||
(rank(position->king[oppColor]) ==
rank(pieceSquare) + colorSign[color])))
{
return TRUE;
}
}
return FALSE;
}
#define MOBR 12
#define MEBR 22
INLINE static void evaluateRook(const Position * position,
EvaluationBase * base, const Square square)
{
const static int mobOpBonus[19] =
{ -(18 + 6), -(13 + 5), -(9 + 4), -(6 + 3), -6, -4, -2, 0,
2, 4, 6, 8, 9, 10, 11,
MOBR, MOBR, MOBR, MOBR
};
const static int mobEgBonus[19] =
{ -(30 + 8), -(23 + 7), -(17 + 6), -(12 + 5), -12, -8, -4, 0,
4, 8, 12, 16, (16 + 3), (19 + 2), (21 + 1),
MEBR, MEBR, MEBR, MEBR
};
const Piece piece = position->piece[square];
const Color color = pieceColor(piece);
const Color oppColor = opponent(color);
const Bitboard moves = getMagicRookMoves(square, position->allPieces);
const Bitboard xrayPieces = position->piecesOfType[QUEEN | color] |
position->piecesOfType[piece];
const Bitboard xrayMoves =
getMagicRookMoves(square, position->allPieces & ~xrayPieces);
const int mobilityCount = getMobilityCount(base, xrayMoves, color);
const Bitboard fileSquares = squaresOfFile[file(square)];
const Bitboard ownPawns = position->piecesOfType[PAWN | color];
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor];
int opCount = 0, egCount = 0;
base->attackedSquares[color] |= moves;
if (squareIsPawnSafe(base, color, square))
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
opCount += count * STD_BONUS_COUNT;
egCount += count * STD_BONUS_COUNT;
}
else if (testSquare(base->weakOutpostSquares[oppColor], square))
{
opCount += STD_BONUS_COUNT;
egCount += STD_BONUS_COUNT;
}
#ifdef BONUS_SLIDER_ATTACKS
addSliderAttackCount(position, base, moves, square, piece, color);
#endif
opCount = min(opCount, NUM_EXPO_FACTORS - 1);
egCount = min(egCount, NUM_EXPO_FACTORS - 1);
base->openingPoints[color] +=
mobOpBonus[mobilityCount] + expoValue[opCount];
base->endgamePoints[color] +=
mobEgBonus[mobilityCount] + expoValue[egCount];
/* Add a bonus if this rook is located on an open file. */
if ((ownPawns & fileSquares) == EMPTY_BITBOARD)
{
const int fileDiff = abs(file(square) - file(position->king[oppColor]));
if ((position->piecesOfType[PAWN | oppColor] & fileSquares) ==
EMPTY_BITBOARD)
{
base->openingPoints[color] += ROOK_BONUS_ON_OPEN_FILE;
base->endgamePoints[color] += ROOK_BONUS_ON_OPEN_FILE;
}
else
{
base->openingPoints[color] += ROOK_BONUS_ON_SEMIOPEN_FILE;
base->endgamePoints[color] += ROOK_BONUS_ON_SEMIOPEN_FILE;
}
if (fileDiff == 0 && base->evaluateKingSafety[oppColor])
{
base->openingPoints[color] += ROOK_BONUS_KING_FILE;
}
if (fileDiff == 1 && base->evaluateKingSafety[oppColor])
{
base->openingPoints[color] += ROOK_BONUS_LATERAL_KING_FILE;
}
}
if (testSquare(rookTraps[color], square) &&
(moves & centralFiles) == EMPTY_BITBOARD)
{
const Bitboard legalRankMoves = moves &
~position->piecesOfColor[color] & squaresOfRank[rank(square)];
if (getNumberOfSetSquares(legalRankMoves) <= 1)
{
const Bitboard blockers = minValue[position->king[color]] |
position->piecesOfType[PAWN | color];
const int malus =
((blockers & rookBlockers[square]) != EMPTY_BITBOARD ?
ROOK_MALUS_BLOCKED : ROOK_MALUS_SQUEEZED);
base->openingPoints[color] -= malus;
base->endgamePoints[color] -= malus;
}
}
if (grantSeventhRankBonus(position, color, oppColor, square))
{
base->openingPoints[color] += ROOK_BONUS_ON_SEVENTH_RANK_OPENING;
base->endgamePoints[color] += ROOK_BONUS_ON_SEVENTH_RANK_ENDGAME;
}
if (base->evaluateKingSafety[oppColor] &&
(xrayMoves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD)
{
base->numAttackers[color]++;
base->attackPoints[color] += ROOK_BONUS_ATTACK;
}
#ifdef MALUS_ROOK_BLOCKING_PASSER
if (numberOfNonPawnPieces(position, color) == 2 &&
colorRank(color, square) == RANK_8 &&
testSquare(base->passedPawns[color],
(Square) downward(color, square)) &&
(fileSquares & squaresBelow[color][square] &
position->piecesOfType[ROOK | oppColor]) != EMPTY_BITBOARD &&
(companionFiles[square] &
(position->piecesOfType[WHITE_PAWN] |
position->piecesOfType[BLACK_PAWN])) == EMPTY_BITBOARD)
{
base->endgamePoints[color] -= ROOK_MALUS_BLOCKING_PASSER;
}
#endif
#ifdef BONUS_SPACE_ATTACKS
if (testSquare(attackingRealm[color], square))
{
base->spaceAttackPoints[color]++;
}
#endif
#ifdef BONUS_EXCHANGE_UP
if (position->piecesOfType[ROOK | oppColor] == EMPTY_BITBOARD &&
position->piecesOfType[PAWN | color] != EMPTY_BITBOARD)
{
if (base->passedPawns[color] != EMPTY_BITBOARD)
{
base->openingPoints[color] += 25;
base->endgamePoints[color] += 50;
}
else
{
base->openingPoints[color] += 15;
base->endgamePoints[color] += 30;
}
}
#endif
}
#define MOBQ 12
#define MEBQ 12
INLINE static void evaluateQueen(const Position * position,
EvaluationBase * base, const Square square)
{
const static int mobOpBonus[36] = {
-(13 + 5), -(9 + 4), -(6 + 3), -(4 + 2), -(4), -(3), -(2), -(1), 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ,
MOBQ, MOBQ, MOBQ
};
const static int mobEgBonus[36] = {
-(13 + 5), -(9 + 4), -(6 + 3), -(4 + 2), -(4), -(3), -(2), -(1), 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ,
MEBQ, MEBQ, MEBQ
};
const Piece piece = position->piece[square];
const Color color = pieceColor(piece);
const Color oppColor = opponent(color);
const int proximityCount = 14 -
taxiDistance(square, position->king[oppColor]);
const Bitboard moves = getMagicQueenMoves(square, position->allPieces);
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor];
const int mobilityCount = getMobilityCount(base, moves, color);
int opCount = 0, egCount = 0;
base->attackedSquares[color] |= moves;
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
opCount += count * STD_BONUS_COUNT;
}
opCount = min(opCount, NUM_EXPO_FACTORS - 1);
egCount = min(egCount, NUM_EXPO_FACTORS - 1);
base->openingPoints[color] +=
proximityCount + mobOpBonus[mobilityCount] + expoValue[opCount];
base->endgamePoints[color] +=
proximityCount + mobEgBonus[mobilityCount] + expoValue[egCount];
if (grantSeventhRankBonus(position, color, oppColor, square))
{
base->openingPoints[color] += QUEEN_BONUS_ON_SEVENTH_RANK_OPENING;
base->endgamePoints[color] += QUEEN_BONUS_ON_SEVENTH_RANK_ENDGAME;
}
if (base->evaluateKingSafety[oppColor] &&
(moves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD)
{
base->numAttackers[color]++;
base->attackPoints[color] += QUEEN_BONUS_ATTACK;
}
#ifdef BONUS_SPACE_ATTACKS
if (testSquare(attackingRealm[color], square))
{
base->spaceAttackPoints[color] += 3;
}
#endif
#ifdef BONUS_SLIDER_ATTACKS
addSliderAttackCount(position, base, moves, square, piece, color);
#endif
}
INLINE static int getSafetyMalusOfKingFile(const Position * position,
const int file,
const Square kingSquare,
const Color color)
{
const Square startSquare = getSquare(file, rank(kingSquare));
const Square promotionSquare = (color == WHITE ?
getSquare(file, RANK_8) :
getSquare(file, RANK_1));
Bitboard candidates = (squaresBetween[startSquare][promotionSquare] |
(minValue[startSquare])) &
position->piecesOfType[PAWN | color];
int promotionDistance = 0, pawnSquare;
ITERATE_BITBOARD(&candidates, pawnSquare)
{
if (distance(pawnSquare, promotionSquare) > promotionDistance)
{
promotionDistance = distance(pawnSquare, promotionSquare);
}
}
assert(promotionDistance >= 0 && promotionDistance <= 6);
return 36 - promotionDistance * promotionDistance;
}
INLINE static int getPawnAttackMalusOfKingFile(const Position * position,
const int file,
const Color color)
{
const Color oppColor = opponent(color);
const Square promotionSquare = (color == WHITE ?
getSquare(file, RANK_1) :
getSquare(file, RANK_8));
Bitboard candidates = squaresOfFile[file] &
position->piecesOfType[PAWN | oppColor];
int promotionDistance = 7, pawnSquare;
ITERATE_BITBOARD(&candidates, pawnSquare)
{
if (distance(pawnSquare, promotionSquare) < promotionDistance)
{
promotionDistance = distance(pawnSquare, promotionSquare);
}
}
assert(promotionDistance >= 1 && promotionDistance <= 7);
return KING_MALUS_PAWN_ATTACK[promotionDistance];
}
INLINE static int getExpositionValue(const Position * position,
const Square kingSquare,
const Color color)
{
const Bitboard obstacles = position->piecesOfType[PAWN | color];
const Bitboard diaExposition =
getMagicBishopMoves(kingSquare, obstacles) & ~obstacles;
const int diaExpositionValue =
6 - min(6, getNumberOfSetSquares(diaExposition));
return 36 - diaExpositionValue * diaExpositionValue;
}
INLINE static int getSafetyMalusOfKingSquare(const Position * position,
const Square kingSquare,
const Color color)
{
const int kingFile = file(kingSquare);
int malus = getExpositionValue(position, kingSquare, color) +
getSafetyMalusOfKingFile(position, kingFile, kingSquare, color);
if (kingFile > FILE_A)
{
malus += getSafetyMalusOfKingFile(position, kingFile - 1, kingSquare,
color);
}
if (kingFile < FILE_H)
{
malus += getSafetyMalusOfKingFile(position, kingFile + 1, kingSquare,
color);
}
if (malus == 0)
{
malus = 11; /* malus for weak back rank */
}
malus += getPawnAttackMalusOfKingFile(position, kingFile, color);
if (kingFile > FILE_A)
{
malus += getPawnAttackMalusOfKingFile(position, kingFile - 1, color);
}
if (kingFile < FILE_H)
{
malus += getPawnAttackMalusOfKingFile(position, kingFile + 1, color);
}
return malus;
}
static int getPawnShelterMalus(const Position * position, const Color color,
KingSafetyHashInfo * kingSafetyHashtable)
{
const Bitboard hashValue = getKingPawnSafetyHashValue(position, color);
KingSafetyHashInfo *kingSafetyHashInfo =
&kingSafetyHashtable[hashValue & KINGSAFETY_HASHTABLE_MASK];
if (kingSafetyHashInfo->hashValue == hashValue &&
kingSafetyHashInfo->hashValue != 0)
{
return kingSafetyHashInfo->safetyMalus;
}
else
{
const static int rankByColor[2] = { RANK_1, RANK_8 };
int cr00, cr000;
const Square kingSquare = position->king[color];
int pawnShelterMalus = 0, castlingShelterMalus = 0;
if (color == WHITE)
{
cr00 = WHITE_00, cr000 = WHITE_000;
}
else
{
cr00 = BLACK_00, cr000 = BLACK_000;
}
pawnShelterMalus = castlingShelterMalus =
getSafetyMalusOfKingSquare(position, kingSquare, color);
if (position->castlingRights & cr00)
{
const Square kingSquare = getSquare(FILE_G, rankByColor[color]);
const int malus00 =
getSafetyMalusOfKingSquare(position, kingSquare, color);
castlingShelterMalus = min(malus00, castlingShelterMalus);
}
if (position->castlingRights & cr000)
{
const Square kingSquare = getSquare(FILE_B, rankByColor[color]);
const int malus000 =
getSafetyMalusOfKingSquare(position, kingSquare, color);
castlingShelterMalus = min(malus000, castlingShelterMalus);
}
pawnShelterMalus = (pawnShelterMalus + castlingShelterMalus) / 2;
kingSafetyHashInfo->hashValue = hashValue;
kingSafetyHashInfo->safetyMalus = pawnShelterMalus;
return pawnShelterMalus;
}
}
static int getKingSafetyMalus(const Position * position,
EvaluationBase * base, const Color color)
{
const Color oppColor = opponent(color);
const Square kingSquare = position->king[color];
const Bitboard protectingPawn = (color == WHITE ?
minValue[kingSquare] << 8 :
minValue[kingSquare] >> 8);
const Bitboard pawnAttackers =
position->piecesOfType[PAWN | oppColor] & kingAttacks[kingSquare].
pawnAttackers[oppColor] & ~protectingPawn;
int pawnShelterMalus = 0, attackMalus = 0;
#ifdef MALUS_UNDEFENDED_KINGATTACKS
const Bitboard oppAttacks = base->attackedSquares[oppColor] |
getKingMoves(position->king[oppColor]);
const Bitboard attackedSquares =
base->kingAttackSquares[color] & oppAttacks;
const Bitboard undefendedSquares =
attackedSquares & ~base->attackedSquares[color];
const int squareMalus =
getNumberOfSetSquares(attackedSquares) +
3 * getNumberOfSetSquares(undefendedSquares);
#endif
#ifdef MALUS_QUEEN_DEFENDER_DISTANCE
int queenMalus;
const int queenDistance =
getMinimalTaxiDistance(position, kingSquare, (Piece) (QUEEN | color));
#endif
#ifdef MALUS_UNDEFENDED_KINGATTACKS
/*
if (numUndefendedSquares)
{
dumpSquare(kingSquare);
dumpBitboard(undefendedSquares, "undefended");
dumpPosition(position);
}
*/
base->attackPoints[oppColor] += 2 * squareMalus;
#endif
base->numAttackers[oppColor] += getNumberOfSetSquares(pawnAttackers);
attackMalus = (base->attackPoints[oppColor] *
KING_ATTACK_WEIGHT[base->numAttackers[oppColor]]) / 256;
#ifdef MALUS_QUEEN_DEFENDER_DISTANCE
queenMalus =
(KING_ATTACK_WEIGHT[min(16, 1 + base->numAttackers[oppColor])] *
queenDistance * 8) / 256;
#endif
pawnShelterMalus =
getPawnShelterMalus(position, color, base->kingsafetyHashtable);
#ifdef MALUS_QUEEN_DEFENDER_DISTANCE
return attackMalus + pawnShelterMalus + queenMalus;
#else
return attackMalus + pawnShelterMalus;
#endif
}
INLINE static bool kingSafetyEvalRequired(const Position * position,
const Color color)
{
const Color oppColor = opponent(color);
return (bool) (numberOfNonPawnPieces(position, oppColor) >= 3 &&
position->piecesOfType[QUEEN | oppColor] != EMPTY_BITBOARD);
}
INLINE static int getPawnAttackDistance(const Position * position,
const EvaluationBase * base,
const Color color)
{
const Color oppColor = opponent(color);
const Bitboard forbiddenSquares =
position->piecesOfType[PAWN | color] |
base->pawnProtectedSquares[oppColor];
return getFloodValue(position->king[color],
position->piecesOfType[PAWN | oppColor],
~forbiddenSquares);
}
INLINE static bool kingIsOffside(const Position * position,
const EvaluationBase * base,
const Color color, int *distanceDiff)
{
if (base->passedPawns[color] != EMPTY_BITBOARD ||
position->piecesOfType[PAWN | color] == EMPTY_BITBOARD)
{
return FALSE;
}
else
{
const Color oppColor = opponent(color);
const Bitboard realm = kingRealm[oppColor]
[position->king[oppColor]][position->king[color]];
const Bitboard ownPawns = position->piecesOfType[PAWN | color];
if ((realm & ownPawns) == ownPawns)
{
const int attackerDistance =
getPawnAttackDistance(position, base, oppColor);
const int defenderDistance =
getPawnAttackDistance(position, base, color);
*distanceDiff = (position->activeColor == color ?
(defenderDistance - 1) - attackerDistance :
defenderDistance - (attackerDistance - 1));
return (bool) (*distanceDiff > 1);
}
}
return FALSE;
}
INLINE static bool kingIsTrapped(const Position * position,
const Color kingColor)
{
const Square kingSquare = position->king[kingColor];
const Rank kingRank = colorRank(kingColor, kingSquare);
const File kingFile = file(kingSquare);
if (kingRank == RANK_1 && (kingFile == FILE_A || kingFile == FILE_H))
{
const int upward = (kingColor == WHITE ? 8 : -8);
const Color oppColor = opponent(kingColor);
const Piece blockingPiece =
position->piece[kingSquare + upward + upward];
if (position->piece[kingSquare + upward] == (PAWN | kingColor) &&
(blockingPiece == (PAWN | oppColor) ||
blockingPiece == (BISHOP | oppColor)))
{
return TRUE;
}
}
return FALSE;
}
INLINE static void initializeEvaluationBase(EvaluationBase * base,
KingSafetyHashInfo *
kingsafetyHashtable)
{
base->openingPoints[WHITE] = base->openingPoints[BLACK] = 0;
base->endgamePoints[WHITE] = base->endgamePoints[BLACK] = 0;
base->kingsafetyHashtable = kingsafetyHashtable;
}
INLINE static void evaluatePieces(const Position * position,
EvaluationBase * base)
{
const Bitboard exclude = position->piecesOfType[WHITE_PAWN] |
position->piecesOfType[BLACK_PAWN] |
minValue[position->king[WHITE]] | minValue[position->king[BLACK]];
Bitboard pieces = position->allPieces & (~exclude);
Square square;
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nStart of piece evaluation\n");
}
#endif
ITERATE_BITBOARD(&pieces, square)
{
const PieceType pieceType = pieceType(position->piece[square]);
#ifndef NDEBUG
if (debugEval)
{
dumpSquare(square);
logDebug("opW=%d egW=%d\n", base->openingPoints[WHITE],
base->endgamePoints[WHITE]);
logDebug("opB=%d egB=%d\n", base->openingPoints[BLACK],
base->endgamePoints[BLACK]);
}
#endif
switch (pieceType)
{
case QUEEN:
evaluateQueen(position, base, square);
break;
case ROOK:
evaluateRook(position, base, square);
break;
case BISHOP:
evaluateBishop(position, base, square);
break;
case KNIGHT:
evaluateKnight(position, base, square);
break;
}
#ifndef NDEBUG
if (debugEval)
{
logDebug("opW=%d egW=%d\n", base->openingPoints[WHITE],
base->endgamePoints[WHITE]);
logDebug("opB=%d egB=%d\n\n", base->openingPoints[BLACK],
base->endgamePoints[BLACK]);
}
#endif
}
if (position->piecesOfType[WHITE_BISHOP] != EMPTY_BITBOARD)
{
evaluateWhiteTrappedBishops(position, base);
}
if (position->piecesOfType[BLACK_BISHOP] != EMPTY_BITBOARD)
{
evaluateBlackTrappedBishops(position, base);
}
#ifndef NDEBUG
if (debugEval)
{
logDebug("Values after piece evaluation\n");
logDebug("opW=%d egW=%d\n", base->openingPoints[WHITE],
base->endgamePoints[WHITE]);
logDebug("opB=%d egB=%d\n", base->openingPoints[BLACK],
base->endgamePoints[BLACK]);
logDebug("End of piece evaluation\n");
}
#endif
}
INLINE Bitboard getFixedPawns(const Position * position,
const EvaluationBase * base, const Color color)
{
const Color oppColor = opponent(color);
const Bitboard candidates = position->piecesOfType[PAWN | color] &
~base->pawnProtectedSquares[color];
const Bitboard blockers = position->piecesOfType[PAWN | color] |
position->piecesOfColor[oppColor] |
base->pawnProtectedSquares[oppColor];
return candidates & (color == WHITE ? blockers >> 8 : blockers << 8);
}
INLINE bool evaluateKingChase(const Position * position,
const Color kingColor)
{
if (position->numberOfPawns[WHITE] == 0 &&
position->numberOfPawns[BLACK] == 0 &&
numberOfNonPawnPieces(position, kingColor) <= 2)
{
return (bool) (getPieceWeight(position, kingColor) <
getPieceWeight(position, opponent(kingColor)));
}
return FALSE;
}
INLINE int getKingChaseMalus(const Position * position,
const Color huntedKingColor)
{
const Color attackingColor = opponent(huntedKingColor);
const Square huntedKingSquare = position->king[huntedKingColor];
const Square attackingKingSquare = position->king[attackingColor];
const int mutualDistance =
distance(huntedKingSquare, attackingKingSquare) - 2;
int cornerDistanceMalus = kingChaseMalus[ALL][huntedKingSquare];
if (hasOrthoPieces(position, attackingColor) == FALSE &&
getPieceCount(position, (Piece) (BISHOP | attackingColor)) >= 0)
{
const Bitboard attackingBishops =
position->piecesOfType[BISHOP | attackingColor];
if ((lightSquares & attackingBishops) == EMPTY_BITBOARD)
{
cornerDistanceMalus = kingChaseMalus[DARK][huntedKingSquare];
}
if ((darkSquares & attackingBishops) == EMPTY_BITBOARD)
{
cornerDistanceMalus = kingChaseMalus[LIGHT][huntedKingSquare];
}
}
return 5 * (5 - mutualDistance) + 15 * cornerDistanceMalus;
}
#ifdef HOMELAND_SECURITY_BONUS
int getHomelandSecurityCount(Position * position, EvaluationBase * base,
const Color color)
{
const Color oppColor = opponent(color);
const Bitboard ownPawns = position->piecesOfType[PAWN | color];
const Bitboard exclude = ownPawns |
base->pawnProtectedSquares[oppColor] |
(base->attackedSquares[oppColor] & ~base->attackedSquares[color]);
const Bitboard safeSquares = homeland[color] & ~exclude;
const Bitboard superSafeSquares =
safeSquares & (color == WHITE ? (ownPawns >> 8) | (ownPawns >> 16) :
(ownPawns << 8) | (ownPawns << 16));
return getNumberOfSetSquares(safeSquares) +
getNumberOfSetSquares(superSafeSquares);
}
#endif
INLINE static int getPositionalValue(Position * position,
EvaluationBase * base)
{
int value, openingValue, endgameValue;
const int pi = position->phaseIndex;
#ifdef BONUS_TARGETS
Bitboard defaultTargets;
#endif
assert(pi >= 0 && pi <= 256);
base->openingPoints[WHITE] = base->openingPoints[BLACK] =
base->endgamePoints[WHITE] = base->endgamePoints[BLACK] = 0;
base->countedSquares[WHITE] = ~((position->piecesOfColor[WHITE] |
base->pawnProtectedSquares[BLACK]) &
~getOrdinaryPieces(position, BLACK));
base->unprotectedPieces[WHITE] = position->piecesOfColor[WHITE] &
~base->pawnProtectedSquares[WHITE];
base->countedSquares[BLACK] = ~((position->piecesOfColor[BLACK] |
base->pawnProtectedSquares[WHITE]) &
~getOrdinaryPieces(position, WHITE));
base->unprotectedPieces[BLACK] = position->piecesOfColor[BLACK] &
~base->pawnProtectedSquares[BLACK];
base->numAttackers[WHITE] = base->numAttackers[BLACK] = 0;
base->attackPoints[WHITE] = base->attackPoints[BLACK] = 0;
base->spaceAttackPoints[WHITE] = base->spaceAttackPoints[BLACK] = 0;
base->attackedSquares[WHITE] = base->pawnProtectedSquares[WHITE];
base->attackedSquares[BLACK] = base->pawnProtectedSquares[BLACK];
#ifdef BONUS_TARGETS
defaultTargets = (base->passedPawns[WHITE] << 8) |
getFixedPawns(position, base, BLACK);
base->openingTargets[WHITE] = base->endgameTargets[WHITE] =
base->countedSquares[WHITE] & defaultTargets;
defaultTargets = (base->passedPawns[BLACK] >> 8) |
getFixedPawns(position, base, WHITE);
base->openingTargets[BLACK] = base->endgameTargets[BLACK] =
base->countedSquares[BLACK] & defaultTargets;
#endif
if ((base->evaluateKingSafety[WHITE] =
kingSafetyEvalRequired(position, WHITE)) != FALSE)
{
const Bitboard corona = getKingMoves(position->king[WHITE]);
base->kingAttackSquares[WHITE] = corona /*| (corona << 8) */ ;
base->kingAttacks[WHITE] = &kingAttacks[position->king[WHITE]];
#ifdef BONUS_TARGETS
base->openingTargets[WHITE] |= base->countedSquares[WHITE] &
squaresInDistance[2][position->king[BLACK]];
#endif
}
if ((base->evaluateKingSafety[BLACK] =
kingSafetyEvalRequired(position, BLACK)) != FALSE)
{
const Bitboard corona = getKingMoves(position->king[BLACK]);
base->kingAttackSquares[BLACK] = corona /*| (corona >> 8) */ ;
base->kingAttacks[BLACK] = &kingAttacks[position->king[BLACK]];
#ifdef BONUS_TARGETS
base->openingTargets[BLACK] |= base->countedSquares[BLACK] &
squaresInDistance[2][position->king[WHITE]];
#endif
}
evaluatePieces(position, base);
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nEval values before passed pawn eval:\n");
logDebug("opW=%d egW=%d\n", base->openingPoints[WHITE],
base->endgamePoints[WHITE]);
logDebug("opB=%d egB=%d\n", base->openingPoints[BLACK],
base->endgamePoints[BLACK]);
}
#endif
if (base->passedPawns[WHITE] != EMPTY_BITBOARD ||
base->passedPawns[BLACK] != EMPTY_BITBOARD)
{
#ifndef NDEBUG
if (debugEval)
{
dumpBitboard(base->passedPawns[WHITE], "white passers");
dumpBitboard(base->passedPawns[BLACK], "black passers");
}
#endif
evaluatePassedPawns(position, base);
}
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nEval values before king safety eval:\n");
logDebug("opW=%d egW=%d\n", base->openingPoints[WHITE],
base->endgamePoints[WHITE]);
logDebug("opB=%d egB=%d\n", base->openingPoints[BLACK],
base->endgamePoints[BLACK]);
}
#endif
if (base->evaluateKingSafety[WHITE])
{
base->openingPoints[WHITE] -= getKingSafetyMalus(position, base, WHITE);
}
if (base->evaluateKingSafety[BLACK])
{
base->openingPoints[BLACK] -= getKingSafetyMalus(position, base, BLACK);
}
if (evaluateKingChase(position, WHITE))
{
const int kingChaseMalus = getKingChaseMalus(position, WHITE);
base->openingPoints[WHITE] -= kingChaseMalus;
base->endgamePoints[WHITE] -= kingChaseMalus;
}
else if (evaluateKingChase(position, BLACK))
{
const int kingChaseMalus = getKingChaseMalus(position, BLACK);
base->openingPoints[BLACK] -= kingChaseMalus;
base->endgamePoints[BLACK] -= kingChaseMalus;
}
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nEval values before space attack eval:\n");
logDebug("opW=%d egW=%d\n", base->openingPoints[WHITE],
base->endgamePoints[WHITE]);
logDebug("opB=%d egB=%d\n", base->openingPoints[BLACK],
base->endgamePoints[BLACK]);
}
#endif
#ifdef BONUS_SPACE_ATTACKS
{
const Bitboard whiteAttackers = position->piecesOfColor[WHITE] &
attackingRealm[WHITE];
const Bitboard blackAttackers = position->piecesOfColor[BLACK] &
attackingRealm[BLACK];
const int numWhiteAttackers = getNumberOfSetSquares(whiteAttackers);
const int numBlackAttackers = getNumberOfSetSquares(blackAttackers);
base->openingPoints[WHITE] += SPACE_BONUS_WEIGHT[numWhiteAttackers] *
(base->spaceAttackPoints[WHITE] + numWhiteAttackers);
base->openingPoints[BLACK] += SPACE_BONUS_WEIGHT[numBlackAttackers] *
(base->spaceAttackPoints[BLACK] + numBlackAttackers);
}
#endif
#ifdef HOMELAND_SECURITY_BONUS
{
Color color;
for (color = WHITE; color <= BLACK; color++)
{
const Square kingSquare = position->king[color];
const Bitboard defended = base->attackedSquares[color] |
getKingMoves(kingSquare);
const Bitboard exclude = minValue[kingSquare] |
position->piecesOfType[QUEEN | color] |
position->piecesOfType[ROOK | color];
const Bitboard protectWorthy = position->piecesOfColor[color] &
~(exclude);
const Bitboard unprotected = protectWorthy & ~defended;
const Bitboard threatened = position->piecesOfColor[color] &
~defended & base->attackedSquares[opponent(color)];
const int malus = 3 * getNumberOfSetSquares(unprotected) +
6 * getNumberOfSetSquares(threatened);
base->openingPoints[color] -= malus;
base->endgamePoints[color] -= malus;
}
}
#endif
openingValue = base->openingPoints[WHITE] - base->openingPoints[BLACK];
endgameValue = base->endgamePoints[WHITE] - base->endgamePoints[BLACK];
value = (openingValue * (256 - pi) + endgameValue * pi) / 256;
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nFinal eval values:\n");
logDebug("opW=%d egW=%d\n", base->openingPoints[WHITE],
base->endgamePoints[WHITE]);
logDebug("opB=%d egB=%d\n", base->openingPoints[BLACK],
base->endgamePoints[BLACK]);
}
#endif
return value;
}
int getValue(Position * position, const int alpha, const int beta,
PawnHashInfo * pawnHashtable,
KingSafetyHashInfo * kingsafetyHashtable)
{
EvaluationBase base;
int value, lazyValue;
PawnHashInfo *pawnHashInfo =
&pawnHashtable[position->pawnHashValue & PAWN_HASHTABLE_MASK];
initializeEvaluationBase(&base, kingsafetyHashtable);
if (pawnHashInfo->hashValue == position->pawnHashValue &&
pawnHashInfo->hashValue != 0)
{
#ifndef NDEBUG
getPawnInfo(position, &base);
evaluatePawns(position, &base);
assert(base.openingPoints[WHITE] == pawnHashInfo->openingPoints[WHITE]);
assert(base.openingPoints[BLACK] == pawnHashInfo->openingPoints[BLACK]);
assert(base.endgamePoints[WHITE] == pawnHashInfo->endgamePoints[WHITE]);
assert(base.endgamePoints[BLACK] == pawnHashInfo->endgamePoints[BLACK]);
assert(base.pawnProtectedSquares[WHITE] ==
pawnHashInfo->pawnProtectedSquares[WHITE]);
assert(base.pawnProtectedSquares[BLACK] ==
pawnHashInfo->pawnProtectedSquares[BLACK]);
assert(base.passedPawns[WHITE] == pawnHashInfo->passedPawns[WHITE]);
assert(base.passedPawns[BLACK] == pawnHashInfo->passedPawns[BLACK]);
#endif
base.openingPoints[WHITE] = pawnHashInfo->openingPoints[WHITE];
base.openingPoints[BLACK] = pawnHashInfo->openingPoints[BLACK];
base.endgamePoints[WHITE] = pawnHashInfo->endgamePoints[WHITE];
base.endgamePoints[BLACK] = pawnHashInfo->endgamePoints[BLACK];
}
else
{
getPawnInfo(position, &base);
evaluatePawns(position, &base);
pawnHashInfo->hashValue = position->pawnHashValue;
pawnHashInfo->openingPoints[WHITE] = base.openingPoints[WHITE];
pawnHashInfo->openingPoints[BLACK] = base.openingPoints[BLACK];
pawnHashInfo->endgamePoints[WHITE] = base.endgamePoints[WHITE];
pawnHashInfo->endgamePoints[BLACK] = base.endgamePoints[BLACK];
pawnHashInfo->pawnProtectedSquares[WHITE] =
base.pawnProtectedSquares[WHITE];
pawnHashInfo->pawnProtectedSquares[BLACK] =
base.pawnProtectedSquares[BLACK];
pawnHashInfo->passedPawns[WHITE] = base.passedPawns[WHITE];
pawnHashInfo->passedPawns[BLACK] = base.passedPawns[BLACK];
pawnHashInfo->weakOutpostSquares[WHITE] =
base.weakOutpostSquares[WHITE];
pawnHashInfo->weakOutpostSquares[BLACK] =
base.weakOutpostSquares[BLACK];
pawnHashInfo->pawnAttackableSquares[WHITE] =
base.pawnAttackableSquares[WHITE];
pawnHashInfo->pawnAttackableSquares[BLACK] =
base.pawnAttackableSquares[BLACK];
#ifdef BONUS_HIDDEN_PASSER
pawnHashInfo->hasPassersOrCandidates[WHITE] =
base.hasPassersOrCandidates[WHITE];
pawnHashInfo->hasPassersOrCandidates[BLACK] =
base.hasPassersOrCandidates[BLACK];
#endif
}
value = positionalBalance(position, &base);
lazyValue = getChanceValue(position, value);
#ifdef TRACE_EVAL
logDebug("\nStarting evaluation.\n");
logDebug("phaseIndex = %d\n", phaseIndex(position));
logDebug("opvWhite = %d egvWhite = %d\n",
position->openingValue[WHITE], position->endgameValue[WHITE]);
logDebug("opvBlack = %d egvBlack = %d\n",
position->openingValue[BLACK], position->endgameValue[BLACK]);
logDebug("basicValue = %d\n\n", basicValue);
logPosition(position);
logDebug("\n");
#endif
if (numberOfNonPawnPieces(position, WHITE) <= 3 ||
numberOfNonPawnPieces(position, BLACK) <= 3 ||
(lazyValue >= alpha - (maxDelta + 20) &&
lazyValue <= beta + (maxDelta + 20)))
{
#ifdef ADAPTIVE_DELTA
int absValue;
#endif
int positionalValue;
if (pawnHashInfo->hashValue == position->pawnHashValue &&
pawnHashInfo->hashValue != 0)
{
base.pawnProtectedSquares[WHITE] =
pawnHashInfo->pawnProtectedSquares[WHITE];
base.pawnProtectedSquares[BLACK] =
pawnHashInfo->pawnProtectedSquares[BLACK];
base.passedPawns[WHITE] = pawnHashInfo->passedPawns[WHITE];
base.passedPawns[BLACK] = pawnHashInfo->passedPawns[BLACK];
base.weakOutpostSquares[WHITE] =
pawnHashInfo->weakOutpostSquares[WHITE];
base.weakOutpostSquares[BLACK] =
pawnHashInfo->weakOutpostSquares[BLACK];
base.pawnAttackableSquares[WHITE] =
pawnHashInfo->pawnAttackableSquares[WHITE];
base.pawnAttackableSquares[BLACK] =
pawnHashInfo->pawnAttackableSquares[BLACK];
#ifdef BONUS_HIDDEN_PASSER
base.hasPassersOrCandidates[WHITE] =
pawnHashInfo->hasPassersOrCandidates[WHITE];
base.hasPassersOrCandidates[BLACK] =
pawnHashInfo->hasPassersOrCandidates[BLACK];
#endif
}
if (kpkpValueAvailable(position))
{
value = getKpkpValue(position);
if (value == 0)
{
return 0;
}
positionalValue = getPositionalValue(position, &base);
}
else
{
positionalValue = getPositionalValue(position, &base);
}
#ifdef ADAPTIVE_DELTA
absValue = abs(positionalValue);
/* rise fast, sink slowly */
if (absValue > maxDelta)
{
maxDelta = max(180, (3 * absValue + maxDelta) / 4);
}
else
{
maxDelta = max(180, (absValue + 3 * maxDelta) / 4);
}
#endif
value += (position->activeColor == WHITE ?
positionalValue : -positionalValue);
}
return getChanceValue(position, value);
}
static void transposeMatrix(const int human[], int machine[])
{
int file, rank, i = 0;
for (rank = RANK_8; rank >= RANK_1; rank--)
{
for (file = FILE_A; file <= FILE_H; file++)
{
const Square machineSquare = getSquare(file, rank);
machine[machineSquare] = human[i++];
}
}
}
#define PSV(piece,square,stage) pieceSquareValue[(piece)][(square)][(stage)]
static void initializePieceSquareValues()
{
const int PawnFileOpening = 5;
const int KnightCentreOpening = 5;
const int KnightCentreEndgame = 5;
const int KnightRankOpening = 5;
const int KnightBackRankOpening = 0;
const int KnightTrapped = 100;
const int BishopCentreOpening = 2;
const int BishopCentreEndgame = 3;
const int BishopBackRankOpening = 10;
const int BishopDiagonalOpening = 4;
const int RookFileOpening = 3;
const int QueenCentreOpening = 1;
const int QueenCentreEndgame = 4;
const int QueenBackRankOpening = 5;
const int KingCentreEndgame = 12;
const int KingFileOpening = 10;
const int KingRankOpening = 10;
const int PawnFile[8] = { -3, -1, +0, +1, +1, +0, -1, -3, };
const int KnightLine[8] = { -4, -2, +0, +1, +1, +0, -2, -4, };
const int KnightRank[8] = { -2, -1, +0, +1, +2, +3, +2, +1, };
const int BishopLine[8] = { -3, -1, +0, +1, +1, +0, -1, -3, };
const int RookFile[8] = { -2, -1, +0, +1, +1, +0, -1, -2, };
const int QueenFileOpening[8] = { -2, -1, +0, +0, +0, +0, -1, -2, };
const int QueenRankOpening[8] = { -1, +0, +0, +0, +0, +0, +0, -1, };
const int QueenFileEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, };
const int QueenRankEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, };
const int KingFileEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, };
const int KingRankEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, };
const int KingFile[8] = { +3, +4, +2, +0, +0, +2, +4, +3, };
const int KingRank[8] = { +1, +0, -2, -3, -4, -5, -6, -7, };
int i;
Square sq;
for (i = 0; i < 16; i++)
{
int j;
for (j = 0; j < _64_; j++)
{
pieceSquareValue[i][j][0] = pieceSquareValue[i][j][1] = 0;
}
}
/* pawns */
ITERATE(sq)
{
PSV(WHITE_PAWN, sq, OPENING) += PawnFile[file(sq)] * PawnFileOpening;
PSV(WHITE_PAWN, sq, OPENING) += PAWN_VALUE_OPENING;
PSV(WHITE_PAWN, sq, ENDGAME) += PAWN_VALUE_ENDGAME;
}
PSV(WHITE_PAWN, D3, OPENING) += 10;
PSV(WHITE_PAWN, E3, OPENING) += 10;
PSV(WHITE_PAWN, D4, OPENING) += 20;
PSV(WHITE_PAWN, E4, OPENING) += 20;
PSV(WHITE_PAWN, D5, OPENING) += 10;
PSV(WHITE_PAWN, E5, OPENING) += 10;
/* knights */
ITERATE(sq)
{
PSV(WHITE_KNIGHT, sq, OPENING) += VALUE_KNIGHT_OPENING;
PSV(WHITE_KNIGHT, sq, ENDGAME) += VALUE_KNIGHT_ENDGAME;
PSV(WHITE_KNIGHT, sq, OPENING) +=
KnightLine[file(sq)] * KnightCentreOpening;
PSV(WHITE_KNIGHT, sq, OPENING) +=
KnightLine[rank(sq)] * KnightCentreOpening;
PSV(WHITE_KNIGHT, sq, ENDGAME) +=
KnightLine[file(sq)] * KnightCentreEndgame;
PSV(WHITE_KNIGHT, sq, ENDGAME) +=
KnightLine[rank(sq)] * KnightCentreEndgame;
PSV(WHITE_KNIGHT, sq, OPENING) +=
KnightRank[rank(sq)] * KnightRankOpening;
}
for (sq = A1; sq <= H1; sq++)
{
PSV(WHITE_KNIGHT, sq, OPENING) -= KnightBackRankOpening;
}
PSV(WHITE_KNIGHT, A8, OPENING) -= KnightTrapped;
PSV(WHITE_KNIGHT, H8, OPENING) -= KnightTrapped;
/* bishops */
ITERATE(sq)
{
PSV(WHITE_BISHOP, sq, OPENING) += VALUE_BISHOP_OPENING;
PSV(WHITE_BISHOP, sq, ENDGAME) += VALUE_BISHOP_ENDGAME;
PSV(WHITE_BISHOP, sq, OPENING) +=
BishopLine[file(sq)] * BishopCentreOpening;
PSV(WHITE_BISHOP, sq, OPENING) +=
BishopLine[rank(sq)] * BishopCentreOpening;
PSV(WHITE_BISHOP, sq, ENDGAME) +=
BishopLine[file(sq)] * BishopCentreEndgame;
PSV(WHITE_BISHOP, sq, ENDGAME) +=
BishopLine[rank(sq)] * BishopCentreEndgame;
}
for (sq = A1; sq <= H1; sq++)
{
PSV(WHITE_BISHOP, sq, OPENING) -= BishopBackRankOpening;
}
for (i = 0; i < 8; i++)
{
sq = getSquare(i, i);
PSV(WHITE_BISHOP, sq, OPENING) += BishopDiagonalOpening;
PSV(WHITE_BISHOP, getFlippedSquare(sq), OPENING) +=
BishopDiagonalOpening;
}
/* rooks */
ITERATE(sq)
{
PSV(WHITE_ROOK, sq, OPENING) += VALUE_ROOK_OPENING;
PSV(WHITE_ROOK, sq, ENDGAME) += VALUE_ROOK_ENDGAME;
PSV(WHITE_ROOK, sq, OPENING) += RookFile[file(sq)] * RookFileOpening;
}
/* queens */
ITERATE(sq)
{
PSV(WHITE_QUEEN, sq, OPENING) += VALUE_QUEEN_OPENING;
PSV(WHITE_QUEEN, sq, ENDGAME) += VALUE_QUEEN_ENDGAME;
PSV(WHITE_QUEEN, sq, OPENING) +=
QueenFileOpening[file(sq)] * QueenCentreOpening;
PSV(WHITE_QUEEN, sq, OPENING) +=
QueenRankOpening[rank(sq)] * QueenCentreOpening;
PSV(WHITE_QUEEN, sq, ENDGAME) +=
QueenFileEndgame[file(sq)] * QueenCentreEndgame;
PSV(WHITE_QUEEN, sq, ENDGAME) +=
QueenRankEndgame[rank(sq)] * QueenCentreEndgame;
}
for (sq = A1; sq <= H1; sq++)
{
PSV(WHITE_QUEEN, sq, OPENING) -= QueenBackRankOpening;
}
/* king */
ITERATE(sq)
{
PSV(WHITE_KING, sq, ENDGAME) +=
KingFileEndgame[file(sq)] * KingCentreEndgame;
PSV(WHITE_KING, sq, ENDGAME) +=
KingRankEndgame[rank(sq)] * KingCentreEndgame;
PSV(WHITE_KING, sq, OPENING) += KingFile[file(sq)] * KingFileOpening;
PSV(WHITE_KING, sq, OPENING) += KingRank[rank(sq)] * KingRankOpening;
}
/* Set the value of the black pieces. */
ITERATE(sq)
{
int stage;
for (stage = OPENING; stage <= ENDGAME; stage++)
{
pieceSquareValue[BLACK_KING][sq][stage] =
pieceSquareValue[WHITE_KING][getFlippedSquare(sq)][stage];
pieceSquareValue[BLACK_QUEEN][sq][stage] =
pieceSquareValue[WHITE_QUEEN][getFlippedSquare(sq)][stage];
pieceSquareValue[BLACK_ROOK][sq][stage] =
pieceSquareValue[WHITE_ROOK][getFlippedSquare(sq)][stage];
pieceSquareValue[BLACK_BISHOP][sq][stage] =
pieceSquareValue[WHITE_BISHOP][getFlippedSquare(sq)][stage];
pieceSquareValue[BLACK_KNIGHT][sq][stage] =
pieceSquareValue[WHITE_KNIGHT][getFlippedSquare(sq)][stage];
pieceSquareValue[BLACK_PAWN][sq][stage] =
pieceSquareValue[WHITE_PAWN][getFlippedSquare(sq)][stage];
}
}
}
void initializeKingAttacks()
{
Square square;
ITERATE(square)
{
const Bitboard corona = getKingMoves(square);
KingAttacks *attackInfo = &kingAttacks[square];
Square attackerSquare;
attackInfo->diaAttackers = attackInfo->orthoAttackers =
attackInfo->knightAttackers = attackInfo->pawnAttackers[WHITE] =
attackInfo->pawnAttackers[WHITE] = EMPTY_BITBOARD;
ITERATE(attackerSquare)
{
attackInfo->attackedByDia[attackerSquare] =
attackInfo->attackedByOrtho[attackerSquare] = NO_SQUARE;
}
ITERATE(attackerSquare)
{
Bitboard dia, ortho;
const Bitboard knight =
corona & generalMoves[WHITE_KNIGHT][attackerSquare];
const Bitboard whitePawn =
corona & generalMoves[WHITE_PAWN][attackerSquare];
const Bitboard blackPawn =
corona & generalMoves[BLACK_PAWN][attackerSquare];
dia = corona & generalMoves[WHITE_BISHOP][attackerSquare];
ortho = corona & generalMoves[WHITE_ROOK][attackerSquare];
if (dia != EMPTY_BITBOARD)
{
Square attackedSquare;
int dist = 8;
setSquare(attackInfo->diaAttackers, attackerSquare);
ITERATE_BITBOARD(&dia, attackedSquare)
{
const int currentDistance =
distance(attackerSquare, attackedSquare);
if (currentDistance < dist)
{
attackInfo->attackedByDia[attackerSquare] = attackedSquare;
dist = currentDistance;
}
}
}
if (ortho != EMPTY_BITBOARD)
{
Square attackedSquare;
int dist = 8;
setSquare(attackInfo->orthoAttackers, attackerSquare);
ITERATE_BITBOARD(&ortho, attackedSquare)
{
const int currentDistance =
distance(attackerSquare, attackedSquare);
if (currentDistance < dist)
{
attackInfo->attackedByOrtho[attackerSquare] =
attackedSquare;
dist = currentDistance;
}
}
}
if (knight != EMPTY_BITBOARD)
{
setSquare(attackInfo->knightAttackers, attackerSquare);
}
if (whitePawn != EMPTY_BITBOARD)
{
setSquare(attackInfo->pawnAttackers[WHITE], attackerSquare);
}
if (blackPawn != EMPTY_BITBOARD)
{
setSquare(attackInfo->pawnAttackers[BLACK], attackerSquare);
}
}
}
}
static void getPieceTradeSignatures(UINT32 * materialSignatureWhite,
UINT32 * materialSignatureBlack)
{
int numWhiteQueens, numWhiteRooks, numWhiteLightSquareBishops;
int numWhiteDarkSquareBishops, numWhiteKnights, numWhitePawns;
int numBlackQueens, numBlackRooks, numBlackLightSquareBishops;
int numBlackDarkSquareBishops, numBlackKnights, numBlackPawns;
getPieceCounters(*materialSignatureWhite, &numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops, &numWhiteDarkSquareBishops,
&numWhiteKnights, &numWhitePawns);
getPieceCounters(*materialSignatureBlack, &numBlackQueens, &numBlackRooks,
&numBlackLightSquareBishops, &numBlackDarkSquareBishops,
&numBlackKnights, &numBlackPawns);
while (numWhiteQueens > 0 && numBlackQueens > 0)
{
numWhiteQueens--;
numBlackQueens--;
}
while (numWhiteRooks > 0 && numBlackRooks > 0)
{
numWhiteRooks--;
numBlackRooks--;
}
while (numWhiteLightSquareBishops > 0 && numBlackLightSquareBishops > 0)
{
numWhiteLightSquareBishops--;
numBlackLightSquareBishops--;
}
while (numWhiteDarkSquareBishops > 0 && numBlackDarkSquareBishops > 0)
{
numWhiteDarkSquareBishops--;
numBlackDarkSquareBishops--;
}
while (numWhiteLightSquareBishops > 0 && numBlackDarkSquareBishops > 0)
{
numWhiteLightSquareBishops--;
numBlackDarkSquareBishops--;
}
while (numWhiteDarkSquareBishops > 0 && numBlackLightSquareBishops > 0)
{
numWhiteDarkSquareBishops--;
numBlackLightSquareBishops--;
}
while (numWhiteKnights > 0 && numBlackKnights > 0)
{
numWhiteKnights--;
numBlackKnights--;
}
while (numWhiteLightSquareBishops > 0 && numBlackKnights > 0)
{
numWhiteLightSquareBishops--;
numBlackKnights--;
}
while (numWhiteDarkSquareBishops > 0 && numBlackKnights > 0)
{
numWhiteDarkSquareBishops--;
numBlackKnights--;
}
while (numWhiteKnights > 0 && numBlackLightSquareBishops > 0)
{
numWhiteKnights--;
numBlackLightSquareBishops--;
}
while (numWhiteKnights > 0 && numBlackDarkSquareBishops > 0)
{
numWhiteKnights--;
numBlackDarkSquareBishops--;
}
*materialSignatureWhite =
materialSignature(numWhiteQueens, numWhiteRooks,
numWhiteLightSquareBishops, numWhiteDarkSquareBishops,
numWhiteKnights, numWhitePawns);
*materialSignatureBlack =
materialSignature(numBlackQueens, numBlackRooks,
numBlackLightSquareBishops, numBlackDarkSquareBishops,
numBlackKnights, numBlackPawns);
}
static bool hasMaterialForMate(const UINT32 materialSignature,
const UINT32 oppMaterialSignature,
SpecialEvalType * specialEval,
const bool tradePieces)
{
int numQueens, numRooks, numLightSquareBishops, numDarkSquareBishops;
int numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int numBishops, numOppBishops;
if (tradePieces)
{
UINT32 ms = materialSignature, mso = oppMaterialSignature;
SpecialEvalType dummy;
getPieceTradeSignatures(&ms, &mso);
return hasMaterialForMate(ms, mso, &dummy, FALSE);
}
getPieceCounters(materialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numBishops = numLightSquareBishops + numDarkSquareBishops;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
if (numQueens + numRooks + numLightSquareBishops + numDarkSquareBishops +
numKnights == 0 && numPawns > 0)
{
*specialEval = Se_KpK;
return TRUE;
}
if (numQueens + numRooks + numLightSquareBishops + numDarkSquareBishops +
numPawns == 0 && numKnights == 2)
{
if (numOppQueens + numOppRooks + numOppLightSquareBishops +
numOppDarkSquareBishops + numOppKnights == 0 && numOppPawns > 0)
{
*specialEval = Se_KnnKp;
return TRUE;
}
}
if (numQueens + numRooks + numKnights == 0 &&
numLightSquareBishops + numDarkSquareBishops == 1 && numPawns > 0)
{
*specialEval = Se_KbpK;
return TRUE;
}
if (numQueens + numBishops + numKnights == 0 && numRooks == 1 &&
numPawns == 1 && numOppBishops >= 1)
{
*specialEval = Se_KrpKb;
return TRUE;
}
if (numQueens + numBishops + numKnights == 0 && numRooks == 1 &&
numPawns == 1 && numOppRooks >= 1)
{
*specialEval = Se_KrpKr;
return TRUE;
}
if (numQueens + numBishops + numKnights == 0 && numRooks == 1 &&
numPawns == 2 && numOppRooks >= 1)
{
*specialEval = Se_KrppKr;
return TRUE;
}
if (numRooks + numBishops + numKnights == 0 && numQueens == 1 &&
numPawns == 1 && numOppQueens >= 1)
{
*specialEval = Se_KqpKq;
return TRUE;
}
if (numRooks + numBishops + numKnights == 0 && numQueens == 1 &&
numPawns == 2 && numOppQueens >= 1)
{
*specialEval = Se_KqppKq;
return TRUE;
}
if (numQueens + numRooks + numPawns > 0 || numKnights >= 3)
{
return TRUE;
}
if (numLightSquareBishops > 0 && numDarkSquareBishops > 0)
{
return TRUE;
}
if (numKnights > 0 && numLightSquareBishops + numDarkSquareBishops > 0)
{
return TRUE;
}
return FALSE;
}
static PieceType getKamikazePiece(const UINT32 ownMaterialSignature,
const UINT32 oppMaterialSignature)
{
int numQueens, numRooks, numLightSquareBishops;
int numDarkSquareBishops, numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int ownSignature;
getPieceCounters(ownMaterialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
ownSignature =
materialSignature(numQueens, numRooks,
numLightSquareBishops,
numDarkSquareBishops, numKnights, numPawns - 1);
if (numOppRooks > 0)
{
const int oppSignature =
materialSignature(numOppQueens, numOppRooks - 1,
numOppLightSquareBishops,
numOppDarkSquareBishops,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return ROOK;
}
}
if (numOppLightSquareBishops > 0)
{
const int oppSignature = materialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops - 1,
numOppDarkSquareBishops,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return BISHOP;
}
}
if (numOppDarkSquareBishops > 0)
{
const int oppSignature = materialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops,
numOppDarkSquareBishops - 1,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return BISHOP;
}
}
if (numOppKnights > 0)
{
const int oppSignature = materialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops,
numOppDarkSquareBishops,
numOppKnights - 1,
numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return KNIGHT;
}
}
return NO_PIECETYPE;
}
static UINT8 getWinningChances(const UINT32 materialSignature,
const UINT32 oppMaterialSignature)
{
int numQueens, numRooks, numLightSquareBishops;
int numDarkSquareBishops, numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int numPieces, numOppPieces;
int numOppBishops, numOppMinors, numOppSliders;
bool oppositeColoredBishops;
const PieceType kamikazePiece = getKamikazePiece(materialSignature,
oppMaterialSignature);
getPieceCounters(materialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numPieces = numQueens + numRooks + numLightSquareBishops +
numDarkSquareBishops + numKnights;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
numOppMinors = numOppBishops + numOppKnights;
numOppSliders = numOppQueens + numOppRooks + numOppBishops;
numOppPieces = numOppSliders + numOppKnights;
oppositeColoredBishops = (bool)
(numLightSquareBishops + numDarkSquareBishops > 0 &&
((numOppLightSquareBishops > 0 && numLightSquareBishops == 0) ||
(numOppDarkSquareBishops > 0 && numDarkSquareBishops == 0)));
if (numPieces == 0)
{
if (numPawns <= 1 && numOppSliders > 0)
{
return 0;
}
if (numPawns <= 1 && numOppKnights > 0)
{
return 4;
}
if (numPawns == 2)
{
return (numOppSliders >= 2 ? 2 : 8);
}
}
if (numPieces == 1)
{
if (oppositeColoredBishops)
{
return (numPawns > 1 ? 8 : 0);
}
if (numPawns == 1) /* One piece, one pawn: */
{
if (numQueens > 0 && numOppRooks >= 2)
{
return 1;
}
if (numQueens > 0 && numOppRooks + numOppMinors >= 2)
{
return 12; /* usually won, but difficult */
}
if (kamikazePiece != NO_PIECETYPE)
{
switch (kamikazePiece)
{
case ROOK:
return 1;
case BISHOP:
return 2;
case KNIGHT:
return 4;
default:
break;
}
}
}
}
else if (numPieces == 2) /* has more than one piece: */
{
if (numPawns <= 1)
{
if (numRooks == 2 && numOppQueens > 0)
{
return (numPawns == 0 ? 1 : 2);
}
if (kamikazePiece != NO_PIECETYPE)
{
switch (kamikazePiece)
{
case ROOK:
return 1;
case BISHOP:
return 2;
case KNIGHT:
return 4;
default:
break;
}
}
}
if (numQueens == 0 && numRooks <= 1 && numRooks == numOppRooks &&
oppositeColoredBishops)
{
return 12;
}
}
return 16;
}
static UINT8 getWinningChancesWithoutPawn(UINT32 materialSignature,
UINT32 oppMaterialSignature)
{
int numQueens, numRooks, numLightSquareBishops;
int numDarkSquareBishops, numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int numPieces, numOppPieces;
int numOppBishops, numOppMinors, numOppSliders;
bool oppositeColoredBishops;
getPieceTradeSignatures(&materialSignature, &oppMaterialSignature);
getPieceCounters(materialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numPieces = numQueens + numRooks + numLightSquareBishops +
numDarkSquareBishops + numKnights;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
numOppMinors = numOppBishops + numOppKnights;
numOppSliders = numOppQueens + numOppRooks + numOppBishops;
numOppPieces = numOppSliders + numOppKnights;
oppositeColoredBishops = (bool)
(numLightSquareBishops + numDarkSquareBishops > 0 &&
((numOppLightSquareBishops > 0 && numLightSquareBishops == 0) ||
(numOppDarkSquareBishops > 0 && numDarkSquareBishops == 0)));
if (numPieces == 0)
{
return 0;
}
if (numPieces == 1)
{
if (numQueens > 0 && numOppRooks > 0 && numOppRooks + numOppMinors >= 2)
{
return 1;
}
if (numQueens > 0 && numOppKnights >= 2)
{
return 1;
}
if (numRooks > 0 && numOppQueens + numOppRooks > 0)
{
return 1;
}
if (numRooks > 0 && numOppMinors > 0)
{
return (numOppMinors == 1 ? 2 : 1);
}
if (numLightSquareBishops + numDarkSquareBishops + numKnights > 0)
{
return 0;
}
}
if (numLightSquareBishops == 1 && numDarkSquareBishops == 1)
{
if (numOppRooks > 0)
{
return 2;
}
if (numOppKnights > 0)
{
return 8; /* hard to win sometimes */
}
}
return 16;
}
static void initializeMaterialInfoTableCore1(const UINT32 signatureWhite,
const UINT32 signatureBlack)
{
const int index = signatureWhite + (signatureBlack << 9);
SpecialEvalType specialEvalWhite = Se_None;
SpecialEvalType specialEvalBlack = Se_None;
const bool whiteMateMat =
hasMaterialForMate(signatureWhite, signatureBlack, &specialEvalWhite,
FALSE);
const bool blackMateMat =
hasMaterialForMate(signatureBlack, signatureWhite, &specialEvalBlack,
FALSE);
int numWhiteQueens, numWhiteRooks, numWhiteLightSquareBishops;
int numWhiteDarkSquareBishops, numWhiteKnights, numWhitePawns;
int numBlackQueens, numBlackRooks, numBlackLightSquareBishops;
int numBlackDarkSquareBishops, numBlackKnights, numBlackPawns;
int numWhitePieces, numBlackPieces;
getPieceCounters(signatureWhite, &numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops, &numWhiteDarkSquareBishops,
&numWhiteKnights, &numWhitePawns);
getPieceCounters(signatureBlack, &numBlackQueens, &numBlackRooks,
&numBlackLightSquareBishops, &numBlackDarkSquareBishops,
&numBlackKnights, &numBlackPawns);
numWhitePieces =
numWhiteQueens + numWhiteRooks + numWhiteLightSquareBishops +
numWhiteDarkSquareBishops + numWhiteKnights;
numBlackPieces =
numBlackQueens + numBlackRooks + numBlackLightSquareBishops +
numBlackDarkSquareBishops + numBlackKnights;
materialInfo[index].chancesWhite = (whiteMateMat == FALSE ? 0 : 16);
materialInfo[index].chancesBlack = (blackMateMat == FALSE ? 0 : 16);
materialInfo[index].specialEvalWhite = specialEvalWhite;
materialInfo[index].specialEvalBlack = specialEvalBlack;
if (whiteMateMat != FALSE)
{
if (numWhitePawns == 0)
{
if (hasMaterialForMate(signatureWhite, signatureBlack, 0, TRUE) ==
FALSE)
{
materialInfo[index].chancesWhite = 1;
}
else
{
materialInfo[index].chancesWhite =
getWinningChancesWithoutPawn(signatureWhite, signatureBlack);
}
}
else
{
materialInfo[index].chancesWhite =
getWinningChances(signatureWhite, signatureBlack);
}
}
if (blackMateMat != FALSE)
{
if (numBlackPawns == 0)
{
if (hasMaterialForMate(signatureBlack, signatureWhite, 0, TRUE) ==
FALSE)
{
materialInfo[index].chancesBlack = 1;
}
else
{
materialInfo[index].chancesBlack =
getWinningChancesWithoutPawn(signatureBlack, signatureWhite);
}
}
else
{
materialInfo[index].chancesBlack =
getWinningChances(signatureBlack, signatureWhite);
}
}
}
void initializeMaterialInfoTable(const UINT32 signatureWhite,
const UINT32 signatureBlack, int stage)
{
int numQueens, numRooks, numLightSquareBishops, numDarkSquareBishops;
int numKnights, numPawns;
if (stage < 2)
{
for (numQueens = 0; numQueens <= 1; numQueens++)
{
for (numRooks = 0; numRooks <= 3; numRooks++)
{
for (numLightSquareBishops = 0; numLightSquareBishops <= 1;
numLightSquareBishops++)
{
for (numDarkSquareBishops = 0; numDarkSquareBishops <= 1;
numDarkSquareBishops++)
{
for (numKnights = 0; numKnights <= 3; numKnights++)
{
for (numPawns = 0; numPawns <= 3; numPawns++)
{
UINT32 signature =
materialSignature(numQueens, numRooks,
numLightSquareBishops,
numDarkSquareBishops,
numKnights,
numPawns);
if (stage == 0)
{
initializeMaterialInfoTable(signature, 0, 1);
}
else
{
initializeMaterialInfoTable(signatureWhite,
signature, 2);
}
}
}
}
}
}
}
}
else
{
initializeMaterialInfoTableCore1(signatureWhite, signatureBlack);
}
}
int initializeModuleEvaluation()
{
int i;
Square square, kingsquare, catchersquare;
centralFiles = squaresOfFile[FILE_D] | squaresOfFile[FILE_E];
attackingRealm[WHITE] = squaresOfRank[RANK_5] | squaresOfRank[RANK_6] |
squaresOfRank[RANK_7] | squaresOfRank[RANK_8];
attackingRealm[BLACK] = squaresOfRank[RANK_4] | squaresOfRank[RANK_3] |
squaresOfRank[RANK_2] | squaresOfRank[RANK_1];
rookTraps[WHITE] = rookTraps[BLACK] = EMPTY_BITBOARD;
setSquare(rookTraps[WHITE], A1);
setSquare(rookTraps[WHITE], B1);
setSquare(rookTraps[WHITE], C1);
setSquare(rookTraps[WHITE], A2);
setSquare(rookTraps[WHITE], B2);
setSquare(rookTraps[WHITE], F1);
setSquare(rookTraps[WHITE], G1);
setSquare(rookTraps[WHITE], H1);
setSquare(rookTraps[WHITE], G2);
setSquare(rookTraps[WHITE], H2);
ITERATE(square)
{
Color color;
Square kingSquare;
for (color = WHITE; color <= BLACK; color++)
{
passedPawnRectangle[color][square] =
passedPawnCorridor[color][square] =
candidateDefenders[color][square] =
candidateSupporters[color][square] =
pawnOpponents[color][square] = EMPTY_BITBOARD;
}
if (testSquare(rookTraps[WHITE], square))
{
setSquare(rookTraps[BLACK], getFlippedSquare(square));
}
ITERATE(kingSquare)
{
kingRealm[WHITE][square][kingSquare] =
kingRealm[BLACK][square][kingSquare] = EMPTY_BITBOARD;
}
}
ITERATE(square)
{
const int squarefile = file(square);
const int squarerank = rank(square);
int d1 = min(distance(square, D4), distance(square, E4));
int d2 = min(distance(square, D5), distance(square, E5));
int td1 = min(taxiDistance(square, D4), taxiDistance(square, E4));
int td2 = min(taxiDistance(square, D5), taxiDistance(square, E5));
centerDistance[square] = min(d1, d2);
centerTaxiDistance[square] = min(td1, td2);
butterflySquares[square] =
generalMoves[KING][square] & ~squaresOfFile[squarefile];
lateralSquares[square] =
generalMoves[KING][square] & squaresOfRank[squarerank];
companionFiles[square] =
((squaresOfFile[squarefile] & nonA) >> 1) |
((squaresOfFile[squarefile] & nonH) << 1);
rookBlockers[square] = EMPTY_BITBOARD;
ITERATE(kingsquare)
{
const int kingsquarefile = file(kingsquare);
const int kingsquarerank = rank(kingsquare);
Square targetSquare;
if (kingsquarerank >= squarerank &&
distance(square, kingsquare) <= 7 - squarerank)
{
setSquare(passedPawnRectangle[WHITE][square], kingsquare);
}
if (kingsquarerank <= squarerank &&
distance(square, kingsquare) <= squarerank)
{
setSquare(passedPawnRectangle[BLACK][square], kingsquare);
}
if (kingsquarefile == squarefile)
{
if (kingsquarerank > squarerank)
{
setSquare(passedPawnCorridor[WHITE][square], kingsquare);
}
if (kingsquarerank < squarerank)
{
setSquare(passedPawnCorridor[BLACK][square], kingsquare);
}
}
if (squarerank == kingsquarerank)
{
if (squarefile <= FILE_C && kingsquarefile <= FILE_C &&
kingsquarefile > squarefile)
{
setSquare(rookBlockers[square], kingsquare);
}
if (squarefile >= FILE_F && kingsquarefile >= FILE_F &&
kingsquarefile < squarefile)
{
setSquare(rookBlockers[square], kingsquare);
}
}
ITERATE(targetSquare)
{
if (distance(square, targetSquare) <
distance(kingsquare, targetSquare))
{
const Rank targetrank = rank(targetSquare);
if (targetrank <= squarerank + 1)
{
setSquare(kingRealm[WHITE][square][kingsquare],
targetSquare);
}
if (targetrank >= squarerank - 1)
{
setSquare(kingRealm[BLACK][square][kingsquare],
targetSquare);
}
}
}
}
ITERATE(catchersquare)
{
if (abs(file(catchersquare) - squarefile) == 1)
{
if (rank(catchersquare) > squarerank)
{
setSquare(candidateDefenders[WHITE][square], catchersquare);
}
if (rank(catchersquare) <= squarerank)
{
setSquare(candidateSupporters[WHITE][square], catchersquare);
}
if (rank(catchersquare) < squarerank)
{
setSquare(candidateDefenders[BLACK][square], catchersquare);
}
if (rank(catchersquare) >= squarerank)
{
setSquare(candidateSupporters[BLACK][square], catchersquare);
}
}
if (abs(file(catchersquare) - squarefile) <= 1)
{
if (rank(catchersquare) >= squarerank)
{
setSquare(pawnOpponents[WHITE][square], catchersquare);
}
if (rank(catchersquare) <= squarerank)
{
setSquare(pawnOpponents[BLACK][square], catchersquare);
}
}
}
}
ITERATE(square)
{
const int squarerank = rank(square);
ITERATE(kingsquare)
{
if (squarerank >= RANK_2 && squarerank <= RANK_7)
{
passedPawnDefenderMalus[WHITE][WHITE][square][kingsquare] =
getPassedPawnDefenderMalus(WHITE, WHITE, square, kingsquare);
passedPawnDefenderMalus[WHITE][BLACK][square][kingsquare] =
getPassedPawnDefenderMalus(WHITE, BLACK, square, kingsquare);
passedPawnDefenderMalus[BLACK][WHITE][square][kingsquare] =
getPassedPawnDefenderMalus(BLACK, WHITE, square, kingsquare);
passedPawnDefenderMalus[BLACK][BLACK][square][kingsquare] =
getPassedPawnDefenderMalus(BLACK, BLACK, square, kingsquare);
}
else
{
passedPawnDefenderMalus[WHITE][WHITE][square][kingsquare] =
passedPawnDefenderMalus[WHITE][BLACK][square][kingsquare] =
passedPawnDefenderMalus[BLACK][WHITE][square][kingsquare] =
passedPawnDefenderMalus[BLACK][BLACK][square][kingsquare] = 0;
}
}
}
ITERATE(square)
{
const int dDark =
min(taxiDistance(square, A1), taxiDistance(square, H8));
const int dLight =
min(taxiDistance(square, A8), taxiDistance(square, H1));
const int dStandard = centerDistance[square];
kingChaseMalus[DARK][square] = 3 * (7 - dDark) + dStandard;
kingChaseMalus[LIGHT][square] = 3 * (7 - dLight) + dStandard;
kingChaseMalus[ALL][square] = 6 - min(dDark, dLight) +
centerDistance[square];
}
/*
dumpBoardValues(kingChaseMalus[DARK]);
dumpBoardValues(kingChaseMalus[LIGHT]);
dumpBoardValues(kingChaseMalus[ALL]);
getKeyStroke();
*/
initializePieceSquareValues();
initializeKingAttacks();
attackPoints[WHITE_KING] = 0;
attackPoints[WHITE_QUEEN] = QUEEN_BONUS_ATTACK;
attackPoints[WHITE_ROOK] = ROOK_BONUS_ATTACK;
attackPoints[WHITE_BISHOP] = BISHOP_BONUS_ATTACK;
attackPoints[WHITE_KNIGHT] = KNIGHT_BONUS_ATTACK;
attackPoints[WHITE_PAWN] = 0;
attackPoints[BLACK_KING] = 0;
attackPoints[BLACK_QUEEN] = QUEEN_BONUS_ATTACK;
attackPoints[BLACK_ROOK] = ROOK_BONUS_ATTACK;
attackPoints[BLACK_BISHOP] = BISHOP_BONUS_ATTACK;
attackPoints[BLACK_KNIGHT] = KNIGHT_BONUS_ATTACK;
attackPoints[BLACK_PAWN] = 0;
weakOutpostSquareCandidates[WHITE] = weakOutpostSquareCandidates[BLACK] =
EMPTY_BITBOARD;
setSquare(weakOutpostSquareCandidates[WHITE], C4);
setSquare(weakOutpostSquareCandidates[WHITE], D4);
setSquare(weakOutpostSquareCandidates[WHITE], E4);
setSquare(weakOutpostSquareCandidates[WHITE], F4);
setSquare(weakOutpostSquareCandidates[WHITE], C3);
setSquare(weakOutpostSquareCandidates[WHITE], D3);
setSquare(weakOutpostSquareCandidates[WHITE], E3);
setSquare(weakOutpostSquareCandidates[WHITE], F3);
setSquare(weakOutpostSquareCandidates[BLACK], C5);
setSquare(weakOutpostSquareCandidates[BLACK], D5);
setSquare(weakOutpostSquareCandidates[BLACK], E5);
setSquare(weakOutpostSquareCandidates[BLACK], F5);
setSquare(weakOutpostSquareCandidates[BLACK], C6);
setSquare(weakOutpostSquareCandidates[BLACK], D6);
setSquare(weakOutpostSquareCandidates[BLACK], E6);
setSquare(weakOutpostSquareCandidates[BLACK], F6);
expoFactor[0] = 1024;
for (i = 1; i < NUM_EXPO_FACTORS; i++)
{
expoFactor[i] = (1044 * expoFactor[i - 1]) / 1024;
}
for (i = 0; i < NUM_EXPO_FACTORS; i++)
{
expoValue[i] = (100 * expoFactor[i]) / 1024 - 100;
/*logDebug("ev(%d)=%d\n", i, expoValue[i]); */
}
homeland[WHITE] = (squaresOfRank[RANK_1] | squaresOfRank[RANK_2] |
squaresOfRank[RANK_3] | squaresOfRank[RANK_4]) &
(squaresOfFile[FILE_C] | squaresOfFile[FILE_D] |
squaresOfFile[FILE_E] | squaresOfFile[FILE_F]);
/*
homeland[WHITE] |= (squaresOfRank[RANK_1] |
squaresOfRank[RANK_2] | squaresOfRank[RANK_3]) &
(squaresOfFile[FILE_A] | squaresOfFile[FILE_B] |
squaresOfFile[FILE_G] | squaresOfFile[FILE_H]);
*/
homeland[BLACK] = getFlippedBitboard(homeland[WHITE]);
#ifdef GENERATE_TABLES
generateKpkpTable();
#endif
for (i = 0; i < 16; i++)
{
int j;
for (j = 0; j < 16; j++)
{
sliderAttackPoints[i][j] = 0;
}
}
sliderAttackPoints[WHITE_BISHOP][WHITE_PAWN] = 2;
sliderAttackPoints[WHITE_BISHOP][WHITE_KNIGHT] = 4;
sliderAttackPoints[WHITE_BISHOP][WHITE_ROOK] = 4;
sliderAttackPoints[WHITE_BISHOP][WHITE_KING] = 4;
sliderAttackPoints[WHITE_BISHOP][BLACK_PAWN] = 3;
sliderAttackPoints[WHITE_BISHOP][BLACK_KNIGHT] = 3;
sliderAttackPoints[WHITE_BISHOP][BLACK_ROOK] = 10;
sliderAttackPoints[WHITE_BISHOP][BLACK_QUEEN] = 10;
sliderAttackPoints[WHITE_ROOK][WHITE_PAWN] = 1;
sliderAttackPoints[WHITE_ROOK][WHITE_KNIGHT] = 4;
sliderAttackPoints[WHITE_ROOK][WHITE_BISHOP] = 4;
sliderAttackPoints[WHITE_ROOK][WHITE_KING] = 4;
sliderAttackPoints[WHITE_ROOK][BLACK_PAWN] = 3;
sliderAttackPoints[WHITE_ROOK][BLACK_KNIGHT] = 3;
sliderAttackPoints[WHITE_ROOK][BLACK_BISHOP] = 3;
sliderAttackPoints[WHITE_ROOK][BLACK_QUEEN] = 10;
sliderAttackPoints[WHITE_QUEEN][WHITE_PAWN] = 2;
sliderAttackPoints[WHITE_QUEEN][WHITE_KNIGHT] = 3;
sliderAttackPoints[WHITE_QUEEN][WHITE_BISHOP] = 3;
sliderAttackPoints[WHITE_QUEEN][WHITE_ROOK] = 4;
sliderAttackPoints[WHITE_QUEEN][WHITE_KING] = 3;
sliderAttackPoints[WHITE_QUEEN][BLACK_PAWN] = 1;
sliderAttackPoints[WHITE_QUEEN][BLACK_KNIGHT] = 3;
sliderAttackPoints[WHITE_QUEEN][BLACK_BISHOP] = 3;
sliderAttackPoints[WHITE_QUEEN][BLACK_ROOK] = 3;
for (i = 0; i < 16; i++)
{
int j;
for (j = 0; j < 16; j++)
{
if (pieceColor(i) == BLACK)
{
const Color reversedColor = opponent(pieceColor(j));
PieceType attacker = (PieceType) (pieceType(i) | WHITE);
PieceType middlePiece =
(PieceType) (pieceType(j) | reversedColor);
sliderAttackPoints[i][j] =
sliderAttackPoints[attacker][middlePiece];
}
}
}
assert(sliderAttackPoints[BLACK_ROOK][WHITE_PAWN] ==
sliderAttackPoints[WHITE_ROOK][BLACK_PAWN]);
assert(sliderAttackPoints[BLACK_QUEEN][WHITE_BISHOP] ==
sliderAttackPoints[WHITE_QUEEN][BLACK_BISHOP]);
assert(sliderAttackPoints[BLACK_KNIGHT][WHITE_BISHOP] ==
sliderAttackPoints[WHITE_KNIGHT][BLACK_BISHOP]);
troitzkyArea[WHITE] =
passedPawnCorridor[WHITE][A3] | passedPawnCorridor[WHITE][B5] |
passedPawnCorridor[WHITE][C3] | passedPawnCorridor[WHITE][D3] |
passedPawnCorridor[WHITE][E3] | passedPawnCorridor[WHITE][F3] |
passedPawnCorridor[WHITE][G5] | passedPawnCorridor[WHITE][H3];
troitzkyArea[BLACK] = getFlippedBitboard(troitzkyArea[WHITE]);
krprkDrawFiles = squaresOfFile[FILE_A] | squaresOfFile[FILE_B] |
squaresOfFile[FILE_G] | squaresOfFile[FILE_H];
A1C1 = minValue[A1] | minValue[C1], F1H1 = minValue[F1] | minValue[H1];
A1B1 = minValue[A1] | minValue[B1], G1H1 = minValue[G1] | minValue[H1];
initializeMaterialInfoTable(0, 0, 0);
return 0;
}
#ifndef NDEBUG
bool flipTest(Position * position,
PawnHashInfo * pawnHashtable,
KingSafetyHashInfo * kingsafetyHashtable)
{
int v1, v2;
initializePosition(position);
v1 = getValue(position, VALUE_MATED, -VALUE_MATED,
pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
v2 = getValue(position, VALUE_MATED, -VALUE_MATED,
pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
if (v1 != v2)
{
const int debugFlag = debugOutput;
const bool debugEvalFlag = debugEval;
debugOutput = TRUE;
debugEval = TRUE;
logDebug("flip test failed: v1=%d v2=%d\n", v1, v2);
logPosition(position);
logDebug("hash: %llu\n", position->hashValue);
getValue(position, VALUE_MATED, -VALUE_MATED,
pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
logPosition(position);
getValue(position, VALUE_MATED, -VALUE_MATED,
pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
debugEval = debugEvalFlag;
debugOutput = debugFlag;
}
return (bool) (v1 == v2);
}
#endif
static int testPawnInfoGeneration()
{
Variation variation;
EvaluationBase base;
initializeVariation(&variation,
"8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - 0 1");
getPawnInfo(&variation.singlePosition, &base);
assert(getNumberOfSetSquares(base.pawnProtectedSquares[WHITE]) == 8);
assert(testSquare(base.pawnProtectedSquares[WHITE], B4));
assert(testSquare(base.pawnProtectedSquares[WHITE], A3));
assert(testSquare(base.pawnProtectedSquares[WHITE], C3));
assert(testSquare(base.pawnProtectedSquares[WHITE], D4));
assert(testSquare(base.pawnProtectedSquares[WHITE], F4));
assert(testSquare(base.pawnProtectedSquares[WHITE], E5));
assert(testSquare(base.pawnProtectedSquares[WHITE], G5));
assert(testSquare(base.pawnProtectedSquares[WHITE], G3));
assert(getNumberOfSetSquares(base.pawnProtectedSquares[BLACK]) == 7);
assert(testSquare(base.pawnProtectedSquares[BLACK], B3));
assert(testSquare(base.pawnProtectedSquares[BLACK], D3));
assert(testSquare(base.pawnProtectedSquares[BLACK], C2));
assert(testSquare(base.pawnProtectedSquares[BLACK], E2));
assert(testSquare(base.pawnProtectedSquares[BLACK], E4));
assert(testSquare(base.pawnProtectedSquares[BLACK], G4));
assert(testSquare(base.pawnProtectedSquares[BLACK], G6));
assert(getNumberOfSetSquares(base.passedPawns[WHITE]) == 0);
assert(getNumberOfSetSquares(base.passedPawns[BLACK]) == 1);
assert(testSquare(base.passedPawns[BLACK], D3));
assert(getNumberOfSetSquares(base.weakPawns[WHITE]) == 3);
assert(testSquare(base.weakPawns[WHITE], B2));
assert(testSquare(base.weakPawns[WHITE], E3));
assert(testSquare(base.weakPawns[WHITE], H2));
assert(getNumberOfSetSquares(base.weakPawns[BLACK]) == 4);
assert(testSquare(base.weakPawns[BLACK], A4));
assert(testSquare(base.weakPawns[BLACK], C4));
assert(testSquare(base.weakPawns[BLACK], F5));
assert(testSquare(base.weakPawns[BLACK], H7));
initializeVariation(&variation,
"4k3/2p5/p2p4/P2P4/1PP3p1/7p/7P/4K3 w - - 0 1");
getPawnInfo(&variation.singlePosition, &base);
assert(getNumberOfSetSquares(base.passedPawns[WHITE]) == 0);
assert(getNumberOfSetSquares(base.passedPawns[BLACK]) == 0);
assert(getNumberOfSetSquares(base.weakPawns[WHITE]) == 1);
assert(testSquare(base.weakPawns[WHITE], H2));
assert(getNumberOfSetSquares(base.weakPawns[BLACK]) == 3);
assert(testSquare(base.weakPawns[BLACK], A6));
assert(testSquare(base.weakPawns[BLACK], C7));
assert(testSquare(base.weakPawns[BLACK], G4));
return 0;
}
static int testWeakPawnDetection()
{
Position position;
Bitboard expectedResult = EMPTY_BITBOARD;
EvaluationBase base;
clearPosition(&position);
position.piece[E1] = WHITE_KING;
position.piece[E8] = BLACK_KING;
position.piece[A3] = WHITE_PAWN;
position.piece[B5] = WHITE_PAWN;
position.piece[B6] = WHITE_PAWN;
position.piece[C4] = WHITE_PAWN;
position.piece[E4] = WHITE_PAWN;
position.piece[G4] = WHITE_PAWN;
position.piece[H2] = WHITE_PAWN;
position.piece[A4] = BLACK_PAWN;
position.piece[B7] = BLACK_PAWN;
setSquare(expectedResult, A3);
setSquare(expectedResult, E4);
initializePosition(&position);
getPawnInfo(&position, &base);
assert(base.weakPawns[WHITE] == expectedResult);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, B7);
assert(base.weakPawns[BLACK] == expectedResult);
assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD);
position.piece[C4] = NO_PIECE;
position.piece[C5] = WHITE_PAWN;
initializePosition(&position);
getPawnInfo(&position, &base);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, C5);
assert(base.candidatePawns[WHITE] == expectedResult);
clearPosition(&position);
position.piece[E1] = WHITE_KING;
position.piece[E8] = BLACK_KING;
position.piece[A3] = WHITE_PAWN;
position.piece[B5] = WHITE_PAWN;
position.piece[B6] = WHITE_PAWN;
position.piece[C4] = WHITE_PAWN;
position.piece[E4] = WHITE_PAWN;
position.piece[G4] = WHITE_PAWN;
position.piece[H2] = WHITE_PAWN;
position.piece[A4] = BLACK_PAWN;
position.piece[B7] = BLACK_PAWN;
position.piece[D6] = BLACK_PAWN;
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, A3);
setSquare(expectedResult, E4);
setSquare(expectedResult, C4);
initializePosition(&position);
getPawnInfo(&position, &base);
assert(base.weakPawns[WHITE] == expectedResult);
assert(base.candidatePawns[WHITE] == EMPTY_BITBOARD);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, B7);
setSquare(expectedResult, D6);
assert(base.weakPawns[BLACK] == expectedResult);
assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD);
position.piece[G5] = BLACK_PAWN;
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, A3);
setSquare(expectedResult, E4);
setSquare(expectedResult, C4);
setSquare(expectedResult, H2);
initializePosition(&position);
getPawnInfo(&position, &base);
assert(base.weakPawns[WHITE] == expectedResult);
assert(base.candidatePawns[WHITE] == EMPTY_BITBOARD);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, B7);
setSquare(expectedResult, D6);
setSquare(expectedResult, G5);
assert(base.weakPawns[BLACK] == expectedResult);
assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD);
return 0;
}
static int testBaseInitialization()
{
Variation variation;
initializeVariation(&variation, FEN_GAMESTART);
assert(testSquare(passedPawnCorridor[WHITE][B4], B6));
assert(testSquare(passedPawnCorridor[BLACK][B4], B6) == FALSE);
assert(testSquare(passedPawnCorridor[WHITE][C2], H7) == FALSE);
assert(testSquare(passedPawnCorridor[BLACK][G6], G2));
return 0;
}
/*
static int testFlippings()
{
const char fen1[] =
"2rr2k1/1b3ppp/pb2p3/1p2P3/1P2BPnq/P1N3P1/1B2Q2P/R4R1K b - - 0 1";
const char fen2[] = "4k3/2p5/p2p4/P2P4/1PP3p1/7p/7P/4K3 w - - 0 1";
const char fen3[] = "8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - 0 1";
const char fen4[] =
"6r1/Q2Pn2k/p1p1P2p/5p2/2PqR1r1/1P6/P6P/5R1K b - - 5 4";
const char fen5[] =
"Q4rk1/2bb1ppp/4pn2/pQ5q/3P4/N4N2/5PPP/R1B2RK1 w - a6 0 4";
Variation variation;
initializeVariation(&variation, fen1);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen2);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen3);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen4);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen5);
assert(flipTest(&variation.singlePosition) != FALSE);
return 0;
}
*/
int testModuleEvaluation()
{
int result;
if ((result = testPawnInfoGeneration()) != 0)
{
return result;
}
if ((result = testWeakPawnDetection()) != 0)
{
return result;
}
if ((result = testBaseInitialization()) != 0)
{
return result;
}
/*
if ((result = testFlippings()) != 0)
{
return result;
}
*/
return 0;
}