1 /* Copyright (C) 2007-2012 Vincent Ollivier
3 * Purple Haze is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * Purple Haze is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "hashtable.h"
27 // PST[Phase][Color][PieceType][Square]
28 static int PST
[2][2][NB_PIECE_TYPES
][BOARD_SIZE
] = { { { { 0 } } } };
30 void Game::init_eval()
32 for (const Square
&s
: SQUARES
) {
33 for (const PieceType
&t
: PIECE_TYPES
) {
34 int opening_score
= 0;
39 // Develop central pawns
41 opening_score
= PAWN_FILES_VALUES
[board
.file(s
)];
44 ending_score
= 10 * board
.rank(s
);
48 // Develop toward center files
49 opening_score
= CENTER_BONUS
[board
.file(s
)];
50 if (board
.is_border(s
)) {
51 opening_score
= 2 * BORDER_MALUS
;
55 ending_score
= CENTER_BONUS
[board
.file(s
)];
56 ending_score
+= CENTER_BONUS
[board
.rank(s
)];
61 int bonus
= OPENING_RANKS_BONUS
[t
][board
.rank(s
)];
62 opening_score
+= (opening_score
* bonus
) / 2;
64 PST
[OPENING
][WHITE
][t
][s
] = opening_score
;
65 PST
[ENDING
][WHITE
][t
][s
] = ending_score
;
68 // Special corrections
69 // Urge to develop light pieces during opening
70 PST
[OPENING
][WHITE
][KNIGHT
][B1
] = -20;
71 PST
[OPENING
][WHITE
][KNIGHT
][G1
] = -20;
72 PST
[OPENING
][WHITE
][BISHOP
][C1
] = -15;
73 PST
[OPENING
][WHITE
][BISHOP
][F1
] = -15;
74 // But others should stay where they are
75 PST
[OPENING
][WHITE
][ROOK
][A1
] = 5;
76 PST
[OPENING
][WHITE
][ROOK
][H1
] = 5;
77 PST
[OPENING
][WHITE
][KING
][E1
] = 5;
79 PST
[OPENING
][WHITE
][BISHOP
][B2
] = 3;
80 PST
[OPENING
][WHITE
][BISHOP
][G2
] = 3;
81 // Protection against bishop attacks
82 PST
[OPENING
][WHITE
][PAWN
][A3
] += 3;
83 PST
[OPENING
][WHITE
][PAWN
][H3
] += 3;
85 // Flip scores according to black's side
86 for (const Phase
&p
: PHASES
) {
87 for (const Square
&ws
: SQUARES
) {
88 const Square bs
= Board::flip(ws
);
89 for (const PieceType
&t
: PIECE_TYPES
) {
90 PST
[p
][BLACK
][t
][bs
] = PST
[p
][WHITE
][t
][ws
];
96 static const int LAZY_EVAL_MARGIN
= PIECE_VALUE
[ROOK
];
98 int Game::eval(int alpha
, int beta
)
100 // Material evaluation
101 int score
= material_eval();
103 // TODO Draws should be caught here
109 if (score
> PIECE_VALUE
[KING
]) {
111 } else if (score
< -PIECE_VALUE
[KING
]) {
116 if (score
+ LAZY_EVAL_MARGIN
< alpha
) {
118 } else if (score
- LAZY_EVAL_MARGIN
> beta
) {
122 // TODO Positional evaluation
123 score
+= position_eval();
125 // TODO Mobility evaluation
126 //score += mobility_eval();
131 int Game::material_eval()
133 Position
&pos
= current_position();
135 // Lookup position in material hash table
136 bool is_empty
= true;
137 auto hash_score
= material_table
.lookup(pos
.material_hash(), &is_empty
);
139 return (pos
.side() == WHITE
? hash_score
: -hash_score
);
142 int scores
[2] = { 0 };
143 int bonuses
[2] = { 0 };
144 for (const Color
&c
: COLORS
) {
147 for (const PieceType
&t
: PIECE_TYPES
) {
148 const int n
= pieces
.count(c
, t
);
149 // Standard pieces values
150 scores
[c
] += n
* PIECE_VALUE
[t
];
152 // Bonus values depending on material imbalance
157 bonuses
[c
] += NO_PAWNS_MALUS
;
163 bonuses
[c
] += REDUNDANCY_MALUS
;
166 // Value adjusted by the number of pawns on the board
167 bonuses
[c
] += n
* PAWNS_ADJUSTEMENT
[KNIGHT
][nb_pawns
];
171 // Bishop bonus pair (from +40 to +64): less than half a pawn
172 // when most or all the pawns are on the board, and more than
173 // half a pawn when half or more of the pawns are gone.
176 // No bonus for two bishops controlling the same color
177 // No bonus for more than two bishops
178 if (n
== 2 && has_bishop_pair(c
, pieces
)) {
179 bonuses
[c
] += BISHOP_PAIR_BONUS
+ 3 * 8 - nb_pawns
;
182 // Value adjusted by the number of pawns on the board
183 bonuses
[c
] += n
* PAWNS_ADJUSTEMENT
[BISHOP
][nb_pawns
];
186 // Principle of the redundancy (Kaufman 1999)
188 bonuses
[c
] += REDUNDANCY_MALUS
;
191 // Value adjusted by the number of pawns on the board
192 bonuses
[c
] += n
* PAWNS_ADJUSTEMENT
[ROOK
][nb_pawns
];
196 // With two or more minor pieces, the queen equals two
197 // rooks. (Kaufman 1999)
198 bonuses
[c
] += 2 * PIECE_VALUE
[ROOK
] - PIECE_VALUE
[QUEEN
];
200 // Value adjusted by the number of pawns on the board
201 bonuses
[c
] += n
* PAWNS_ADJUSTEMENT
[QUEEN
][nb_pawns
];
209 // Draw by insufficient material detection
210 bool is_draw
= false;
211 const int K
= PIECE_VALUE
[KING
];
212 const int P
= PIECE_VALUE
[PAWN
];
213 const int N
= PIECE_VALUE
[KNIGHT
];
214 const int B
= PIECE_VALUE
[BISHOP
];
215 for (const Color
&c
: COLORS
) {
217 // FIDE rules for draw
218 if (scores
[c
] == K
) {
219 if (scores
[!c
] == K
) {
221 } else if (scores
[!c
] == K
+ B
) {
223 } else if (scores
[!c
] == K
+ N
) {
225 } else if (scores
[!c
] == K
+ N
+ N
) {
229 // TODO is this duplicate with MALUS_NO_PAWNS?
230 if (!pieces
.count(!c
, PAWN
) && scores
[!c
] < K
+ 4 * P
) {
234 is_draw
= false; // no break happened
237 const Color c
= pos
.side();
240 score
= scores
[c
] - scores
[!c
];
241 score
+= bonuses
[c
] - bonuses
[!c
];
244 // Save score to material hash table
245 hash_score
= (c
== WHITE
? score
: -score
);
246 material_table
.save(pos
.material_hash(), hash_score
);
251 static int castling_score(const Position
&pos
, Color c
)
254 if (pos
.has_castled(c
)) {
255 score
+= CASTLE_BONUS
;
257 for (const PieceType
&t
: SIDE_TYPES
) { // for QUEEN and KING side
258 if (!pos
.can_castle(c
, t
)) {
259 score
+= BREAKING_CASTLE_MALUS
;
266 int Game::position_eval()
269 int pos_scores
[2][2] = { { 0 } };
270 int pawns_files
[2][8] = { { 0 } };
271 const Position
&pos
= current_position();
272 for (const Color
&c
: COLORS
) {
273 for (const PieceType
&t
: PIECE_TYPES
) {
274 const int n
= pieces
.count(c
, t
);
275 phase
+= n
* PHASE_COEF
[t
];
276 for (int i
= 0; i
< n
; ++i
) {
277 const Square s
= pieces
.position(c
, t
, i
);
278 pos_scores
[OPENING
][c
] += PST
[OPENING
][c
][t
][s
];
279 pos_scores
[ENDING
][c
] += PST
[ENDING
][c
][t
][s
];
281 pawns_files
[c
][board
.file(s
)]++;
287 for (int i
= 0; i
< 8; ++i
) {
288 pawns_score
+= MULTI_PAWNS_MALUS
[pawns_files
[c
][i
]];
290 pos_scores
[OPENING
][c
] += pawns_score
;
292 // Rooks' files bonus
294 for (int i
= 0, n
= pieces
.count(c
, ROOK
); i
< n
; ++i
) {
295 const Square s
= pieces
.position(c
, ROOK
, i
);
296 if (!pawns_files
[!c
][board
.file(s
)]) {
297 if (!pawns_files
[c
][board
.file(s
)]) {
298 rooks_score
+= OPEN_FILE_BONUS
;
300 rooks_score
+= HALF_OPEN_FILE_BONUS
;
304 pos_scores
[OPENING
][c
] += rooks_score
;
306 // Castling bonus/malus
307 pos_scores
[OPENING
][c
] += castling_score(pos
, c
);
311 // Retrieve opening and ending score
312 const Color c
= pos
.side();
313 const int opening
= pos_scores
[OPENING
][c
] - pos_scores
[OPENING
][!c
];
314 const int ending
= pos_scores
[ENDING
][c
] - pos_scores
[ENDING
][!c
];
316 // Tapered Eval (idea from Fruit 2.1)
317 const int max
= PHASE_MAX
;
318 phase
= ((phase
> max
) ? max
: ((phase
< 0) ? 0 : phase
));
319 return (opening
* phase
+ ending
* (max
- phase
)) / max
;