/*
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"
#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
#include "evaluation.h"
/*
#define BONUS_TARGETS
#define CALCULATE_TARGETS
#define MALUS_OFFSIDE_KING
#define BONUS_CONNECTED_DISTANT_PASSERS
*/
/* -------------------------------------------------------------------------- */
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_MALUS_BLOCKED = 30;
const int PASSED_PAWN_MALUS_LACK_OF_SUPPORT = 30;
const int PASSED_PAWN_BONUS_CONNECTED_DISTANT = 40;
const int PASSED_PAWN_BONUS_CONNECTED_DISTANT_DUO = 10;
const int PASSED_PAWN_ATTACKERDIST_WEIGHT = 5;
const int PASSED_PAWN_DEFENDERDIST_WEIGHT = 20;
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 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 rookTraps[2];
Bitboard rookBlockers[_64_];
Bitboard centralFiles;
Bitboard kingRealm[2][_64_][_64_];
Bitboard attackingRealm[2];
KingAttacks kingAttacks[_64_];
UINT64 numEvals = 0, sumDiff = 0, sumDiffSquare = 0;
int expoFactor[NUM_EXPO_FACTORS];
int expoValue[NUM_EXPO_FACTORS];
int kingChaseMalus[3][_64_];
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 bool oppositeColoredBishops(const Position * position)
{
if (getPieceCount(position, WHITE_BISHOP) == 1 &&
getPieceCount(position, BLACK_BISHOP) == 1)
{
const Bitboard bishops =
position->piecesOfType[WHITE_BISHOP] |
position->piecesOfType[BLACK_BISHOP];
return (bool) ((lightSquares & bishops) != EMPTY_BITBOARD &&
(darkSquares & bishops) != EMPTY_BITBOARD);
}
else
{
return FALSE;
}
}
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 delta = PASSED_PAWN_BONUS_ENDGAME_MAX -
PASSED_PAWN_BONUS_ENDGAME_MIN;
bool blocked = TRUE;
const bool hasSupportingBishop =
hasAttackingBishop(position, pawnColor, stopSquare);
const bool oppHasBlockingBishop =
hasAttackingBishop(position, oppColor, stopSquare);
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))
{
delta += 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)
{
delta += PASSED_PAWN_BONUS_UNSTOPPABLE;
}
}
#ifdef BONUS_WINNING_PASSER
if (delta < PASSED_PAWN_BONUS_UNSTOPPABLE &&
base->hasPassersOrCandidates[oppColor] == FALSE &&
passerWalks(position, square, pawnColor))
{
delta += PASSED_PAWN_BONUS_UNSTOPPABLE;
}
#endif
}
if (position->piece[stopSquare] == NO_PIECE &&
delta < 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)
{
delta += PASSED_PAWN_BONUS_NOT_BLOCKED;
blocked = FALSE;
}
}
delta -=
distance(stopSquare, position->king[pawnColor]) *
PASSED_PAWN_ATTACKERDIST_WEIGHT;
delta +=
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))))
{
delta -= 10;
}
#endif
#ifdef BONUS_CONNECTED_DISTANT_PASSERS
if (testSquare(passedPawnRectangle[pawnColor][square],
position->king[oppColor]) == FALSE)
{
const File pawnFile = file(square);
const int fileDiff = pawnFile - file(position->king[oppColor]);
const Bitboard dangerousCompanionFiles =
(fileDiff > 0 ? squaresOfFileRange[pawnFile][FILE_H] :
squaresOfFileRange[FILE_A][pawnFile]);
const Bitboard dangerousCompanions =
base->passedPawns[pawnColor] &
butterflySquares[square] & dangerousCompanionFiles;
if (dangerousCompanions != EMPTY_BITBOARD)
{
delta += PASSED_PAWN_BONUS_CONNECTED_DISTANT;
}
}
#endif
#ifdef MALUS_BLOCKABLE_PASSERS
if (numberOfNonPawnPieces(position, pawnColor) <=
numberOfNonPawnPieces(position, oppColor) && oppHasBlockingBishop)
{
if (hasSupportingBishop)
{
delta -= 5;
}
else
{
delta -= 20;
}
}
if (blocked &&
numberOfNonPawnPieces(position, pawnColor) <=
numberOfNonPawnPieces(position, oppColor) &&
getPieceCount(position, (Piece) (BISHOP | pawnColor)) > 0 &&
hasSupportingBishop == FALSE)
{
delta -= 10;
}
if ((base->passedPawns[pawnColor] & butterflySquares[square]) !=
EMPTY_BITBOARD)
{
const int attackerDist = distance(position->king[pawnColor], square);
const int defenderDist = distance(position->king[oppColor], square);
delta += max(0, 5 * (defenderDist - attackerDist));
if (oppHasBlockingBishop)
{
if (hasSupportingBishop)
{
delta += 10;
}
else
if (getPieceCount(position, (Piece) (KNIGHT | pawnColor)) > 0)
{
delta += 5;
}
}
else
{
delta += 20;
}
}
#endif
if (delta > 0)
{
base->endgamePoints[pawnColor] += quad(0, delta, 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)]);
}
#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;
#ifdef CALCULATE_TARGETS
base->pieceAttacks[color] |= moves;
#endif
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;
}
#ifdef BONUS_TARGETS
evaluateTargets(base->openingTargets[color],
base->endgameTargets[color], moves, &opCount, &egCount);
#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] += 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
#ifdef CALCULATE_TARGETS
base->pieceAttacks[color] |= moves;
#endif
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_TARGETS
evaluateTargets(base->openingTargets[color],
base->endgameTargets[color], moves, &opCount, &egCount);
#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;
#ifdef CALCULATE_TARGETS
base->pieceAttacks[color] |= moves;
#endif
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_TARGETS
evaluateTargets(base->openingTargets[color],
base->endgameTargets[color], moves, &opCount, &egCount);
#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;
#ifdef CALCULATE_TARGETS
base->pieceAttacks[color] |= moves;
#endif
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
}
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_QUEEN_DEFENDER_DISTANCE
int queenMalus;
const int queenDistance =
getMinimalTaxiDistance(position, kingSquare, (Piece) (QUEEN | color));
#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
}
Bitboard getPromotablePawns(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
const Square oppKing = position->king[oppColor];
const bool lightSquaredBishop = (bool)
(EMPTY_BITBOARD !=
(lightSquares & position->piecesOfType[BISHOP | color]));
const Bitboard pawns = position->piecesOfType[PAWN | color];
Bitboard supporters;
File excludeFile;
Rank promotionRank;
Square promotionSquare;
if (color == WHITE)
{
excludeFile = (lightSquaredBishop ? FILE_H : FILE_A);
promotionRank = RANK_8;
}
else
{
excludeFile = (lightSquaredBishop ? FILE_A : FILE_H);
promotionRank = RANK_1;
}
promotionSquare = getSquare(excludeFile, promotionRank);
supporters = companionFiles[promotionSquare] & pawns;
if (distance(oppKing, promotionSquare) <= 1 &&
supporters == EMPTY_BITBOARD)
{
return pawns & ~squaresOfFile[excludeFile];
}
else
{
return pawns;
}
}
static int getWinningChances(const Position * position, const Color color)
{
const int MIN_CHANCES = 1;
const Color oppColor = opponent(color);
const int numPawns = position->numberOfPawns[color];
const int numPieces = position->numberOfPieces[color] - numPawns - 1;
const int numOppPawns = position->numberOfPawns[oppColor];
const int numOppPieces =
position->numberOfPieces[oppColor] - numOppPawns - 1;
const bool rookPresent = pieceIsPresent(position, (Piece) (ROOK | color));
const bool queenPresent =
pieceIsPresent(position, (Piece) (QUEEN | color));
if (rookPresent || queenPresent)
{
const bool oppRookPresent =
pieceIsPresent(position, (Piece) (ROOK | oppColor));
const bool oppQueenPresent =
pieceIsPresent(position, (Piece) (QUEEN | oppColor));
if (queenPresent)
{
if (numPieces == 1 && numPawns == 2 && oppQueenPresent)
{
const Bitboard pawns = position->piecesOfType[PAWN | color];
if ((((pawns & squaresOfFile[FILE_A]) &&
(pawns & squaresOfFile[FILE_B])) ||
((pawns & squaresOfFile[FILE_H]) &&
(pawns & squaresOfFile[FILE_G]))))
{
return 12;
}
}
if (rookPresent || numPawns >= 2 || numPieces >= 3 ||
getPieceCount(position, (Piece) (QUEEN | color)) >= 2)
{
return 16;
}
assert(rookPresent == FALSE);
assert(numPawns <= 1);
assert(numPieces <= 2);
assert(getPieceCount(position, (Piece) (QUEEN | color)) == 1);
if (numPawns == 0) /* KQKx, KQBKx, KQNKx */
{
if (oppQueenPresent ||
getPieceCount(position, (Piece) (ROOK | oppColor)) >= 2)
{
return 2; /* KQBKQ, KQNKQ, KQBKRR, KQNKRR */
}
else if (numPieces == 1 && numOppPieces >= 2)
{
/* single queen vs. two pieces */
return (oppRookPresent ? 2 : 8);
}
}
else
{
assert(numPawns == 1);
if (numPieces == 1 &&
(oppQueenPresent || (numOppPieces >= 2 && oppRookPresent)))
{
/* KQPKQx, KQPKRBx, KQPKRNx */
Bitboard pawns =
position->piecesOfType[(Piece) (PAWN | color)];
const Square pawnSquare = getNextSquare(&pawns);
assert(pawnSquare != NO_SQUARE);
if (testSquare(passedPawnCorridor[color][pawnSquare],
position->king[oppColor]))
{
return 4;
}
else
{
return 16;
}
}
if (numPieces == 2 && oppQueenPresent && numOppPieces >= 2)
{
assert(pieceIsPresent(position, (Piece) (KNIGHT | color)) ||
pieceIsPresent(position, (Piece) (BISHOP | color)));
/* KQ[BN]PKQ[RBN] */
return 4; /* kamikaze sac possible */
}
}
}
else /* rook present: */
{
assert(rookPresent);
assert(queenPresent == FALSE);
if (numPieces == 1 && numPawns == 2)
{
const Bitboard pawns =
position->piecesOfType[(Piece) (PAWN | color)];
if ((((pawns & squaresOfFile[FILE_A]) &&
(pawns & squaresOfFile[FILE_C])) ||
((pawns & squaresOfFile[FILE_H]) &&
(pawns & squaresOfFile[FILE_F]))))
{
return 12;
}
}
if (numPawns >= 2 || numPieces >= 3)
{
if (getPieceCount(position, (Piece) (ROOK | color)) == 1 &&
numPawns == 0 && oppRookPresent &&
numPieces <= numOppPieces + 1)
{
return 4; /* R+[BN]+[BN] vs. R+[BN] */
}
if (numPawns == 0 &&
getPieceCount(position, (Piece) (ROOK | oppColor)) >= 2)
{
/* R+R+[BN] vs. R+R+x */
return 2;
}
return 16;
}
assert(numPawns <= 1);
assert(numPieces <= 2);
if (getPieceCount(position, (Piece) (ROOK | color)) == 2)
{
if (numPawns >= 1)
{
return 16;
}
assert(numPawns == 0);
if (oppQueenPresent || (oppRookPresent && numOppPieces >= 2))
{
/* 2 rooks vs. queen */
return 2;
}
else
{
return 16;
}
}
assert(getPieceCount(position, (Piece) (ROOK | color)) == 1);
if (numPawns == 0)
{
if (oppQueenPresent || oppRookPresent)
{
/* rook (+ minor piece) vs. queen */
return 2;
}
else
{
/* rook (+ minor piece) vs. minor piece(s) */
return (numPieces > numOppPieces ? 16 : 2);
}
}
else
{
assert(numPawns == 1);
if (numPieces == 1)
{
if (numOppPieces >= 2)
{
/* rook + pawn vs. 2+ pieces */
if (oppRookPresent ||
pieceIsPresent(position, (Piece) (BISHOP | oppColor)))
{
return 2; /* kamikaze sac possible */
}
else
{
return 16; /* two knights might have serious problems */
}
}
if (oppRookPresent || numOppPawns >= 2)
{
return 12;
}
}
else
{
assert(numPieces == 2);
if (oppRookPresent && numOppPieces >= 2)
{
/* KR[BN]PKR[BN]x */
return 8; /* kamikaze sac possible */
}
}
}
}
}
else /* no major pieces present: */
{
const bool kamikazeSac = (bool) (numOppPieces >= numPawns);
if (numPieces == 0) /* king (+pawns) */
{
if (numPawns == 0)
{
return 0;
}
else
{
Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
if ((pawns & nonA & nonH) != EMPTY_BITBOARD)
{
return 16;
}
else
{
const Square king = position->king[color];
const Square oppKing = position->king[oppColor];
Square square;
ITERATE_BITBOARD(&pawns, square)
{
const int promotionRank =
(color == WHITE ? RANK_8 : RANK_1);
const Square promotionSquare =
getSquare(file(square), promotionRank);
const int oppKingDist = distance(oppKing, promotionSquare);
assert(file(square) == FILE_A || file(square) == FILE_H);
if (oppKingDist > distance(square, promotionSquare) ||
oppKingDist > distance(king, promotionSquare))
{
return 16;
}
}
return MIN_CHANCES; /* king holds pawn(s) */
}
}
}
if (numPawns == 0 && numPieces - numOppPieces <= 1 &&
getPieceCount(position, (Piece) (BISHOP | color)) < 2)
{
/* no pawns, only one minor piece up */
if (numOppPawns > 0 && numOppPieces > 0 &&
pieceIsPresent(position, (Piece) (BISHOP | color)) == FALSE)
{
return 12; /* opp might have chances */
}
return (numPieces > 1 ? MIN_CHANCES + 1 : MIN_CHANCES);
}
if (numPawns == 1 && numPieces <= numOppPieces)
{
return 2; /* one pawn, opp may sac piece for pawn */
}
if (pieceIsPresent(position, (Piece) (KNIGHT | color)) == FALSE)
{ /* only bishops: */
const Bitboard exclude =
position->piecesOfType[(Piece) (PAWN | color)] |
minValue[position->king[color]];
const Bitboard bishops = position->piecesOfColor[color] & ~exclude;
int numBishops = numPieces;
assert(getPieceCount(position, (Piece) (BISHOP | color)) ==
numPieces);
if (numPieces > 1)
{
if (((bishops & lightSquares) == EMPTY_BITBOARD) ||
((bishops & darkSquares) == EMPTY_BITBOARD))
{
numBishops = 1;
}
}
if (numBishops == 2 && numPawns == 0)
{
if (pieceIsPresent(position, (Piece) (ROOK | oppColor)) ||
pieceIsPresent(position, (Piece) (BISHOP | oppColor)))
{
return MIN_CHANCES;
}
}
if (numBishops == 1)
{
const bool oppColors = oppositeColoredBishops(position);
const int max = (oppColors ? 8 : 16);
if (numPawns == 0)
{
return MIN_CHANCES;
}
else if (kamikazeSac)
{
if (pieceIsPresent(position, (Piece) (BISHOP | oppColor)) ||
pieceIsPresent(position, (Piece) (ROOK | oppColor)))
{
return 4;
}
else
{
return 12;
}
}
else
{
const Bitboard promotablePawns =
getPromotablePawns(position, color);
const int numPromotablePawns =
getNumberOfSetSquares(promotablePawns);
const int numDefenders =
(oppColors ?
getPieceCount(position, (Piece) (BISHOP | oppColor)) : 0);
return (numPromotablePawns > numDefenders ? max : MIN_CHANCES);
}
}
}
else if (pieceIsPresent(position, (Piece) (BISHOP | color)) == FALSE)
{ /* only knights: */
assert(getPieceCount(position, (Piece) (KNIGHT | color)) ==
numPieces);
if (numPieces == 2)
{
/* king + two knights (+ pawn) */
if (numPawns == 0)
{
if (numOppPawns > 0 &&
pieceIsPresent(position, (Piece) (ROOK | oppColor)))
{
return 12; /* winning chances for opponent */
}
else if (numOppPieces == 0 && numOppPawns != 0)
{
return 2; /* small chances */
}
else
{
return MIN_CHANCES; /* no chances */
}
}
if (kamikazeSac)
{
return 12;
}
}
if (numPieces == 1)
{
Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
if (numPawns == 0)
{
return MIN_CHANCES;
}
else if (kamikazeSac)
{
if (pieceIsPresent(position, (Piece) (BISHOP | oppColor)) ||
pieceIsPresent(position, (Piece) (ROOK | oppColor)))
{
return 4;
}
else
{
return 12;
}
}
else if ((pawns & nonA & nonH) != EMPTY_BITBOARD)
{
return 16;
}
else /* Check for advanced border pawns: */
{
const Square pawnSquare = getNextSquare(&pawns);
const int promotionRank = (color == WHITE ? RANK_8 : RANK_1);
const Square promotionSquare =
getSquare(file(pawnSquare), promotionRank);
assert(pawnSquare != NO_SQUARE);
assert(file(pawnSquare) == FILE_A ||
file(pawnSquare) == FILE_H);
if (distance(pawnSquare, promotionSquare) == 1 &&
distance(position->king[oppColor], promotionSquare) <= 1)
{
assert((color == WHITE && rank(pawnSquare) == RANK_7) ||
(color == BLACK && rank(pawnSquare) == RANK_2));
return MIN_CHANCES;
}
}
}
}
}
return 16;
}
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;
ITERATE_BITBOARD(&pieces, square)
{
const PieceType pieceType = pieceType(position->piece[square]);
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;
}
}
if (position->piecesOfType[WHITE_BISHOP] != EMPTY_BITBOARD)
{
evaluateWhiteTrappedBishops(position, base);
}
if (position->piecesOfType[BLACK_BISHOP] != EMPTY_BITBOARD)
{
evaluateBlackTrappedBishops(position, base);
}
}
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, 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) + 10 * cornerDistanceMalus;
}
INLINE static int getPositionalValue(Position * position,
EvaluationBase * base)
{
int value, openingValue, endgameValue;
const int pi = phaseIndex(position);
#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;
#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
#ifdef CALCULATE_TARGETS
base->pieceAttacks[WHITE] = base->pieceAttacks[BLACK] = EMPTY_BITBOARD;
#endif
if ((base->evaluateKingSafety[WHITE] =
kingSafetyEvalRequired(position, WHITE)) != FALSE)
{
base->kingAttackSquares[WHITE] = getKingMoves(position->king[WHITE]);
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)
{
base->kingAttackSquares[BLACK] = getKingMoves(position->king[BLACK]);
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);
if (base->passedPawns[WHITE] != EMPTY_BITBOARD ||
base->passedPawns[BLACK] != EMPTY_BITBOARD)
{
evaluatePassedPawns(position, base);
}
if (base->evaluateKingSafety[WHITE])
{
base->openingPoints[WHITE] -= getKingSafetyMalus(position, base, WHITE);
}
if (base->evaluateKingSafety[BLACK])
{
base->openingPoints[BLACK] -= getKingSafetyMalus(position, base, BLACK);
}
#ifndef INCLUDE_TABLEBASE_ACCESS
{
Color color;
for (color = WHITE; color <= BLACK; color++)
{
if (evaluateKingChase(position, color))
{
const int kingChaseMalus = getKingChaseMalus(position, color);
base->openingPoints[color] -= kingChaseMalus;
base->endgamePoints[color] -= kingChaseMalus;
}
}
}
#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
openingValue = base->openingPoints[WHITE] - base->openingPoints[BLACK];
endgameValue = base->endgamePoints[WHITE] - base->endgamePoints[BLACK];
value = (openingValue * (256 - pi) + endgameValue * pi) / 256;
return value;
}
int getValue(Position * position, const int alpha, const int beta,
PawnHashInfo * pawnHashtable,
KingSafetyHashInfo * kingsafetyHashtable)
{
const int MAX_DELTA = 200;
EvaluationBase base;
int value, lazyValue, chances = 16;
Color winningColor;
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);
winningColor = (value > 0 ?
position->activeColor : opponent(position->activeColor));
if (numberOfNonPawnPieces(position, winningColor) <= 4)
{
chances = getWinningChances(position, winningColor);
}
lazyValue = (value * chances) / 16;
#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 - MAX_DELTA && lazyValue <= beta + MAX_DELTA))
{
int positionalValue;
Color effectiveWinningColor;
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
}
positionalValue = getPositionalValue(position, &base);
value += (position->activeColor == WHITE ?
positionalValue : -positionalValue);
effectiveWinningColor = (value > 0 ?
position->activeColor :
opponent(position->activeColor));
if (effectiveWinningColor != winningColor)
{
chances =
(numberOfNonPawnPieces(position, effectiveWinningColor) <= 4 ?
getWinningChances(position, effectiveWinningColor) : 16);
}
}
return (value * chances) / 16;
}
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);
}
}
}
}
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] = 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);
}
}
}
}
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] = 7 - dDark + dStandard;
kingChaseMalus[LIGHT][square] = 7 - dLight + dStandard;
kingChaseMalus[ALL][square] = 10 - min(dDark, dLight);
}
/*
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]); */
}
return 0;
}
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;
debugOutput = 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);
debugOutput = debugFlag;
}
return (bool) (v1 == v2);
}
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;
}
*/
static int testWinningChancesCalculations()
{
Position position;
clearPosition(&position);
position.piece[E1] = WHITE_KING;
position.piece[E8] = BLACK_KING;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) == 0);
assert(getWinningChances(&position, BLACK) == 0);
position.piece[A8] = BLACK_KNIGHT;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) == 1);
position.piece[A8] = BLACK_BISHOP;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) == 1);
position.piece[A8] = BLACK_ROOK;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) > 0);
position.piece[A8] = WHITE_QUEEN;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) > 0);
position.piece[A8] = NO_PIECE;
position.piece[B1] = WHITE_KNIGHT;
position.piece[G1] = WHITE_KNIGHT;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) == 1);
position.piece[A7] = BLACK_PAWN;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) > 0);
position.piece[B8] = BLACK_KNIGHT;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) <= 4);
position.piece[B2] = WHITE_KNIGHT;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) > 0);
clearPosition(&position);
position.piece[E1] = WHITE_KING;
position.piece[E8] = BLACK_KING;
position.piece[C1] = WHITE_BISHOP;
position.piece[F1] = WHITE_BISHOP;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) > 0);
position.piece[F1] = NO_PIECE;
position.piece[G1] = WHITE_BISHOP;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) == 1);
position.piece[A2] = WHITE_PAWN;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) > 0);
position.piece[E8] = NO_PIECE;
position.piece[B8] = BLACK_KING;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) == 1);
position.piece[A2] = NO_PIECE;
position.piece[H2] = WHITE_PAWN;
position.piece[B8] = NO_PIECE;
position.piece[H8] = BLACK_KING;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) > 0);
clearPosition(&position);
position.piece[E1] = WHITE_KING;
position.piece[E8] = BLACK_KING;
position.piece[C7] = BLACK_BISHOP;
position.piece[F7] = BLACK_BISHOP;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) > 0);
position.piece[F7] = NO_PIECE;
position.piece[G7] = BLACK_BISHOP;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) == 1);
position.piece[H4] = BLACK_PAWN;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) > 0);
position.piece[E1] = NO_PIECE;
position.piece[H2] = WHITE_KING;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) == 1);
position.piece[H4] = NO_PIECE;
position.piece[G4] = BLACK_PAWN;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) > 0);
position.piece[G4] = NO_PIECE;
position.piece[A4] = BLACK_PAWN;
position.piece[H2] = NO_PIECE;
position.piece[A2] = WHITE_KING;
initializePosition(&position);
assert(getWinningChances(&position, BLACK) > 0);
clearPosition(&position);
position.piece[F1] = WHITE_KING;
position.piece[G7] = BLACK_KING;
position.piece[H2] = WHITE_PAWN;
position.piece[H3] = WHITE_PAWN;
position.piece[H4] = WHITE_PAWN;
position.piece[D5] = WHITE_BISHOP;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) == 1);
position.piece[D5] = NO_PIECE;
position.piece[D6] = WHITE_BISHOP;
initializePosition(&position);
assert(getWinningChances(&position, WHITE) == 16);
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;
}
*/
if ((result = testWinningChancesCalculations()) != 0)
{
return result;
}
return 0;
}