Protector Code
Brought to you by:
raimundheid
--- a +++ b/evaluation.h @@ -0,0 +1,355 @@ +/* + 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 <http://www.gnu.org/licenses/>. + +*/ + +#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