Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 99 | pmbaty | 1 | /* |
| 2 | Texel - A UCI chess engine. |
||
| 3 | Copyright (C) 2012-2014 Peter Ă–sterlund, peterosterlund2@gmail.com |
||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify |
||
| 6 | it under the terms of the GNU General Public License as published by |
||
| 7 | the Free Software Foundation, either version 3 of the License, or |
||
| 8 | (at your option) any later version. |
||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, |
||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 13 | GNU General Public License for more details. |
||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License |
||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
| 17 | */ |
||
| 18 | |||
| 19 | /* |
||
| 20 | * evaluate.hpp |
||
| 21 | * |
||
| 22 | * Created on: Feb 25, 2012 |
||
| 23 | * Author: petero |
||
| 24 | */ |
||
| 25 | |||
| 26 | #ifndef EVALUATE_HPP_ |
||
| 27 | #define EVALUATE_HPP_ |
||
| 28 | |||
| 29 | #include "parameters.hpp" |
||
| 30 | #include "piece.hpp" |
||
| 31 | #include "position.hpp" |
||
| 32 | #include "util/alignedAlloc.hpp" |
||
| 33 | |||
| 34 | class EvaluateTest; |
||
| 35 | |||
| 36 | /** Position evaluation routines. */ |
||
| 37 | class Evaluate { |
||
| 38 | friend class EvaluateTest; |
||
| 39 | private: |
||
| 40 | struct PawnHashData { |
||
| 41 | PawnHashData(); |
||
| 42 | U64 key; |
||
| 43 | S16 current; // For hash replacement policy |
||
| 44 | S16 score; // Positive score means good for white |
||
| 45 | S16 passedBonusW; |
||
| 46 | S16 passedBonusB; |
||
| 47 | U64 passedPawns; // The most advanced passed pawns for each file |
||
| 48 | // Contains both white and black pawns |
||
| 49 | U64 outPostsW; // Possible outpost squares for white |
||
| 50 | U64 outPostsB; |
||
| 51 | U64 stalePawns; // Pawns that can not be used for "pawn breaks" |
||
| 52 | }; |
||
| 53 | |||
| 54 | struct MaterialHashData { |
||
| 55 | MaterialHashData(); |
||
| 56 | int id; |
||
| 57 | int score; |
||
| 58 | S16 wPawnIPF, bPawnIPF; |
||
| 59 | S16 wKnightIPF, bKnightIPF; |
||
| 60 | S16 castleIPF, queenIPF; |
||
| 61 | S16 wPassedPawnIPF, bPassedPawnIPF; |
||
| 62 | S16 kingSafetyIPF; |
||
| 63 | S16 diffColorBishopIPF; |
||
| 64 | S16 wKnightOutPostIPF, bKnightOutPostIPF; |
||
| 65 | U8 endGame; |
||
| 66 | }; |
||
| 67 | |||
| 68 | struct KingSafetyHashData { |
||
| 69 | KingSafetyHashData(); |
||
| 70 | U64 key; |
||
| 71 | int score; |
||
| 72 | S16 current; // For hash replacement policy |
||
| 73 | }; |
||
| 74 | |||
| 75 | public: |
||
| 76 | struct EvalHashTables { |
||
| 77 | EvalHashTables(); |
||
| 78 | std::vector<PawnHashData> pawnHash; |
||
| 79 | std::vector<MaterialHashData> materialHash; |
||
| 80 | vector_aligned<KingSafetyHashData> kingSafetyHash; |
||
| 81 | }; |
||
| 82 | |||
| 83 | /** Constructor. */ |
||
| 84 | Evaluate(EvalHashTables& et); |
||
| 85 | |||
| 86 | static int pieceValueOrder[Piece::nPieceTypes]; |
||
| 87 | |||
| 88 | static const int* psTab1[Piece::nPieceTypes]; |
||
| 89 | static const int* psTab2[Piece::nPieceTypes]; |
||
| 90 | |||
| 91 | /** Get evaluation hash tables. */ |
||
| 92 | static std::shared_ptr<EvalHashTables> getEvalHashTables(); |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Static evaluation of a position. |
||
| 96 | * @param pos The position to evaluate. |
||
| 97 | * @return The evaluation score, measured in centipawns. |
||
| 98 | * Positive values are good for the side to make the next move. |
||
| 99 | */ |
||
| 100 | int evalPos(const Position& pos); |
||
| 101 | int evalPosPrint(const Position& pos); |
||
| 102 | |||
| 103 | /** Compute "swindle" score corresponding to an evaluation score when |
||
| 104 | * the position is a known TB draw. */ |
||
| 105 | static int swindleScore(int evalScore); |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Interpolate between (x1,y1) and (x2,y2). |
||
| 109 | * If x < x1, return y1, if x > x2 return y2. Otherwise, use linear interpolation. |
||
| 110 | */ |
||
| 111 | static int interpolate(int x, int x1, int y1, int x2, int y2); |
||
| 112 | |||
| 113 | static const int IPOLMAX = 1024; |
||
| 114 | |||
| 115 | /** Compute v1 + (v2-v1)*k/IPOLMAX */ |
||
| 116 | static int interpolate(int v1, int v2, int k); |
||
| 117 | |||
| 118 | static void staticInitialize(); |
||
| 119 | static void updateEvalParams(); |
||
| 120 | |||
| 121 | private: |
||
| 122 | template <bool print> int evalPos(const Position& pos); |
||
| 123 | |||
| 124 | /** Compute score based on piece square tables. Positive values are good for white. */ |
||
| 125 | int pieceSquareEval(const Position& pos); |
||
| 126 | |||
| 127 | /** Get material score */ |
||
| 128 | int materialScore(const Position& pos, bool print); |
||
| 129 | |||
| 130 | /** Compute material score. */ |
||
| 131 | void computeMaterialScore(const Position& pos, MaterialHashData& mhd, bool print) const; |
||
| 132 | |||
| 133 | /** Implement the "when ahead trade pieces, when behind trade pawns" rule. */ |
||
| 134 | int tradeBonus(const Position& pos, int wCorr, int bCorr) const; |
||
| 135 | |||
| 136 | /** Score castling ability. */ |
||
| 137 | int castleBonus(const Position& pos); |
||
| 138 | |||
| 139 | PawnHashData& getPawnHashEntry(std::vector<PawnHashData>& pawnHash, U64 key); |
||
| 140 | int pawnBonus(const Position& pos); |
||
| 141 | |||
| 142 | /** Compute set of pawns that can not participate in "pawn breaks". */ |
||
| 143 | static U64 computeStalePawns(const Position& pos); |
||
| 144 | |||
| 145 | /** Compute pawn hash data for pos. */ |
||
| 146 | void computePawnHashData(const Position& pos, PawnHashData& ph); |
||
| 147 | |||
| 148 | /** Compute rook bonus. Rook on open/half-open file. */ |
||
| 149 | int rookBonus(const Position& pos); |
||
| 150 | |||
| 151 | /** Compute bishop evaluation. */ |
||
| 152 | int bishopEval(const Position& pos, int oldScore); |
||
| 153 | |||
| 154 | /** Compute knight evaluation. */ |
||
| 155 | int knightEval(const Position& pos); |
||
| 156 | |||
| 157 | /** Bonus for threatening opponent pieces. */ |
||
| 158 | int threatBonus(const Position& pos); |
||
| 159 | |||
| 160 | /** Bonus for own pieces protected by pawns. */ |
||
| 161 | int protectBonus(const Position& pos); |
||
| 162 | |||
| 163 | /** Compute king safety for both kings. */ |
||
| 164 | int kingSafety(const Position& pos); |
||
| 165 | |||
| 166 | KingSafetyHashData& getKingSafetyHashEntry(vector_aligned<KingSafetyHashData>& ksHash, U64 key); |
||
| 167 | int kingSafetyKPPart(const Position& pos); |
||
| 168 | |||
| 169 | static int castleMaskFactor[256]; |
||
| 170 | static int knightMobScoreA[64][9]; |
||
| 171 | static U64 knightKingProtectPattern[64]; |
||
| 172 | static U64 bishopKingProtectPattern[64]; |
||
| 173 | |||
| 174 | std::vector<PawnHashData>& pawnHash; |
||
| 175 | const PawnHashData* phd; |
||
| 176 | |||
| 177 | std::vector<MaterialHashData>& materialHash; |
||
| 178 | const MaterialHashData* mhd; |
||
| 179 | |||
| 180 | vector_aligned<KingSafetyHashData>& kingSafetyHash; |
||
| 181 | |||
| 182 | // King safety variables |
||
| 183 | U64 wKingZone, bKingZone; // Squares close to king that are worth attacking |
||
| 184 | int wKingAttacks, bKingAttacks; // Number of attacks close to white/black king |
||
| 185 | U64 wAttacksBB, bAttacksBB; |
||
| 186 | U64 wPawnAttacks, bPawnAttacks; // Squares attacked by white/black pawns |
||
| 187 | }; |
||
| 188 | |||
| 189 | |||
| 190 | inline |
||
| 191 | Evaluate::PawnHashData::PawnHashData() |
||
| 192 | : key((U64)-1), // Non-zero to avoid collision for positions with no pawns |
||
| 193 | current(0), score(0), |
||
| 194 | passedBonusW(0), |
||
| 195 | passedBonusB(0), |
||
| 196 | passedPawns(0) { |
||
| 197 | } |
||
| 198 | |||
| 199 | inline |
||
| 200 | Evaluate::MaterialHashData::MaterialHashData() |
||
| 201 | : id(-1), score(0) { |
||
| 202 | } |
||
| 203 | |||
| 204 | inline |
||
| 205 | Evaluate::KingSafetyHashData::KingSafetyHashData() |
||
| 206 | : key((U64)-1), score(0), current(0) { |
||
| 207 | } |
||
| 208 | |||
| 209 | inline |
||
| 210 | Evaluate::EvalHashTables::EvalHashTables() { |
||
| 211 | pawnHash.resize(1<<16); |
||
| 212 | kingSafetyHash.resize(1 << 15); |
||
| 213 | materialHash.resize(1 << 14); |
||
| 214 | } |
||
| 215 | |||
| 216 | inline int |
||
| 217 | Evaluate::interpolate(int x, int x1, int y1, int x2, int y2) { |
||
| 218 | if (x > x2) { |
||
| 219 | return y2; |
||
| 220 | } else if (x < x1) { |
||
| 221 | return y1; |
||
| 222 | } else { |
||
| 223 | return (x - x1) * (y2 - y1) / (x2 - x1) + y1; |
||
| 224 | } |
||
| 225 | } |
||
| 226 | |||
| 227 | inline int |
||
| 228 | Evaluate::interpolate(int v1, int v2, int k) { |
||
| 229 | return v1 + (v2 - v1) * k / IPOLMAX; |
||
| 230 | } |
||
| 231 | |||
| 232 | inline int |
||
| 233 | Evaluate::materialScore(const Position& pos, bool print) { |
||
| 234 | int mId = pos.materialId(); |
||
| 235 | int key = (mId >> 16) * 40507 + mId; |
||
| 236 | MaterialHashData& newMhd = materialHash[key & (materialHash.size() - 1)]; |
||
| 237 | if ((newMhd.id != mId) || print) |
||
| 238 | computeMaterialScore(pos, newMhd, print); |
||
| 239 | mhd = &newMhd; |
||
| 240 | return newMhd.score; |
||
| 241 | } |
||
| 242 | |||
| 243 | inline Evaluate::PawnHashData& |
||
| 244 | Evaluate::getPawnHashEntry(std::vector<Evaluate::PawnHashData>& pawnHash, U64 key) { |
||
| 245 | int e0 = (int)key & (pawnHash.size() - 2); |
||
| 246 | int e1 = e0 + 1; |
||
| 247 | if (pawnHash[e0].key == key) { |
||
| 248 | pawnHash[e0].current = 1; |
||
| 249 | pawnHash[e1].current = 0; |
||
| 250 | return pawnHash[e0]; |
||
| 251 | } |
||
| 252 | if (pawnHash[e1].key == key) { |
||
| 253 | pawnHash[e1].current = 1; |
||
| 254 | pawnHash[e0].current = 0; |
||
| 255 | return pawnHash[e1]; |
||
| 256 | } |
||
| 257 | if (pawnHash[e0].current) { |
||
| 258 | pawnHash[e1].current = 1; |
||
| 259 | pawnHash[e0].current = 0; |
||
| 260 | return pawnHash[e1]; |
||
| 261 | } else { |
||
| 262 | pawnHash[e0].current = 1; |
||
| 263 | pawnHash[e1].current = 0; |
||
| 264 | return pawnHash[e0]; |
||
| 265 | } |
||
| 266 | } |
||
| 267 | |||
| 268 | inline Evaluate::KingSafetyHashData& |
||
| 269 | Evaluate::getKingSafetyHashEntry(vector_aligned<Evaluate::KingSafetyHashData>& ksHash, U64 key) { |
||
| 270 | int e0 = (int)key & (ksHash.size() - 2); |
||
| 271 | int e1 = e0 + 1; |
||
| 272 | if (ksHash[e0].key == key) { |
||
| 273 | ksHash[e0].current = 1; |
||
| 274 | ksHash[e1].current = 0; |
||
| 275 | return ksHash[e0]; |
||
| 276 | } |
||
| 277 | if (ksHash[e1].key == key) { |
||
| 278 | ksHash[e1].current = 1; |
||
| 279 | ksHash[e0].current = 0; |
||
| 280 | return ksHash[e1]; |
||
| 281 | } |
||
| 282 | if (ksHash[e0].current) { |
||
| 283 | ksHash[e1].current = 1; |
||
| 284 | ksHash[e0].current = 0; |
||
| 285 | return ksHash[e1]; |
||
| 286 | } else { |
||
| 287 | ksHash[e0].current = 1; |
||
| 288 | ksHash[e1].current = 0; |
||
| 289 | return ksHash[e0]; |
||
| 290 | } |
||
| 291 | } |
||
| 292 | |||
| 293 | #endif /* EVALUATE_HPP_ */ |