]> git.sesse.net Git - stupid/blob - evaluator.c
Initial checkin for move to Git (no prior version history available).
[stupid] / evaluator.c
1 #include <stdlib.h>
2 #include <assert.h>
3 #include "evaluator.h"
4 #include "hash.h"
5
6 int material_values[NUM_PIECES][NUM_SQUARES];
7
8 // simple material counter for now, improve later :-)
9 void init_evaluator(void)
10 {
11         unsigned i, x, y;
12
13         for (i = 0; i < NUM_SQUARES; ++i) {
14                 material_values[PIECE_EMPTY ][i] = 0;
15                 material_values[PIECE_KNIGHT][i] = 280;
16                 material_values[PIECE_BISHOP][i] = 320;
17                 material_values[PIECE_ROOK  ][i] = 500;
18                 material_values[PIECE_QUEEN ][i] = 900;
19                 material_values[PIECE_KING  ][i] = 20000;  // more than all else combined
20         }
21                 
22         // pawns are better off near the other side, and better close to the middle
23         for (y = 0; y < 8; ++y) {       
24                 for (x = 0; x < 8; ++x) {
25                         unsigned value = 100;
26
27                         switch (x) {
28                         case 0:
29                         case 7:
30                                 break;
31                         case 1:
32                         case 6:
33                                 value += 5;
34                                 break;
35                         case 2:
36                         case 5:
37                                 value += 7;
38                                 if (y >= 3)
39                                         value += 10;  // central pawns ftw
40                                 break;
41                         case 3:
42                         case 4:
43                                 value += 10;
44                                 if (y >= 3)
45                                         value += 10;  // central pawns ftw
46                                 break;
47                         }
48                         
49                         switch (y) {
50                         case 4:
51                                 value += 10;
52                                 break;
53                         case 5:
54                                 value += 20;
55                                 break;
56                         case 6:
57                                 value += 40;
58                                 break;
59                         case 7:
60                                 value += 80;
61                                 break;
62                         }
63
64                         material_values[PIECE_PAWN][SQUARE_TO_NUM(x,y)] = value;
65                 }
66         }
67                 
68         // knights hate the edges
69         for (y = 0; y < 8; ++y) {       
70                 for (x = 0; x < 8; ++x) {
71                         if (x == 0 || x == 7 || y == 0 || y == 7)
72                                 material_values[PIECE_KNIGHT][SQUARE_TO_NUM(x,y)] -= 40;
73                         else if (x == 1 || x == 6 || y == 1 || y == 6)
74                                 material_values[PIECE_KNIGHT][SQUARE_TO_NUM(x,y)] -= 15;
75                 }
76         }
77 }
78
79 void count_pawns(const struct piece * const pieces, unsigned *pawns)
80 {
81         unsigned i;
82         for (i = 0; i < 8; ++i) {
83                 if (pieces[i].type == PIECE_PAWN) {
84                         assert(NUM_TO_FILE(pieces[i].square) >= 0);
85                         assert(NUM_TO_FILE(pieces[i].square) < 8);
86                         ++pawns[NUM_TO_FILE(pieces[i].square)];
87                 }
88         }
89 }
90
91 unsigned find_doubled_pawns(const unsigned * const pawns)
92 {
93         unsigned i;
94         unsigned num = 0;
95
96         for (i = 0; i < 8; ++i) {
97                 if (pawns[i] > 1) {
98                         ++num;
99                 }
100         }
101
102         return num;
103 }
104
105 unsigned find_isolated_pawns(const unsigned * const pawns)
106 {
107         unsigned i;
108         unsigned num = 0;
109
110         for (i = 0; i < 8; ++i) {
111                 if (pawns[i] == 0)
112                         continue;
113                 if (i > 0 && pawns[i - 1] > 0)
114                         continue;
115                 if (i < 8 && pawns[i + 1] > 0)
116                         continue;
117                 ++num;
118         }
119
120         return num;
121 }
122
123 unsigned find_passed_pawns(const struct piece * const pieces, const struct piece * const opp_pieces, unsigned *pawns, unsigned *opp_pawns, int inverse)
124 {
125         unsigned i, j;
126         unsigned num = 0;
127
128         for (i = 0; i < 8; ++i) {
129                 unsigned file, rank;
130
131                 // could be empty, or promoted (although the latter is unlikely)
132                 if (pieces[i].type != PIECE_PAWN)
133                         continue;
134
135                 file = NUM_TO_FILE(pieces[i].square);
136
137                 // usual heuristic: blocked by "the same pawn" on the same file
138                 if (file == NUM_TO_FILE(opp_pieces[i].square) &&
139                     POSSIBLY_INVERT(opp_pieces[i].square - pieces[i].square, inverse) >= 0)
140                         continue;
141
142                 // ok, obviously not. let's see if there's anything can indeed block it.
143                 if (opp_pawns[file] > 0 || (file > 0 && opp_pawns[file - 1] > 0) || (file < 7 && opp_pawns[file + 1] > 0)) {
144                         rank = NUM_TO_RANK(pieces[i].square);
145                         for (j = 0; j < 8; ++j) {
146                                 unsigned ofile;
147
148                                 if (opp_pieces[j].type != PIECE_PAWN)
149                                         continue;
150                                 
151                                 // needs to be in front to block
152                                 if (POSSIBLY_INVERT(NUM_TO_RANK(opp_pieces[j].square) - rank, inverse) <= 0)
153                                         continue;
154                         
155                                 ofile = NUM_TO_FILE(opp_pieces[j].square);
156                                 if (file == ofile || file == ofile - 1 || file == ofile + 1)
157                                         goto not_this_one;
158                         }
159                 }
160
161                 ++num;
162
163 not_this_one:
164                 1;
165         }
166
167         return num;
168 }
169
170 // very crude, but hey
171 int king_safe(const struct piece * const pieces)
172 {
173         unsigned square = pieces[0].square;
174         unsigned full_safety = 3;
175
176         // c1, f1, c6, f6 are "half-safe", and are judged as the more cornered ones, only slightly
177         // more harshly
178         if (square == SQUARE_TO_NUM(2, 0) || square == SQUARE_TO_NUM(5, 0) || square == SQUARE_TO_NUM(2, 7) || square == SQUARE_TO_NUM(5, 7))
179                 full_safety = 2;
180
181         if (square == SQUARE_TO_NUM(0, 0) || square == SQUARE_TO_NUM(1, 0)) {
182                 if (pieces[8].type != PIECE_PAWN || pieces[9].type != PIECE_PAWN || pieces[10].type != PIECE_PAWN)
183                         return 0;
184
185                 // king on a1 or b1, just need three good pawns for full safety (ignore threats down there for now)
186                 if (pieces[8].square == SQUARE_TO_NUM(0, 1) && pieces[9].square == SQUARE_TO_NUM(1, 1) && pieces[10].square == SQUARE_TO_NUM(2, 1))
187                         return full_safety;
188                 if (pieces[8].square == SQUARE_TO_NUM(0, 2) && pieces[9].square == SQUARE_TO_NUM(1, 1) && pieces[10].square == SQUARE_TO_NUM(2, 1))
189                         return full_safety;
190                 if (pieces[8].square == SQUARE_TO_NUM(0, 1) && pieces[9].square == SQUARE_TO_NUM(1, 2) && pieces[10].square == SQUARE_TO_NUM(2, 1))
191                         return full_safety;
192                 if (pieces[8].square == SQUARE_TO_NUM(0, 3) && pieces[9].square == SQUARE_TO_NUM(1, 2) && pieces[10].square == SQUARE_TO_NUM(2, 1))
193                         return full_safety;
194                 if (pieces[8].square == SQUARE_TO_NUM(0, 1) && pieces[9].square == SQUARE_TO_NUM(1, 1) && pieces[10].square == SQUARE_TO_NUM(2, 2))
195                         return 1;
196         } else if (square == SQUARE_TO_NUM(6, 0) || square == SQUARE_TO_NUM(7, 0)) {
197                 if (pieces[15].type != PIECE_PAWN || pieces[14].type != PIECE_PAWN || pieces[13].type != PIECE_PAWN)
198                         return 0;
199
200                 // king on g1 or h1, just need three good pawns for full safety (ignore threats down there for now)
201                 if (pieces[15].square == SQUARE_TO_NUM(7, 1) && pieces[14].square == SQUARE_TO_NUM(6, 1) && pieces[13].square == SQUARE_TO_NUM(5, 1))
202                         return full_safety;
203                 if (pieces[15].square == SQUARE_TO_NUM(7, 2) && pieces[14].square == SQUARE_TO_NUM(6, 1) && pieces[13].square == SQUARE_TO_NUM(5, 1))
204                         return full_safety;
205                 if (pieces[15].square == SQUARE_TO_NUM(7, 1) && pieces[14].square == SQUARE_TO_NUM(6, 2) && pieces[13].square == SQUARE_TO_NUM(5, 1))
206                         return full_safety;
207                 if (pieces[15].square == SQUARE_TO_NUM(7, 3) && pieces[14].square == SQUARE_TO_NUM(6, 2) && pieces[13].square == SQUARE_TO_NUM(5, 1))
208                         return full_safety;
209                 if (pieces[15].square == SQUARE_TO_NUM(7, 1) && pieces[14].square == SQUARE_TO_NUM(6, 1) && pieces[13].square == SQUARE_TO_NUM(5, 2))
210                         return 1;
211         } else if (square == SQUARE_TO_NUM(0, 7) || square == SQUARE_TO_NUM(1, 7)) {
212                 if (pieces[8].type != PIECE_PAWN || pieces[9].type != PIECE_PAWN || pieces[10].type != PIECE_PAWN)
213                         return 0;
214
215                 // king on a8 or b8, just need three good pawns for full safety (ignore threats down there for now)
216                 if (pieces[8].square == SQUARE_TO_NUM(0, 6) && pieces[9].square == SQUARE_TO_NUM(1, 6) && pieces[10].square == SQUARE_TO_NUM(2, 6))
217                         return full_safety;
218                 if (pieces[8].square == SQUARE_TO_NUM(0, 5) && pieces[9].square == SQUARE_TO_NUM(1, 6) && pieces[10].square == SQUARE_TO_NUM(2, 6))
219                         return full_safety;
220                 if (pieces[8].square == SQUARE_TO_NUM(0, 6) && pieces[9].square == SQUARE_TO_NUM(1, 5) && pieces[10].square == SQUARE_TO_NUM(2, 6))
221                         return full_safety;
222                 if (pieces[8].square == SQUARE_TO_NUM(0, 3) && pieces[9].square == SQUARE_TO_NUM(1, 5) && pieces[10].square == SQUARE_TO_NUM(2, 6))
223                         return full_safety;
224                 if (pieces[8].square == SQUARE_TO_NUM(0, 6) && pieces[9].square == SQUARE_TO_NUM(1, 6) && pieces[10].square == SQUARE_TO_NUM(2, 5))
225                         return 1;
226         } else if (square == SQUARE_TO_NUM(6, 7) || square == SQUARE_TO_NUM(7, 7)) {
227                 if (pieces[15].type != PIECE_PAWN || pieces[14].type != PIECE_PAWN || pieces[13].type != PIECE_PAWN)
228                         return 0;
229
230                 // king on g1 or h1, just need three good pawns for full safety (ignore threats down there for now)
231                 if (pieces[15].square == SQUARE_TO_NUM(7, 6) && pieces[14].square == SQUARE_TO_NUM(6, 6) && pieces[13].square == SQUARE_TO_NUM(5, 6))
232                         return full_safety;
233                 if (pieces[15].square == SQUARE_TO_NUM(7, 5) && pieces[14].square == SQUARE_TO_NUM(6, 6) && pieces[13].square == SQUARE_TO_NUM(5, 6))
234                         return full_safety;
235                 if (pieces[15].square == SQUARE_TO_NUM(7, 6) && pieces[14].square == SQUARE_TO_NUM(6, 5) && pieces[13].square == SQUARE_TO_NUM(5, 6))
236                         return full_safety;
237                 if (pieces[15].square == SQUARE_TO_NUM(7, 3) && pieces[14].square == SQUARE_TO_NUM(6, 5) && pieces[13].square == SQUARE_TO_NUM(5, 6))
238                         return full_safety;
239                 if (pieces[15].square == SQUARE_TO_NUM(7, 6) && pieces[14].square == SQUARE_TO_NUM(6, 6) && pieces[13].square == SQUARE_TO_NUM(5, 5))
240                         return 1;
241         }
242
243         return 0;
244 }
245
246 int pawn_and_king_evaluation(const struct position * const p, unsigned total_material)
247 {
248         // this is rather expensive, so we hash it
249         unsigned long long phash = hash_position_pk(p);
250         unsigned bucket = phash % PHASH_BUCKETS;
251         struct hash_pawn_entry *he = pawn_eval_table[bucket];
252         int pawn_score = 0, king_safety;
253 #ifdef PROFILE_HASHES
254         unsigned chain = 0;
255 #endif
256
257         while (he != NULL) {
258                 if (he->phash == phash) {
259 #ifdef PROFILE_HASHES
260                         record_lookup(2, true, ++chain);
261 #endif
262                         return he->pawn_score + ((he->king_safety * (int)total_material) >> 8);
263                 }
264                 he = he->next;
265 #ifdef PROFILE_HASHES
266                 ++chain;
267 #endif
268         }
269 #ifdef PROFILE_HASHES
270         record_lookup(2, false, chain);
271 #endif
272
273         // ok, need to calculate
274         {
275                 unsigned white_pawns[8] = { 0 }, black_pawns[8] = { 0 };
276                 count_pawns(p->white_pieces + 8, white_pawns);
277                 count_pawns(p->black_pieces + 8, black_pawns);
278
279                 // doubled pawns are bad
280                 pawn_score += 20 * find_doubled_pawns(white_pawns);
281                 pawn_score -= 20 * find_doubled_pawns(black_pawns);
282                 
283                 // so are isolated pawns
284                 pawn_score += 40 * find_isolated_pawns(white_pawns);
285                 pawn_score -= 40 * find_isolated_pawns(black_pawns);
286
287                 // but passed pawns are extraordinarily good
288                 pawn_score += 80 * find_passed_pawns(p->white_pieces + 8, p->black_pieces + 8, white_pawns, black_pawns, 0);
289                 pawn_score -= 80 * find_passed_pawns(p->black_pieces + 8, p->white_pieces + 8, black_pawns, white_pawns, -1);
290         }
291
292         king_safety = king_safe(p->white_pieces) - king_safe(p->black_pieces);
293
294         // insert into the hash
295         he = (struct hash_pawn_entry *)malloc(sizeof(struct hash_pawn_entry));
296         he->phash = phash;
297         he->pawn_score = pawn_score;
298         he->king_safety = king_safety;
299         
300         assert(bucket < PHASH_BUCKETS);
301
302         he->next = pawn_eval_table[bucket];
303         pawn_eval_table[bucket] = he;
304
305         return pawn_score + ((king_safety * (int)total_material) >> 8);
306 }
307
308 int evaluate(const struct position * const p)
309 {
310         unsigned i;
311         int score = 0;
312         unsigned white_material = 0, black_material = 0;
313
314         for (i = 0; i < 16; ++i) {
315                 white_material += material_values[p->white_pieces[i].type][p->white_pieces[i].square];
316         }
317         for (i = 0; i < 16; ++i) {
318                 black_material += material_values[p->black_pieces[i].type][NUM_SQUARES - 1 - p->black_pieces[i].square];
319         }
320
321         // bishop pair is good
322         if (p->white_pieces[4].type == PIECE_BISHOP && p->white_pieces[5].type == PIECE_BISHOP)
323                 score += 50;
324         if (p->black_pieces[4].type == PIECE_BISHOP && p->black_pieces[5].type == PIECE_BISHOP)
325                 score -= 50;
326
327         // ability to castle is good
328         if (p->wc_short)
329                 score += 25;
330         if (p->wc_long)
331                 score += 20;
332         if (p->bc_short)
333                 score -= 25;
334         if (p->bc_long)
335                 score -= 20;
336
337         score += pawn_and_king_evaluation(p, white_material + black_material - 40000);
338
339         ++total_nodes;
340
341         return score + white_material - black_material;
342 }
343