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