Rev 96 | Rev 169 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 96 | Rev 154 | ||
|---|---|---|---|
| Line 20... | Line 20... | ||
| 20 | 20 | ||
| 21 | #include <algorithm> |
21 | #include <algorithm> |
| 22 | #include <cassert> |
22 | #include <cassert> |
| 23 | 23 | ||
| 24 | #include "bitboard.h" |
24 | #include "bitboard.h" |
| 25 | #include "bitcount.h" |
- | |
| 26 | #include "pawns.h" |
25 | #include "pawns.h" |
| 27 | #include "position.h" |
26 | #include "position.h" |
| 28 | #include "thread.h" |
27 | #include "thread.h" |
| 29 | 28 | ||
| 30 | namespace { |
29 | namespace { |
| 31 | 30 | ||
| 32 | #define V Value |
31 | #define V Value |
| 33 | #define S(mg, eg) make_score(mg, eg) |
32 | #define S(mg, eg) make_score(mg, eg) |
| 34 | 33 | ||
| 35 | // Isolated pawn penalty by opposed flag |
34 | // Isolated pawn penalty by opposed flag |
| 36 | const Score Isolated[2][FILE_NB] = { |
- | |
| 37 | { S(31, 36), S(45, 41), S(50, 41), S(50, 41), |
- | |
| 38 |
|
35 | const Score Isolated[2] = { S(45, 40), S(30, 27) }; |
| 39 | { S(21, 24), S(30, 28), S(33, 28), S(33, 28), |
- | |
| 40 | S(33, 28), S(33, 28), S(30, 28), S(21, 24) } }; |
- | |
| 41 | 36 | ||
| 42 | // Backward pawn penalty by opposed flag |
37 | // Backward pawn penalty by opposed flag |
| 43 | const Score Backward[2] = { S(56, 33), S(41, 19) }; |
38 | const Score Backward[2] = { S(56, 33), S(41, 19) }; |
| 44 | 39 | ||
| 45 | // Unsupported pawn penalty for pawns which are neither isolated or |
40 | // Unsupported pawn penalty for pawns which are neither isolated or backward |
| 46 | // by number of pawns it supports [less than 2 / exactly 2]. |
- | |
| 47 | const Score Unsupported |
41 | const Score Unsupported = S(17, 8); |
| 48 | 42 | ||
| 49 | // Connected pawn bonus by opposed, phalanx, twice supported and rank |
43 | // Connected pawn bonus by opposed, phalanx, twice supported and rank |
| 50 | Score Connected[2][2][2][RANK_NB]; |
44 | Score Connected[2][2][2][RANK_NB]; |
| 51 | 45 | ||
| 52 | // Doubled pawn penalty |
46 | // Doubled pawn penalty |
| 53 | const Score Doubled |
47 | const Score Doubled = S(18,38); |
| 54 | S(11, 34), S(17, 38), S(19, 38), S(19, 38), |
- | |
| 55 | S(19, 38), S(19, 38), S(17, 38), S(11, 34) }; |
- | |
| 56 | 48 | ||
| 57 | // Lever bonus by rank |
49 | // Lever bonus by rank |
| 58 | const Score Lever[RANK_NB] = { |
50 | const Score Lever[RANK_NB] = { |
| 59 | S( 0, 0), S( 0, 0), S(0, 0), S(0, 0), |
51 | S( 0, 0), S( 0, 0), S(0, 0), S(0, 0), |
| 60 | S(17, 16), S(33, 32), S(0, 0), S(0, 0) |
52 | S(17, 16), S(33, 32), S(0, 0), S(0, 0) |
| - | 53 | }; |
|
| 61 | 54 | ||
| 62 | // Weakness of our pawn shelter in front of the king by [distance from edge][rank] |
55 | // Weakness of our pawn shelter in front of the king by [distance from edge][rank] |
| 63 | const Value ShelterWeakness[][RANK_NB] = { |
56 | const Value ShelterWeakness[][RANK_NB] = { |
| 64 | { V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) }, |
57 | { V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) }, |
| 65 | { V(120), V( 0), V(28), V(76), V(88), V(103), V(104) }, |
58 | { V(120), V( 0), V(28), V(76), V(88), V(103), V(104) }, |
| 66 | { V(101), V( 7), V(54), V(78), V(77), V( 92), V(101) }, |
59 | { V(101), V( 7), V(54), V(78), V(77), V( 92), V(101) }, |
| 67 | { V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) } |
60 | { V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) } |
| - | 61 | }; |
|
| 68 | 62 | ||
| 69 | // Danger of enemy pawns moving toward our king by [type][distance from edge][rank] |
63 | // Danger of enemy pawns moving toward our king by [type][distance from edge][rank] |
| 70 | const Value StormDanger[][4][RANK_NB] = { |
64 | const Value StormDanger[][4][RANK_NB] = { |
| 71 | { { V( 0), V( 67), V( 134), V(38), V(32) }, |
65 | { { V( 0), V( 67), V( 134), V(38), V(32) }, |
| 72 | { V( 0), V( 57), V( 139), V(37), V(22) }, |
66 | { V( 0), V( 57), V( 139), V(37), V(22) }, |
| Line 81... | Line 75... | ||
| 81 | { V( 0), V( 0), V( 160), V(22), V( 5) }, |
75 | { V( 0), V( 0), V( 160), V(22), V( 5) }, |
| 82 | { V( 0), V( 0), V( 166), V(24), V(13) } }, |
76 | { V( 0), V( 0), V( 166), V(24), V(13) } }, |
| 83 | { { V( 0), V(-283), V(-281), V(57), V(31) }, |
77 | { { V( 0), V(-283), V(-281), V(57), V(31) }, |
| 84 | { V( 0), V( 58), V( 141), V(39), V(18) }, |
78 | { V( 0), V( 58), V( 141), V(39), V(18) }, |
| 85 | { V( 0), V( 65), V( 142), V(48), V(32) }, |
79 | { V( 0), V( 65), V( 142), V(48), V(32) }, |
| 86 | { V( 0), V( 60), V( 126), V(51), V(19) } } |
80 | { V( 0), V( 60), V( 126), V(51), V(19) } } |
| - | 81 | }; |
|
| 87 | 82 | ||
| 88 | // Max bonus for king safety. Corresponds to start position with all the pawns |
83 | // Max bonus for king safety. Corresponds to start position with all the pawns |
| 89 | // in front of the king and no enemy pawn on the horizon. |
84 | // in front of the king and no enemy pawn on the horizon. |
| 90 | const Value MaxSafetyBonus = V(258); |
85 | const Value MaxSafetyBonus = V(258); |
| 91 | 86 | ||
| Line 93... | Line 88... | ||
| 93 | #undef V |
88 | #undef V |
| 94 | 89 | ||
| 95 | template<Color Us> |
90 | template<Color Us> |
| 96 | Score evaluate(const Position& pos, Pawns::Entry* e) { |
91 | Score evaluate(const Position& pos, Pawns::Entry* e) { |
| 97 | 92 | ||
| 98 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
93 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
| 99 | const Square Up = (Us == WHITE ? |
94 | const Square Up = (Us == WHITE ? NORTH : SOUTH); |
| 100 | const Square Right = (Us == WHITE ? |
95 | const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); |
| 101 | const Square Left = (Us == WHITE ? |
96 | const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); |
| 102 | 97 | ||
| 103 | Bitboard b, neighbours, doubled, supported, phalanx; |
98 | Bitboard b, neighbours, stoppers, doubled, supported, phalanx; |
| 104 | Square s; |
99 | Square s; |
| 105 | bool |
100 | bool opposed, lever, connected, backward; |
| 106 | Score score = SCORE_ZERO; |
101 | Score score = SCORE_ZERO; |
| 107 | const Square* pl = pos.squares<PAWN>(Us); |
102 | const Square* pl = pos.squares<PAWN>(Us); |
| 108 | const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)]; |
103 | const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)]; |
| 109 | 104 | ||
| 110 | Bitboard ourPawns = pos.pieces(Us , PAWN); |
105 | Bitboard ourPawns = pos.pieces(Us , PAWN); |
| 111 | Bitboard theirPawns = pos.pieces(Them, PAWN); |
106 | Bitboard theirPawns = pos.pieces(Them, PAWN); |
| 112 | 107 | ||
| 113 | e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; |
108 | e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; |
| 114 | e->kingSquares[Us] = SQ_NONE; |
- | |
| 115 | e->semiopenFiles[Us] = 0xFF; |
109 | e->semiopenFiles[Us] = 0xFF; |
| - | 110 | e->kingSquares[Us] = SQ_NONE; |
|
| 116 | e->pawnAttacks[Us] = |
111 | e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns); |
| 117 | e->pawnsOnSquares[Us][BLACK] = popcount |
112 | e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares); |
| 118 | e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK]; |
113 | e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK]; |
| 119 | 114 | ||
| 120 | // Loop through all pawns of the current color and score each pawn |
115 | // Loop through all pawns of the current color and score each pawn |
| 121 | while ((s = *pl++) != SQ_NONE) |
116 | while ((s = *pl++) != SQ_NONE) |
| 122 | { |
117 | { |
| 123 | assert(pos.piece_on(s) == make_piece(Us, PAWN)); |
118 | assert(pos.piece_on(s) == make_piece(Us, PAWN)); |
| 124 | 119 | ||
| 125 | File f = file_of(s); |
120 | File f = file_of(s); |
| 126 | 121 | ||
| 127 | e->semiopenFiles[Us] &= ~(1 << f); |
122 | e->semiopenFiles[Us] &= ~(1 << f); |
| 128 | e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); |
123 | e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); |
| 129 | 124 | ||
| 130 | // Flag the pawn |
125 | // Flag the pawn |
| 131 |
|
126 | opposed = theirPawns & forward_bb(Us, s); |
| 132 |
|
127 | stoppers = theirPawns & passed_pawn_mask(Us, s); |
| 133 |
|
128 | lever = theirPawns & pawnAttacksBB[s]; |
| 134 |
|
129 | doubled = ourPawns & (s + Up); |
| 135 |
|
130 | neighbours = ourPawns & adjacent_files_bb(f); |
| 136 | phalanx |
131 | phalanx = neighbours & rank_bb(s); |
| 137 | supported |
132 | supported = neighbours & rank_bb(s - Up); |
| 138 | connected |
133 | connected = supported | phalanx; |
| 139 | isolated = !neighbours; |
- | |
| 140 | 134 | ||
| 141 | // Test for backward pawn. |
- | |
| 142 | // If the pawn is passed, isolated, lever or connected it cannot be |
- | |
| 143 | // backward |
135 | // A pawn is backward when it is behind all pawns of the same color on the |
| 144 | // |
136 | // adjacent files and cannot be safely advanced. |
| 145 | if ( (passed | isolated | lever | connected) |
- | |
| 146 | || (ourPawns & pawn_attack_span(Them, s)) |
- | |
| 147 |
|
137 | if (!neighbours || lever || relative_rank(Us, s) >= RANK_5) |
| 148 | backward = false; |
138 | backward = false; |
| 149 | else |
139 | else |
| 150 | { |
140 | { |
| 151 | // We now know there are no friendly pawns beside or behind this |
- | |
| 152 | // pawn on adjacent files. We now check whether the pawn is |
- | |
| 153 | // backward by looking in the forward direction on the adjacent |
- | |
| 154 | // |
141 | // Find the backmost rank with neighbours or stoppers |
| 155 | b = |
142 | b = rank_bb(backmost_sq(Us, neighbours | stoppers)); |
| 156 | b = pawn_attack_span(Us, s) & rank_bb(backmost_sq(Us, b)); |
- | |
| 157 | 143 | ||
| - | 144 | // The pawn is backward when it cannot safely progress to that rank: |
|
| 158 | // |
145 | // either there is a stopper in the way on this rank, or there is a |
| 159 | // |
146 | // stopper on adjacent file which controls the way to that rank. |
| 160 | backward = (b | |
147 | backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers; |
| 161 | } |
- | |
| 162 | 148 | ||
| 163 | assert( |
149 | assert(!backward || !(pawn_attack_span(Them, s + Up) & neighbours)); |
| - | 150 | } |
|
| 164 | 151 | ||
| 165 | // Passed pawns will be properly scored in evaluation because we need |
152 | // Passed pawns will be properly scored in evaluation because we need |
| 166 | // full attack info to evaluate them. |
153 | // full attack info to evaluate them. |
| 167 |
|
154 | if (!stoppers && !(ourPawns & forward_bb(Us, s))) |
| 168 | if (passed && !doubled) |
- | |
| 169 | e->passedPawns[Us] |= s; |
155 | e->passedPawns[Us] |= s; |
| 170 | 156 | ||
| 171 | // Score this pawn |
157 | // Score this pawn |
| 172 | if ( |
158 | if (!neighbours) |
| 173 | score -= Isolated[opposed |
159 | score -= Isolated[opposed]; |
| 174 | 160 | ||
| 175 | else if (backward) |
161 | else if (backward) |
| 176 | score -= Backward[opposed]; |
162 | score -= Backward[opposed]; |
| 177 | 163 | ||
| 178 | else if (!supported) |
164 | else if (!supported) |
| 179 | score -= Unsupported |
165 | score -= Unsupported; |
| 180 | 166 | ||
| 181 | if (connected) |
167 | if (connected) |
| 182 | score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)]; |
168 | score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)]; |
| 183 | 169 | ||
| 184 | if (doubled) |
170 | if (doubled) |
| 185 | score -= Doubled |
171 | score -= Doubled; |
| 186 | 172 | ||
| 187 | if (lever) |
173 | if (lever) |
| 188 | score += Lever[relative_rank(Us, s)]; |
174 | score += Lever[relative_rank(Us, s)]; |
| 189 | } |
175 | } |
| 190 | - | ||
| 191 | b = e->semiopenFiles[Us] ^ 0xFF; |
- | |
| 192 | e->pawnSpan[Us] = b ? int(msb(b) - lsb(b)) : 0; |
- | |
| 193 | 176 | ||
| 194 | return score; |
177 | return score; |
| 195 | } |
178 | } |
| 196 | 179 | ||
| 197 | } // namespace |
180 | } // namespace |
| Line 200... | Line 183... | ||
| 200 | 183 | ||
| 201 | /// Pawns::init() initializes some tables needed by evaluation. Instead of using |
184 | /// Pawns::init() initializes some tables needed by evaluation. Instead of using |
| 202 | /// hard-coded tables, when makes sense, we prefer to calculate them with a formula |
185 | /// hard-coded tables, when makes sense, we prefer to calculate them with a formula |
| 203 | /// to reduce independent parameters and to allow easier tuning and better insight. |
186 | /// to reduce independent parameters and to allow easier tuning and better insight. |
| 204 | 187 | ||
| 205 | void init() |
188 | void init() { |
| 206 | { |
189 | |
| 207 | static const int Seed[RANK_NB] = { 0, 8, 19, 13, 71, 94, 169, 324 }; |
190 | static const int Seed[RANK_NB] = { 0, 8, 19, 13, 71, 94, 169, 324 }; |
| 208 | 191 | ||
| 209 | for (int opposed = 0; opposed <= 1; ++opposed) |
192 | for (int opposed = 0; opposed <= 1; ++opposed) |
| 210 | for (int phalanx = 0; phalanx <= 1; ++phalanx) |
193 | for (int phalanx = 0; phalanx <= 1; ++phalanx) |
| 211 | for (int apex = 0; apex <= 1; ++apex) |
194 | for (int apex = 0; apex <= 1; ++apex) |
| Line 231... | Line 214... | ||
| 231 | if (e->key == key) |
214 | if (e->key == key) |
| 232 | return e; |
215 | return e; |
| 233 | 216 | ||
| 234 | e->key = key; |
217 | e->key = key; |
| 235 | e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e); |
218 | e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e); |
| 236 | e->asymmetry = popcount |
219 | e->asymmetry = popcount(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]); |
| - | 220 | e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]); |
|
| 237 | return e; |
221 | return e; |
| 238 | } |
222 | } |
| 239 | 223 | ||
| 240 | 224 | ||
| 241 | /// Entry::shelter_storm() calculates shelter and storm penalties for the file |
225 | /// Entry::shelter_storm() calculates shelter and storm penalties for the file |
| Line 285... | Line 269... | ||
| 285 | int minKingPawnDistance = 0; |
269 | int minKingPawnDistance = 0; |
| 286 | 270 | ||
| 287 | Bitboard pawns = pos.pieces(Us, PAWN); |
271 | Bitboard pawns = pos.pieces(Us, PAWN); |
| 288 | if (pawns) |
272 | if (pawns) |
| 289 | while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {} |
273 | while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {} |
| 290 | - | ||
| 291 | if (relative_rank(Us, ksq) > RANK_4) |
- | |
| 292 | return make_score(0, -16 * minKingPawnDistance); |
- | |
| 293 | 274 | ||
| 294 | Value bonus = shelter_storm<Us>(pos, ksq); |
275 | Value bonus = shelter_storm<Us>(pos, ksq); |
| 295 | 276 | ||
| 296 | // If we can castle use the bonus after the castling if it is bigger |
277 | // If we can castle use the bonus after the castling if it is bigger |
| 297 | if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right)) |
278 | if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right)) |