1
2 // pawn.cpp
3
4 // includes
5
6 #include <cstring>
7
8 #include "board.h"
9 #include "colour.h"
10 #include "hash.h"
11 #include "option.h"
12 #include "pawn.h"
13 #include "piece.h"
14 #include "protocol.h"
15 #include "square.h"
16 #include "util.h"
17
18 // constants
19
20 static const bool UseTable = true;
21 static const uint32 TableSize = 16384; // 256kB
22
23 // types
24
25 typedef pawn_info_t entry_t;
26
27 struct pawn_t {
28 entry_t * table;
29 uint32 size;
30 uint32 mask;
31 uint32 used;
32 sint64 read_nb;
33 sint64 read_hit;
34 sint64 write_nb;
35 sint64 write_collision;
36 };
37
38 // constants and variables
39
40 static /* const */ int PawnStructureWeight = 256; // 100%
41
42 static const int DoubledOpening = 10;
43 static const int DoubledEndgame = 20;
44
45 static const int IsolatedOpening = 10;
46 static const int IsolatedOpeningOpen = 20;
47 static const int IsolatedEndgame = 20;
48
49 static const int BackwardOpening = 8;
50 static const int BackwardOpeningOpen = 16;
51 static const int BackwardEndgame = 10;
52
53 static const int CandidateOpeningMin = 5;
54 static const int CandidateOpeningMax = 55;
55 static const int CandidateEndgameMin = 10;
56 static const int CandidateEndgameMax = 110;
57
58 // this was moved to eval.cpp
59
60 /*
61 static const int PassedOpeningMin = 10;
62 static const int PassedOpeningMax = 70;
63 static const int PassedEndgameMin = 20;
64 static const int PassedEndgameMax = 140;
65 */
66
67 static /* const */ int Bonus[RankNb];
68
69 // variables
70
71 int BitEQ[16];
72 int BitLT[16];
73 int BitLE[16];
74 int BitGT[16];
75 int BitGE[16];
76
77 int BitFirst[0x100];
78 int BitLast[0x100];
79 int BitCount[0x100];
80 int BitRev[0x100];
81
82 static pawn_t Pawn[1];
83
84 static int BitRank1[RankNb];
85 static int BitRank2[RankNb];
86 static int BitRank3[RankNb];
87
88 // prototypes
89
90 static void pawn_comp_info (pawn_info_t * info, const board_t * board);
91
92 // functions
93
94 // pawn_init_bit()
95
pawn_init_bit()96 void pawn_init_bit() {
97
98 int rank;
99 int first, last, count;
100 int b, rev;
101
102 // rank-indexed Bit*[]
103
104 for (rank = 0; rank < RankNb; rank++) {
105
106 BitEQ[rank] = 0;
107 BitLT[rank] = 0;
108 BitLE[rank] = 0;
109 BitGT[rank] = 0;
110 BitGE[rank] = 0;
111
112 BitRank1[rank] = 0;
113 BitRank2[rank] = 0;
114 BitRank3[rank] = 0;
115 }
116
117 for (rank = Rank1; rank <= Rank8; rank++) {
118 BitEQ[rank] = 1 << (rank - Rank1);
119 BitLT[rank] = BitEQ[rank] - 1;
120 BitLE[rank] = BitLT[rank] | BitEQ[rank];
121 BitGT[rank] = BitLE[rank] ^ 0xFF;
122 BitGE[rank] = BitGT[rank] | BitEQ[rank];
123 }
124
125 for (rank = Rank1; rank <= Rank8; rank++) {
126 BitRank1[rank] = BitEQ[rank+1];
127 BitRank2[rank] = BitEQ[rank+1] | BitEQ[rank+2];
128 BitRank3[rank] = BitEQ[rank+1] | BitEQ[rank+2] | BitEQ[rank+3];
129 }
130
131 // bit-indexed Bit*[]
132
133 for (b = 0; b < 0x100; b++) {
134
135 first = Rank8; // HACK for pawn shelter
136 last = Rank1; // HACK
137 count = 0;
138 rev = 0;
139
140 for (rank = Rank1; rank <= Rank8; rank++) {
141 if ((b & BitEQ[rank]) != 0) {
142 if (rank < first) first = rank;
143 if (rank > last) last = rank;
144 count++;
145 rev |= BitEQ[RANK_OPP(rank)];
146 }
147 }
148
149 BitFirst[b] = first;
150 BitLast[b] = last;
151 BitCount[b] = count;
152 BitRev[b] = rev;
153 }
154 }
155
156
157 // pawn_parameter()
158
pawn_parameter()159 void pawn_parameter() {
160
161 // UCI options
162
163 PawnStructureWeight = (option_get_int("Pawn Structure") * 256 + 50) / 100;
164
165 }
166
167 // pawn_init()
168
pawn_init()169 void pawn_init() {
170
171 int rank;
172
173 // UCI options
174
175 pawn_parameter();
176
177 // bonus
178
179 for (rank = 0; rank < RankNb; rank++) Bonus[rank] = 0;
180
181 Bonus[Rank4] = 26;
182 Bonus[Rank5] = 77;
183 Bonus[Rank6] = 154;
184 Bonus[Rank7] = 256;
185
186 // pawn hash-table
187
188 Pawn->size = 0;
189 Pawn->mask = 0;
190 Pawn->table = NULL;
191 }
192
193 // pawn_alloc()
194
pawn_alloc()195 void pawn_alloc() {
196
197 ASSERT(sizeof(entry_t)==16);
198
199 if (UseTable) {
200
201 Pawn->size = TableSize;
202 Pawn->mask = TableSize - 1;
203 Pawn->table = (entry_t *) my_malloc(Pawn->size*sizeof(entry_t));
204
205 pawn_clear();
206 }
207 }
208
209 // pawn_clear()
210
pawn_clear()211 void pawn_clear() {
212
213 if (Pawn->table != NULL) {
214 memset(Pawn->table,0,Pawn->size*sizeof(entry_t));
215 }
216
217 Pawn->used = 0;
218 Pawn->read_nb = 0;
219 Pawn->read_hit = 0;
220 Pawn->write_nb = 0;
221 Pawn->write_collision = 0;
222 }
223
224 // pawn_get_info()
225
pawn_get_info(pawn_info_t * info,const board_t * board)226 void pawn_get_info(pawn_info_t * info, const board_t * board) {
227
228 uint64 key;
229 entry_t * entry;
230
231 ASSERT(info!=NULL);
232 ASSERT(board!=NULL);
233
234 // probe
235
236 if (UseTable) {
237
238 Pawn->read_nb++;
239
240 key = board->pawn_key;
241 entry = &Pawn->table[KEY_INDEX(key)&Pawn->mask];
242
243 if (entry->lock == KEY_LOCK(key)) {
244
245 // found
246
247 Pawn->read_hit++;
248
249 *info = *entry;
250
251 return;
252 }
253 }
254
255 // calculation
256
257 pawn_comp_info(info,board);
258
259 // store
260
261 if (UseTable) {
262
263 Pawn->write_nb++;
264
265 if (entry->lock == 0) { // HACK: assume free entry
266 Pawn->used++;
267 } else {
268 Pawn->write_collision++;
269 }
270
271 *entry = *info;
272 entry->lock = KEY_LOCK(key);
273 }
274 }
275
276 // pawn_comp_info()
277
pawn_comp_info(pawn_info_t * info,const board_t * board)278 static void pawn_comp_info(pawn_info_t * info, const board_t * board) {
279
280 int colour;
281 int file, rank;
282 int me, opp;
283 const sq_t * ptr;
284 int sq;
285 bool backward, candidate, doubled, isolated, open, passed;
286 int t1, t2;
287 int n;
288 int bits;
289 int opening[ColourNb], endgame[ColourNb];
290 int flags[ColourNb];
291 int file_bits[ColourNb];
292 int passed_bits[ColourNb];
293 int single_file[ColourNb];
294
295 ASSERT(info!=NULL);
296 ASSERT(board!=NULL);
297
298 // pawn_file[]
299
300 #if DEBUG
301 for (colour = 0; colour < ColourNb; colour++) {
302
303 int pawn_file[FileNb];
304
305 me = colour;
306
307 for (file = 0; file < FileNb; file++) {
308 pawn_file[file] = 0;
309 }
310
311 for (ptr = &board->pawn[me][0]; (sq=*ptr) != SquareNone; ptr++) {
312
313 file = SQUARE_FILE(sq);
314 rank = PAWN_RANK(sq,me);
315
316 ASSERT(file>=FileA&&file<=FileH);
317 ASSERT(rank>=Rank2&&rank<=Rank7);
318
319 pawn_file[file] |= BIT(rank);
320 }
321
322 for (file = 0; file < FileNb; file++) {
323 if (board->pawn_file[colour][file] != pawn_file[file]) my_fatal("board->pawn_file[][]\n");
324 }
325 }
326 #endif
327
328 // init
329
330 for (colour = 0; colour < ColourNb; colour++) {
331
332 opening[colour] = 0;
333 endgame[colour] = 0;
334
335 flags[colour] = 0;
336 file_bits[colour] = 0;
337 passed_bits[colour] = 0;
338 single_file[colour] = SquareNone;
339 }
340
341 // features and scoring
342
343 for (colour = 0; colour < ColourNb; colour++) {
344
345 me = colour;
346 opp = COLOUR_OPP(me);
347
348 for (ptr = &board->pawn[me][0]; (sq=*ptr) != SquareNone; ptr++) {
349
350 // init
351
352 file = SQUARE_FILE(sq);
353 rank = PAWN_RANK(sq,me);
354
355 ASSERT(file>=FileA&&file<=FileH);
356 ASSERT(rank>=Rank2&&rank<=Rank7);
357
358 // flags
359
360 file_bits[me] |= BIT(file);
361 if (rank == Rank2) flags[me] |= BackRankFlag;
362
363 // features
364
365 backward = false;
366 candidate = false;
367 doubled = false;
368 isolated = false;
369 open = false;
370 passed = false;
371
372 t1 = board->pawn_file[me][file-1] | board->pawn_file[me][file+1];
373 t2 = board->pawn_file[me][file] | BitRev[board->pawn_file[opp][file]];
374
375 // doubled
376
377 if ((board->pawn_file[me][file] & BitLT[rank]) != 0) {
378 doubled = true;
379 }
380
381 // isolated and backward
382
383 if (t1 == 0) {
384
385 isolated = true;
386
387 } else if ((t1 & BitLE[rank]) == 0) {
388
389 backward = true;
390
391 // really backward?
392
393 if ((t1 & BitRank1[rank]) != 0) {
394
395 ASSERT(rank+2<=Rank8);
396
397 if (((t2 & BitRank1[rank])
398 | ((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitRank2[rank])) == 0) {
399
400 backward = false;
401 }
402
403 } else if (rank == Rank2 && ((t1 & BitEQ[rank+2]) != 0)) {
404
405 ASSERT(rank+3<=Rank8);
406
407 if (((t2 & BitRank2[rank])
408 | ((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitRank3[rank])) == 0) {
409
410 backward = false;
411 }
412 }
413 }
414
415 // open, candidate and passed
416
417 if ((t2 & BitGT[rank]) == 0) {
418
419 open = true;
420
421 if (((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitGT[rank]) == 0) {
422
423 passed = true;
424 passed_bits[me] |= BIT(file);
425
426 } else {
427
428 // candidate?
429
430 n = 0;
431
432 n += BIT_COUNT(board->pawn_file[me][file-1]&BitLE[rank]);
433 n += BIT_COUNT(board->pawn_file[me][file+1]&BitLE[rank]);
434
435 n -= BIT_COUNT(BitRev[board->pawn_file[opp][file-1]]&BitGT[rank]);
436 n -= BIT_COUNT(BitRev[board->pawn_file[opp][file+1]]&BitGT[rank]);
437
438 if (n >= 0) {
439
440 // safe?
441
442 n = 0;
443
444 n += BIT_COUNT(board->pawn_file[me][file-1]&BitEQ[rank-1]);
445 n += BIT_COUNT(board->pawn_file[me][file+1]&BitEQ[rank-1]);
446
447 n -= BIT_COUNT(BitRev[board->pawn_file[opp][file-1]]&BitEQ[rank+1]);
448 n -= BIT_COUNT(BitRev[board->pawn_file[opp][file+1]]&BitEQ[rank+1]);
449
450 if (n >= 0) candidate = true;
451 }
452 }
453 }
454
455 // score
456
457 if (doubled) {
458 opening[me] -= DoubledOpening;
459 endgame[me] -= DoubledEndgame;
460 }
461
462 if (isolated) {
463 if (open) {
464 opening[me] -= IsolatedOpeningOpen;
465 endgame[me] -= IsolatedEndgame;
466 } else {
467 opening[me] -= IsolatedOpening;
468 endgame[me] -= IsolatedEndgame;
469 }
470 }
471
472 if (backward) {
473 if (open) {
474 opening[me] -= BackwardOpeningOpen;
475 endgame[me] -= BackwardEndgame;
476 } else {
477 opening[me] -= BackwardOpening;
478 endgame[me] -= BackwardEndgame;
479 }
480 }
481
482 if (candidate) {
483 opening[me] += quad(CandidateOpeningMin,CandidateOpeningMax,rank);
484 endgame[me] += quad(CandidateEndgameMin,CandidateEndgameMax,rank);
485 }
486
487 // this was moved to the dynamic evaluation
488
489 /*
490 if (passed) {
491 opening[me] += quad(PassedOpeningMin,PassedOpeningMax,rank);
492 endgame[me] += quad(PassedEndgameMin,PassedEndgameMax,rank);
493 }
494 */
495 }
496 }
497
498 // store info
499
500 info->opening = ((opening[White] - opening[Black]) * PawnStructureWeight) / 256;
501 info->endgame = ((endgame[White] - endgame[Black]) * PawnStructureWeight) / 256;
502
503 for (colour = 0; colour < ColourNb; colour++) {
504
505 me = colour;
506 opp = COLOUR_OPP(me);
507
508 // draw flags
509
510 bits = file_bits[me];
511
512 if (bits != 0 && (bits & (bits-1)) == 0) { // one set bit
513
514 file = BIT_FIRST(bits);
515 rank = BIT_FIRST(board->pawn_file[me][file]);
516 ASSERT(rank>=Rank2);
517
518 if (((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitGT[rank]) == 0) {
519 rank = BIT_LAST(board->pawn_file[me][file]);
520 single_file[me] = SQUARE_MAKE(file,rank);
521 }
522 }
523
524 info->flags[colour] = flags[colour];
525 info->passed_bits[colour] = passed_bits[colour];
526 info->single_file[colour] = single_file[colour];
527 }
528 }
529
530 // quad()
531
quad(int y_min,int y_max,int x)532 int quad(int y_min, int y_max, int x) {
533
534 int y;
535
536 ASSERT(y_min>=0&&y_min<=y_max&&y_max<=+32767);
537 ASSERT(x>=Rank2&&x<=Rank7);
538
539 y = y_min + ((y_max - y_min) * Bonus[x] + 128) / 256;
540 ASSERT(y>=y_min&&y<=y_max);
541
542 return y;
543 }
544
545 // end of pawn.cpp
546
547