Rev 154 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 154 | Rev 169 | ||
---|---|---|---|
Line 4... | Line 4... | ||
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
5 | Copyright (C) 2015- |
5 | Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
6 | 6 | ||
7 | Stockfish is free software: you can redistribute it and/or modify |
7 | Stockfish is free software: you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation, either version 3 of the License, or |
9 | the Free Software Foundation, either version 3 of the License, or |
10 | (at your option) any later version. |
10 | (at your option) any later version. |
Line 29... | Line 29... | ||
29 | namespace { |
29 | namespace { |
30 | 30 | ||
31 | #define V Value |
31 | #define V Value |
32 | #define S(mg, eg) make_score(mg, eg) |
32 | #define S(mg, eg) make_score(mg, eg) |
33 | 33 | ||
34 | // Isolated pawn penalty |
34 | // Isolated pawn penalty |
35 | const Score Isolated |
35 | const Score Isolated = S(13, 18); |
36 | 36 | ||
37 | // Backward pawn penalty |
37 | // Backward pawn penalty |
38 | const Score Backward |
38 | const Score Backward = S(24, 12); |
39 | 39 | ||
40 | // Unsupported pawn penalty for pawns which are neither isolated or backward |
- | |
41 | const Score Unsupported = S(17, 8); |
- | |
42 | - | ||
43 | // Connected pawn bonus by opposed, phalanx, |
40 | // Connected pawn bonus by opposed, phalanx, #support and rank |
44 | Score Connected[2][2][ |
41 | Score Connected[2][2][3][RANK_NB]; |
45 | 42 | ||
46 | // Doubled pawn penalty |
43 | // Doubled pawn penalty |
47 | const Score Doubled = S(18,38); |
44 | const Score Doubled = S(18, 38); |
48 | - | ||
49 | // Lever bonus by rank |
- | |
50 | const Score Lever[RANK_NB] = { |
- | |
51 | S( 0, 0), S( 0, 0), S(0, 0), S(0, 0), |
- | |
52 | S(17, 16), S(33, 32), S(0, 0), S(0, 0) |
- | |
53 | }; |
- | |
54 | 45 | ||
55 | // Weakness of our pawn shelter in front of the king by [distance from edge][rank] |
46 | // Weakness of our pawn shelter in front of the king by [isKingFile][distance from edge][rank]. |
- | 47 | // RANK_1 = 0 is used for files where we have no pawns or our pawn is behind our king. |
|
56 | const Value ShelterWeakness[][RANK_NB] = { |
48 | const Value ShelterWeakness[][int(FILE_NB) / 2][RANK_NB] = { |
- | 49 | { { V( 97), V(17), V( 9), V(44), V( 84), V( 87), V( 99) }, // Not On King file |
|
57 | { V( |
50 | { V(106), V( 6), V(33), V(86), V( 87), V(104), V(112) }, |
58 | { V( |
51 | { V(101), V( 2), V(65), V(98), V( 58), V( 89), V(115) }, |
59 | { V( |
52 | { V( 73), V( 7), V(54), V(73), V( 84), V( 83), V(111) } }, |
- | 53 | { { V(104), V(20), V( 6), V(27), V( 86), V( 93), V( 82) }, // On King file |
|
- | 54 | { V(123), V( 9), V(34), V(96), V(112), V( 88), V( 75) }, |
|
- | 55 | { V(120), V(25), V(65), V(91), V( 66), V( 78), V(117) }, |
|
60 | { V( |
56 | { V( 81), V( 2), V(47), V(63), V( 94), V( 93), V(104) } } |
61 | }; |
57 | }; |
62 | 58 | ||
63 | // Danger of enemy pawns moving toward our king by [type][distance from edge][rank] |
59 | // Danger of enemy pawns moving toward our king by [type][distance from edge][rank]. |
- | 60 | // For the unopposed and unblocked cases, RANK_1 = 0 is used when opponent has |
|
- | 61 | // no pawn on the given file, or their pawn is behind our king. |
|
64 | const Value StormDanger[][4][RANK_NB] = { |
62 | const Value StormDanger[][4][RANK_NB] = { |
65 | { { V( 0), V( |
63 | { { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing |
66 | { V( 0), V( |
64 | { V( 0), V( 60), V( 144), V(39), V(13) }, |
67 | { V( 0), V( |
65 | { V( 0), V( 65), V( 141), V(41), V(34) }, |
68 | { V( 0), V( |
66 | { V( 0), V( 53), V( 127), V(56), V(14) } }, |
69 | { { V( |
67 | { { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed |
70 | { V( |
68 | { V( 1), V( 64), V( 143), V(26), V(13) }, |
71 | { V( |
69 | { V( 1), V( 47), V( 110), V(44), V(24) }, |
72 | { V( |
70 | { V( 0), V( 72), V( 127), V(50), V(31) } }, |
73 | { { V( 0), V( 0), V( |
71 | { { V( 0), V( 0), V( 79), V(23), V( 1) }, // BlockedByPawn |
74 | { V( 0), V( 0), V( |
72 | { V( 0), V( 0), V( 148), V(27), V( 2) }, |
75 | { V( 0), V( 0), V( |
73 | { V( 0), V( 0), V( 161), V(16), V( 1) }, |
76 | { V( 0), V( 0), V( |
74 | { V( 0), V( 0), V( 171), V(22), V(15) } }, |
77 | { { V( |
75 | { { V(22), V( 45), V( 104), V(62), V( 6) }, // Unblocked |
78 | { V( |
76 | { V(31), V( 30), V( 99), V(39), V(19) }, |
79 | { V( |
77 | { V(23), V( 29), V( 96), V(41), V(15) }, |
80 | { V( |
78 | { V(21), V( 23), V( 116), V(41), V(15) } } |
81 | }; |
79 | }; |
82 | 80 | ||
83 | // Max bonus for king safety. Corresponds to start position with all the pawns |
81 | // Max bonus for king safety. Corresponds to start position with all the pawns |
84 | // in front of the king and no enemy pawn on the horizon. |
82 | // in front of the king and no enemy pawn on the horizon. |
85 | const Value MaxSafetyBonus = V(258); |
83 | const Value MaxSafetyBonus = V(258); |
Line 88... | Line 86... | ||
88 | #undef V |
86 | #undef V |
89 | 87 | ||
90 | template<Color Us> |
88 | template<Color Us> |
91 | Score evaluate(const Position& pos, Pawns::Entry* e) { |
89 | Score evaluate(const Position& pos, Pawns::Entry* e) { |
92 | 90 | ||
93 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
91 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
94 | const |
92 | const Direction Up = (Us == WHITE ? NORTH : SOUTH); |
95 | const |
93 | const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); |
96 | const |
94 | const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); |
97 | 95 | ||
98 | Bitboard b, neighbours, stoppers, doubled, supported, phalanx; |
96 | Bitboard b, neighbours, stoppers, doubled, supported, phalanx; |
- | 97 | Bitboard lever, leverPush; |
|
99 | Square s; |
98 | Square s; |
100 | bool opposed, |
99 | bool opposed, backward; |
101 | Score score = SCORE_ZERO; |
100 | Score score = SCORE_ZERO; |
102 | const Square* pl = pos.squares<PAWN>(Us); |
101 | const Square* pl = pos.squares<PAWN>(Us); |
103 | const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)]; |
- | |
104 | 102 | ||
105 | Bitboard ourPawns = pos.pieces( |
103 | Bitboard ourPawns = pos.pieces( Us, PAWN); |
106 | Bitboard theirPawns = pos.pieces(Them, PAWN); |
104 | Bitboard theirPawns = pos.pieces(Them, PAWN); |
107 | 105 | ||
108 | e->passedPawns[Us] |
106 | e->passedPawns[Us] = e->pawnAttacksSpan[Us] = e->weakUnopposed[Us] = 0; |
109 | e->semiopenFiles[Us] = 0xFF; |
107 | e->semiopenFiles[Us] = 0xFF; |
110 | e->kingSquares[Us] = SQ_NONE; |
108 | e->kingSquares[Us] = SQ_NONE; |
111 | e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns); |
109 | e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns); |
112 | e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares); |
110 | e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares); |
113 | e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK]; |
111 | e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK]; |
Line 121... | Line 119... | ||
121 | 119 | ||
122 | e->semiopenFiles[Us] &= ~(1 << f); |
120 | e->semiopenFiles[Us] &= ~(1 << f); |
123 | e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); |
121 | e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); |
124 | 122 | ||
125 | // Flag the pawn |
123 | // Flag the pawn |
126 | opposed = theirPawns & |
124 | opposed = theirPawns & forward_file_bb(Us, s); |
127 | stoppers = theirPawns & passed_pawn_mask(Us, s); |
125 | stoppers = theirPawns & passed_pawn_mask(Us, s); |
128 | lever = theirPawns & |
126 | lever = theirPawns & PawnAttacks[Us][s]; |
- | 127 | leverPush = theirPawns & PawnAttacks[Us][s + Up]; |
|
129 | doubled = ourPawns & (s |
128 | doubled = ourPawns & (s - Up); |
130 | neighbours = ourPawns & adjacent_files_bb(f); |
129 | neighbours = ourPawns & adjacent_files_bb(f); |
131 | phalanx = neighbours & rank_bb(s); |
130 | phalanx = neighbours & rank_bb(s); |
132 | supported = neighbours & rank_bb(s - Up); |
131 | supported = neighbours & rank_bb(s - Up); |
133 | connected = supported | phalanx; |
- | |
134 | 132 | ||
135 | // A pawn is backward when it is behind all pawns of the same color on the |
133 | // A pawn is backward when it is behind all pawns of the same color on the |
136 | // adjacent files and cannot be safely advanced. |
134 | // adjacent files and cannot be safely advanced. |
137 | if (!neighbours || lever || relative_rank(Us, s) >= RANK_5) |
135 | if (!neighbours || lever || relative_rank(Us, s) >= RANK_5) |
138 | backward = false; |
136 | backward = false; |
Line 144... | Line 142... | ||
144 | // The pawn is backward when it cannot safely progress to that rank: |
142 | // The pawn is backward when it cannot safely progress to that rank: |
145 | // either there is a stopper in the way on this rank, or there is a |
143 | // either there is a stopper in the way on this rank, or there is a |
146 | // stopper on adjacent file which controls the way to that rank. |
144 | // stopper on adjacent file which controls the way to that rank. |
147 | backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers; |
145 | backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers; |
148 | 146 | ||
149 | assert(!backward |
147 | assert(!(backward && (forward_ranks_bb(Them, s + Up) & neighbours))); |
150 | } |
148 | } |
151 | 149 | ||
152 | // Passed pawns will be properly scored in evaluation because we need |
150 | // Passed pawns will be properly scored in evaluation because we need |
153 | // full attack info to evaluate them. |
151 | // full attack info to evaluate them. Include also not passed pawns |
- | 152 | // which could become passed after one or two pawn pushes when are |
|
- | 153 | // not attacked more times than defended. |
|
- | 154 | if ( !(stoppers ^ lever ^ leverPush) |
|
154 |
|
155 | && !(ourPawns & forward_file_bb(Us, s)) |
- | 156 | && popcount(supported) >= popcount(lever) |
|
- | 157 | && popcount(phalanx) >= popcount(leverPush)) |
|
155 | e->passedPawns[Us] |= s; |
158 | e->passedPawns[Us] |= s; |
- | 159 | ||
- | 160 | else if ( stoppers == SquareBB[s + Up] |
|
- | 161 | && relative_rank(Us, s) >= RANK_5) |
|
- | 162 | { |
|
- | 163 | b = shift<Up>(supported) & ~theirPawns; |
|
- | 164 | while (b) |
|
- | 165 | if (!more_than_one(theirPawns & PawnAttacks[Us][pop_lsb(&b)])) |
|
- | 166 | e->passedPawns[Us] |= s; |
|
- | 167 | } |
|
156 | 168 | ||
157 | // Score this pawn |
169 | // Score this pawn |
- | 170 | if (supported | phalanx) |
|
- | 171 | score += Connected[opposed][bool(phalanx)][popcount(supported)][relative_rank(Us, s)]; |
|
- | 172 | ||
158 | if (!neighbours) |
173 | else if (!neighbours) |
159 | score -= |
174 | score -= Isolated, e->weakUnopposed[Us] += !opposed; |
160 | 175 | ||
161 | else if (backward) |
176 | else if (backward) |
162 | score -= |
177 | score -= Backward, e->weakUnopposed[Us] += !opposed; |
163 | 178 | ||
164 |
|
179 | if (doubled && !supported) |
165 | score -= Unsupported; |
- | |
166 | - | ||
167 | if (connected) |
- | |
168 | score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)]; |
- | |
169 | - | ||
170 | if (doubled) |
- | |
171 | score -= Doubled; |
180 | score -= Doubled; |
172 | - | ||
173 | if (lever) |
- | |
174 | score += Lever[relative_rank(Us, s)]; |
- | |
175 | } |
181 | } |
176 | 182 | ||
177 | return score; |
183 | return score; |
178 | } |
184 | } |
179 | 185 | ||
Line 185... | Line 191... | ||
185 | /// hard-coded tables, when makes sense, we prefer to calculate them with a formula |
191 | /// hard-coded tables, when makes sense, we prefer to calculate them with a formula |
186 | /// to reduce independent parameters and to allow easier tuning and better insight. |
192 | /// to reduce independent parameters and to allow easier tuning and better insight. |
187 | 193 | ||
188 | void init() { |
194 | void init() { |
189 | 195 | ||
190 | static const int Seed[RANK_NB] = { 0, |
196 | static const int Seed[RANK_NB] = { 0, 13, 24, 18, 76, 100, 175, 330 }; |
191 | 197 | ||
192 | for (int opposed = 0; opposed <= 1; ++opposed) |
198 | for (int opposed = 0; opposed <= 1; ++opposed) |
193 | for (int phalanx = 0; phalanx <= 1; ++phalanx) |
199 | for (int phalanx = 0; phalanx <= 1; ++phalanx) |
194 | for (int |
200 | for (int support = 0; support <= 2; ++support) |
195 | for (Rank r = RANK_2; r < RANK_8; ++r) |
201 | for (Rank r = RANK_2; r < RANK_8; ++r) |
196 | { |
202 | { |
- | 203 | int v = 17 * support; |
|
197 |
|
204 | v += (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed; |
198 | v += (apex ? v / 2 : 0); |
- | |
- | 205 | ||
199 | Connected[opposed][phalanx][ |
206 | Connected[opposed][phalanx][support][r] = make_score(v, v * (r - 2) / 4); |
200 | } |
207 | } |
201 | } |
208 | } |
202 | 209 | ||
203 | 210 | ||
204 | /// Pawns::probe() looks up the current position's pawns configuration in |
211 | /// Pawns::probe() looks up the current position's pawns configuration in |
Line 221... | Line 228... | ||
221 | return e; |
228 | return e; |
222 | } |
229 | } |
223 | 230 | ||
224 | 231 | ||
225 | /// Entry::shelter_storm() calculates shelter and storm penalties for the file |
232 | /// Entry::shelter_storm() calculates shelter and storm penalties for the file |
226 | /// the king is on, as well as the two |
233 | /// the king is on, as well as the two closest files. |
227 | 234 | ||
228 | template<Color Us> |
235 | template<Color Us> |
229 | Value Entry::shelter_storm(const Position& pos, Square ksq) { |
236 | Value Entry::shelter_storm(const Position& pos, Square ksq) { |
230 | 237 | ||
231 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
238 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
232 | 239 | ||
233 | enum { |
240 | enum { BlockedByKing, Unopposed, BlockedByPawn, Unblocked }; |
234 | 241 | ||
235 | Bitboard b = pos.pieces(PAWN) & ( |
242 | Bitboard b = pos.pieces(PAWN) & (forward_ranks_bb(Us, ksq) | rank_bb(ksq)); |
236 | Bitboard ourPawns = b & pos.pieces(Us); |
243 | Bitboard ourPawns = b & pos.pieces(Us); |
237 | Bitboard theirPawns = b & pos.pieces(Them); |
244 | Bitboard theirPawns = b & pos.pieces(Them); |
238 | Value safety = MaxSafetyBonus; |
245 | Value safety = MaxSafetyBonus; |
239 | File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); |
246 | File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); |
240 | 247 | ||
241 | for (File f = center - |
248 | for (File f = File(center - 1); f <= File(center + 1); ++f) |
242 | { |
249 | { |
243 | b = ourPawns & file_bb(f); |
250 | b = ourPawns & file_bb(f); |
244 | Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; |
251 | Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; |
245 | 252 | ||
246 | b |
253 | b = theirPawns & file_bb(f); |
247 | Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; |
254 | Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; |
248 | 255 | ||
- | 256 | int d = std::min(f, ~f); |
|
249 | safety -= ShelterWeakness[ |
257 | safety -= ShelterWeakness[f == file_of(ksq)][d][rkUs] |
250 | + StormDanger |
258 | + StormDanger |
251 | [f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing : |
259 | [f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing : |
252 | rkUs == RANK_1 ? |
260 | rkUs == RANK_1 ? Unopposed : |
253 | rkThem == rkUs + 1 ? BlockedByPawn : Unblocked] |
261 | rkThem == rkUs + 1 ? BlockedByPawn : Unblocked] |
254 | [ |
262 | [d][rkThem]; |
255 | } |
263 | } |
256 | 264 | ||
257 | return safety; |
265 | return safety; |
258 | } |
266 | } |
259 | 267 |