/* Protector -- a UCI chess engine Copyright (C) 2008 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 . */ #ifndef _evaluation_h_ #define _evaluation_h_ #include "position.h" #include "bitboard.h" #include "keytable.h" extern const int PAWN_VALUE_OPENING; extern const int PAWN_VALUE_ENDGAME; #define WHITE_BISHOP_LIGHT 0x01 #define WHITE_BISHOP_DARK 0x02 #define BLACK_BISHOP_LIGHT 0x04 #define BLACK_BISHOP_DARK 0x08 #define WHITE_BISHOP_PAIR 0x03 #define BLACK_BISHOP_PAIR 0x0C typedef struct { Bitboard upwardRealm[2]; Bitboard downwardRealm[2]; Bitboard pawnAttackableSquares[2]; Bitboard pawnProtectedSquares[2]; Bitboard doubledPawns[2]; Bitboard passedPawns[2]; Bitboard candidatePawns[2]; #ifdef BONUS_HIDDEN_PASSER Bitboard hiddenCandidatePawns[2]; bool hasPassersOrCandidates[2]; #endif Bitboard weakPawns[2]; Bitboard fixedPawns[2]; Bitboard countedSquares[2]; Bitboard weakOutpostSquares[2]; KingAttacks *kingAttacks[2]; Bitboard kingAttackSquares[2]; #ifdef CALCULATE_TARGETS Bitboard pieceAttacks[2]; #endif int numAttackers[2]; int attackPoints[2]; int spaceAttackPoints[2]; int openingPoints[2], endgamePoints[2]; bool evaluateKingSafety[2]; KingSafetyHashInfo *kingsafetyHashtable; } EvaluationBase; extern const int PHASE_MAX; /** * Calculate the weight of the non-pawn-pieces of the specified color. */ INLINE int getMaterialValue(const Position * position, const Color color) { const int VALUE_SMALL_PIECE = 300; const int ROOK_DIFF = 500 - VALUE_SMALL_PIECE; const int QUEEN_DIFF = 950 - VALUE_SMALL_PIECE; const int numNonPawnPieces = numberOfNonPawnPieces(position, color) - 1; const int numRooks = getPieceCount(position, (Piece) (ROOK | color)); const int numQueens = getPieceCount(position, (Piece) (QUEEN | color)); return numQueens * QUEEN_DIFF + numRooks * ROOK_DIFF + numNonPawnPieces * VALUE_SMALL_PIECE + position->numberOfPawns[color] * 100; } /** * Calculate the weight of the non-pawn-pieces of the specified color. */ INLINE int getPieceValue(const Position * position, const Color color) { const int VALUE_SMALL_PIECE = 300; const int ROOK_DIFF = 500 - VALUE_SMALL_PIECE; const int QUEEN_DIFF = 950 - VALUE_SMALL_PIECE; const int numNonPawnPieces = numberOfNonPawnPieces(position, color) - 1; const int numRooks = getPieceCount(position, (Piece) (ROOK | color)); const int numQueens = getPieceCount(position, (Piece) (QUEEN | color)); return numQueens * QUEEN_DIFF + numRooks * ROOK_DIFF + numNonPawnPieces * VALUE_SMALL_PIECE; } /** * Calculate the weight of the non-pawn-pieces of the specified color. * * @return a value in the range [0-44] */ INLINE int getPieceWeight(const Position * position, const Color color) { const int numNonPawnPieces = numberOfNonPawnPieces(position, color) - 1; const int numRooks = getPieceCount(position, (Piece) (ROOK | color)); const int numQueens = getPieceCount(position, (Piece) (QUEEN | color)); return 3 * numQueens + numRooks + numNonPawnPieces; } /** * Calculate the value of the non-pawn-pieces of the specified color. * * @return a centipawn value */ INLINE int getOpeningPieceWeight(const Position * position, const Color color) { return position->openingValue[color] - PAWN_VALUE_OPENING * position->numberOfPawns[color]; } /** * Calculate the phase index of the specified position. * * @return a value in the range [0(initial position)-256(endgame)] */ INLINE int phaseIndex(const Position * position) { const int basicPhase = max(0, PHASE_MAX - getPieceWeight(position, WHITE) - getPieceWeight(position, BLACK)); assert(getPieceWeight(position, WHITE) >= 0); assert(getPieceWeight(position, WHITE) <= 44); assert(getPieceWeight(position, BLACK) >= 0); assert(getPieceWeight(position, BLACK) <= 44); assert(basicPhase >= 0); assert(basicPhase <= PHASE_MAX); return (basicPhase * 256 + (PHASE_MAX / 2)) / PHASE_MAX; } INLINE bool hasBishopPair(const Position * position, const Color color) { const Bitboard *bishops = &position->piecesOfType[(Piece) (BISHOP | color)]; return (bool) ((lightSquares & *bishops) != EMPTY_BITBOARD && (darkSquares & *bishops) != EMPTY_BITBOARD); } #define VALUE_TEMPO_OPENING 20 #define VALUE_TEMPO_ENDGAME 10 /** * Calculate a rough value of the specified position, * based on the current pst-values and the specified evaluation base. * * @return the value of the specified position */ INLINE int positionalBalance(const Position * position, EvaluationBase * base) { int openingValue = (base->openingPoints[WHITE] - base->openingPoints[BLACK] + position->openingValue[WHITE] - position->openingValue[BLACK]); int endgameValue = (base->endgamePoints[WHITE] - base->endgamePoints[BLACK] + position->endgameValue[WHITE] - position->endgameValue[BLACK]); const int pi = phaseIndex(position); int value; assert(pi >= 0 && pi <= 256); if (hasBishopPair(position, WHITE)) { openingValue += VALUE_BISHOP_PAIR_OPENING; endgameValue += VALUE_BISHOP_PAIR_ENDGAME; } if (hasBishopPair(position, BLACK)) { openingValue -= VALUE_BISHOP_PAIR_OPENING; endgameValue -= VALUE_BISHOP_PAIR_ENDGAME; } if (position->activeColor == WHITE) { openingValue += VALUE_TEMPO_OPENING; endgameValue += VALUE_TEMPO_ENDGAME; } else { openingValue -= VALUE_TEMPO_OPENING; endgameValue -= VALUE_TEMPO_ENDGAME; } value = (openingValue * (256 - pi) + endgameValue * pi) / 256; return (position->activeColor == WHITE ? value : -value); } /** * Calculate a rough value of the specified position, * based on the current pst-values. * * @return the value of the specified position */ INLINE int basicPositionalBalance(Position * position) { int openingValue = (position->openingValue[WHITE] - position->openingValue[BLACK]); int endgameValue = (position->endgameValue[WHITE] - position->endgameValue[BLACK]); const int pi = phaseIndex(position); int value; assert(pi >= 0 && pi <= 256); if (hasBishopPair(position, WHITE)) { openingValue += VALUE_BISHOP_PAIR_OPENING; endgameValue += VALUE_BISHOP_PAIR_ENDGAME; } if (hasBishopPair(position, BLACK)) { openingValue -= VALUE_BISHOP_PAIR_OPENING; endgameValue -= VALUE_BISHOP_PAIR_ENDGAME; } if (position->activeColor == WHITE) { openingValue += VALUE_TEMPO_OPENING; endgameValue += VALUE_TEMPO_ENDGAME; } else { openingValue -= VALUE_TEMPO_OPENING; endgameValue -= VALUE_TEMPO_ENDGAME; } value = (openingValue * (256 - pi) + endgameValue * pi) / 256; return (position->activeColor == WHITE ? value : -value); } /** * Calculate the value of the specified position. * * @return the value of the specified position */ int getValue(Position * position, const int alpha, const int beta, PawnHashInfo * pawnHashtable, KingSafetyHashInfo * kingsafetyHashtable); /** * Check if the specified color can win the specified position. * * @return FALSE if the specified color doesn't have sufficient material * left to win the position */ INLINE bool hasWinningPotential(Position * position, Color color) { return (bool) (position->numberOfPieces[color] > 1); } /** * Check if the pawn at the specified square is a passed pawn. */ bool pawnIsPassed(const Position * position, const Square pawnSquare); /** * Reset the pawn hashtable. */ void resetPawnHashtable(void); /** * Flip the given position and check if it yields the same result. * * @return FALSE if the flipped position yields a diffent result */ bool flipTest(Position * position, PawnHashInfo * pawnHashtable, KingSafetyHashInfo * kingsafetyHashtable); /** * Initialize this module. * * @return 0 if no errors occurred. */ int initializeModuleEvaluation(void); /** * Test this module. * * @return 0 if all tests succeed. */ int testModuleEvaluation(void); /** * Get the king safety hash value for the given king square. */ INLINE Bitboard getKingPawnSafetyHashValue(const Position * position, const Color color) { const int mask[2] = { WHITE_00 | WHITE_000 | 16, BLACK_00 | BLACK_000 | 32 }; const int index = (position->castlingRights | 48) & mask[color]; return position->pawnHashValue ^ GENERATED_KEYTABLE[color][position->king[color]] ^ GENERATED_KEYTABLE[2][index]; } INLINE bool piecesAreBalanced(const Position * position) { return (bool) (getPieceCount(position, WHITE_QUEEN) == getPieceCount(position, BLACK_QUEEN) && getPieceCount(position, WHITE_ROOK) == getPieceCount(position, BLACK_ROOK) && getPieceCount(position, WHITE_BISHOP) == getPieceCount(position, BLACK_BISHOP) && getPieceCount(position, WHITE_KNIGHT) == getPieceCount(position, BLACK_KNIGHT)); } INLINE int getPawnWidth(const Position * position, const Color color) { const Bitboard tmp = position->piecesOfType[(Piece) (PAWN | color)] | minValue[position->king[opponent(color)]]; return getWidth(tmp); } INLINE int getPassedPawnWidth(const Position * position, const EvaluationBase * base, const Color color) { const Bitboard tmp = base->passedPawns[color] | minValue[position->king[opponent(color)]]; return getWidth(tmp); } #endif