1 
2 // material.cpp
3 
4 // includes
5 
6 #include <cstring>
7 
8 #include "board.h"
9 #include "colour.h"
10 #include "hash.h"
11 #include "material.h"
12 #include "option.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 = 256; // 4kB
22 
23 static const int PawnPhase   = 0;
24 static const int KnightPhase = 1;
25 static const int BishopPhase = 1;
26 static const int RookPhase   = 2;
27 static const int QueenPhase  = 4;
28 
29 static const int TotalPhase = PawnPhase * 16 + KnightPhase * 4 + BishopPhase * 4 + RookPhase * 4 + QueenPhase * 2;
30 
31 // constants and variables
32 
33 #define ABS(x) ((x)<0?-(x):(x))
34 
35 static /* const */ int OpeningExchangePenalty = 30; /* Thomas penalty exchange piece pawn */
36 static /* const */ int EndgameExchangePenalty = 30;
37 
38 static /* const */ int MaterialWeight = 256; // 100%
39 
40 static const int PawnOpening   = 70; // was 100 80
41 static const int PawnEndgame   = 90; // was 100
42 static const int KnightOpening = 325;
43 static const int KnightEndgame = 325;
44 static const int BishopOpening = 325;
45 static const int BishopEndgame = 325;
46 static const int RookOpening   = 500;
47 static const int RookEndgame   = 500;
48 static const int QueenOpening  = 975; //1000;
49 static const int QueenEndgame  = 975; //1000;
50 
51 static const int BishopPairOpening = 50;
52 static const int BishopPairEndgame = 50;
53 
54 // types
55 
56 typedef material_info_t entry_t;
57 
58 struct material_t {
59    entry_t * table;
60    uint32 size;
61    uint32 mask;
62    uint32 used;
63    sint64 read_nb;
64    sint64 read_hit;
65    sint64 write_nb;
66    sint64 write_collision;
67 };
68 
69 // variables
70 
71 static material_t Material[1];
72 
73 // prototypes
74 
75 static void material_comp_info (material_info_t * info, const board_t * board);
76 
77 // functions
78 
79 // material_init()
80 
material_parameter()81 void material_parameter() {
82 
83    // UCI options
84 
85    MaterialWeight = (option_get_int("Material") * 256 + 50) / 100;
86    OpeningExchangePenalty = option_get_int("Toga Exchange Bonus");
87    EndgameExchangePenalty = OpeningExchangePenalty;
88 
89 }
90 
91 // material_init()
92 
material_init()93 void material_init() {
94 
95    // UCI options
96 
97    material_parameter();
98 
99    // material table
100 
101    Material->size = 0;
102    Material->mask = 0;
103    Material->table = NULL;
104 }
105 
106 // material_alloc()
107 
material_alloc()108 void material_alloc() {
109 
110    ASSERT(sizeof(entry_t)==16);
111 
112    if (UseTable) {
113 
114       Material->size = TableSize;
115       Material->mask = TableSize - 1;
116       Material->table = (entry_t *) my_malloc(Material->size*sizeof(entry_t));
117 
118       material_clear();
119    }
120 }
121 
122 // material_clear()
123 
material_clear()124 void material_clear() {
125 
126    if (Material->table != NULL) {
127       memset(Material->table,0,Material->size*sizeof(entry_t));
128    }
129 
130    Material->used = 0;
131    Material->read_nb = 0;
132    Material->read_hit = 0;
133    Material->write_nb = 0;
134    Material->write_collision = 0;
135 }
136 
137 // material_get_info()
138 
material_get_info(material_info_t * info,const board_t * board)139 void material_get_info(material_info_t * info, const board_t * board) {
140 
141    uint64 key;
142    entry_t * entry;
143 
144    ASSERT(info!=NULL);
145    ASSERT(board!=NULL);
146 
147    // probe
148 
149    if (UseTable) {
150 
151       Material->read_nb++;
152 
153       key = board->material_key;
154       entry = &Material->table[KEY_INDEX(key)&Material->mask];
155 
156       if (entry->lock == KEY_LOCK(key)) {
157 
158          // found
159 
160          Material->read_hit++;
161 
162          *info = *entry;
163 
164          return;
165       }
166    }
167 
168    // calculation
169 
170    material_comp_info(info,board);
171 
172    // store
173 
174    if (UseTable) {
175 
176       Material->write_nb++;
177 
178       if (entry->lock == 0) { // HACK: assume free entry
179          Material->used++;
180       } else {
181          Material->write_collision++;
182       }
183 
184       *entry = *info;
185       entry->lock = KEY_LOCK(key);
186    }
187 }
188 
189 // material_comp_info()
190 
material_comp_info(material_info_t * info,const board_t * board)191 static void material_comp_info(material_info_t * info, const board_t * board) {
192 
193    int wp, wn, wb, wr, wq;
194    int bp, bn, bb, br, bq;
195    int wt, bt;
196    int wm, bm;
197    int colour;
198    int recog;
199    int flags;
200    int cflags[ColourNb];
201    int mul[ColourNb];
202    int phase;
203    int opening, endgame;
204    int owf,obf,ewf,ebf; /* Thomas */
205 //    int WhiteMinors,BlackMinors,WhiteMajors,BlackMajors
206 
207    ASSERT(info!=NULL);
208    ASSERT(board!=NULL);
209 
210    // init
211 
212    wp = board->number[WhitePawn12];
213    wn = board->number[WhiteKnight12];
214    wb = board->number[WhiteBishop12];
215    wr = board->number[WhiteRook12];
216    wq = board->number[WhiteQueen12];
217 
218    bp = board->number[BlackPawn12];
219    bn = board->number[BlackKnight12];
220    bb = board->number[BlackBishop12];
221    br = board->number[BlackRook12];
222    bq = board->number[BlackQueen12];
223 
224    wt = wq + wr + wb + wn + wp; // no king
225    bt = bq + br + bb + bn + bp; // no king
226 
227    wm = wb + wn;
228    bm = bb + bn;
229 
230    // recogniser
231 
232    recog = MAT_NONE;
233 
234    if (false) {
235 
236    } else if (wt == 0 && bt == 0) {
237 
238       recog = MAT_KK;
239 
240    } else if (wt == 1 && bt == 0) {
241 
242       if (wb == 1) recog = MAT_KBK;
243       if (wn == 1) recog = MAT_KNK;
244       if (wp == 1) recog = MAT_KPK;
245 
246    } else if (wt == 0 && bt == 1) {
247 
248       if (bb == 1) recog = MAT_KKB;
249       if (bn == 1) recog = MAT_KKN;
250       if (bp == 1) recog = MAT_KKP;
251 
252    } else if (wt == 1 && bt == 1) {
253 
254       if (wq == 1 && bq == 1) recog = MAT_KQKQ;
255       if (wq == 1 && bp == 1) recog = MAT_KQKP;
256       if (wp == 1 && bq == 1) recog = MAT_KPKQ;
257 
258       if (wr == 1 && br == 1) recog = MAT_KRKR;
259       if (wr == 1 && bp == 1) recog = MAT_KRKP;
260       if (wp == 1 && br == 1) recog = MAT_KPKR;
261 
262       if (wb == 1 && bb == 1) recog = MAT_KBKB;
263       if (wb == 1 && bp == 1) recog = MAT_KBKP;
264       if (wp == 1 && bb == 1) recog = MAT_KPKB;
265 
266       if (wn == 1 && bn == 1) recog = MAT_KNKN;
267       if (wn == 1 && bp == 1) recog = MAT_KNKP;
268       if (wp == 1 && bn == 1) recog = MAT_KPKN;
269 
270    } else if (wt == 2 && bt == 0) {
271 
272       if (wb == 1 && wp == 1) recog = MAT_KBPK;
273       if (wn == 1 && wp == 1) recog = MAT_KNPK;
274 
275    } else if (wt == 0 && bt == 2) {
276 
277       if (bb == 1 && bp == 1) recog = MAT_KKBP;
278       if (bn == 1 && bp == 1) recog = MAT_KKNP;
279 
280    } else if (wt == 2 && bt == 1) {
281 
282       if (wr == 1 && wp == 1 && br == 1) recog = MAT_KRPKR;
283       if (wb == 1 && wp == 1 && bb == 1) recog = MAT_KBPKB;
284 
285    } else if (wt == 1 && bt == 2) {
286 
287       if (wr == 1 && br == 1 && bp == 1) recog = MAT_KRKRP;
288       if (wb == 1 && bb == 1 && bp == 1) recog = MAT_KBKBP;
289    }
290 
291    // draw node (exact-draw recogniser)
292 
293    flags = 0; // TODO: MOVE ME
294    for (colour = 0; colour < ColourNb; colour++) cflags[colour] = 0;
295 
296    if (wq+wr+wp == 0 && bq+br+bp == 0) { // no major piece or pawn
297       if (wm + bm <= 1 // at most one minor => KK, KBK or KNK
298        || recog == MAT_KBKB) {
299          flags |= DrawNodeFlag;
300       }
301    } else if (recog == MAT_KPK  || recog == MAT_KKP
302            || recog == MAT_KBPK || recog == MAT_KKBP) {
303       flags |= DrawNodeFlag;
304    }
305 
306    // bishop endgame
307 
308    if (wq+wr+wn == 0 && bq+br+bn == 0) { // only bishops
309       if (wb == 1 && bb == 1) {
310          if (wp-bp >= -2 && wp-bp <= +2) { // pawn diff <= 2
311             flags |= DrawBishopFlag;
312          }
313       }
314    }
315 
316    // multipliers
317 
318    for (colour = 0; colour < ColourNb; colour++) mul[colour] = 16; // 1
319 
320    // white multiplier
321 
322    if (wp == 0) { // white has no pawns
323 
324       int w_maj = wq * 2 + wr;
325       int w_min = wb + wn;
326       int w_tot = w_maj * 2 + w_min;
327 
328       int b_maj = bq * 2 + br;
329       int b_min = bb + bn;
330       int b_tot = b_maj * 2 + b_min;
331 
332       if (false) {
333 
334       } else if (w_tot == 1) {
335 
336          ASSERT(w_maj==0);
337          ASSERT(w_min==1);
338 
339          // KBK* or KNK*, always insufficient
340 
341          mul[White] = 0;
342 
343       } else if (w_tot == 2 && wn == 2) {
344 
345          ASSERT(w_maj==0);
346          ASSERT(w_min==2);
347 
348          // KNNK*, usually insufficient
349 
350          if (b_tot != 0 || bp == 0) {
351             mul[White] = 0;
352          } else { // KNNKP+, might not be draw
353             mul[White] = 1; // 1/16
354          }
355 
356       } else if (w_tot == 2 && wb == 2 && b_tot == 1 && bn == 1) {
357 
358          ASSERT(w_maj==0);
359          ASSERT(w_min==2);
360          ASSERT(b_maj==0);
361          ASSERT(b_min==1);
362 
363          // KBBKN*, barely drawish (not at all?)
364 
365          mul[White] = 8; // 1/2
366 
367       } else if (w_tot-b_tot <= 1 && w_maj <= 2) {
368 
369          // no more than 1 minor up, drawish
370 
371          mul[White] = 2; // 1/8
372       }
373 
374    } else if (wp == 1) { // white has one pawn
375 
376       int w_maj = wq * 2 + wr;
377       int w_min = wb + wn;
378       int w_tot = w_maj * 2 + w_min;
379 
380       int b_maj = bq * 2 + br;
381       int b_min = bb + bn;
382       int b_tot = b_maj * 2 + b_min;
383 
384       if (false) {
385 
386       } else if (b_min != 0) {
387 
388          // assume black sacrifices a minor against the lone pawn
389 
390          b_min--;
391          b_tot--;
392 
393          if (false) {
394 
395          } else if (w_tot == 1) {
396 
397             ASSERT(w_maj==0);
398             ASSERT(w_min==1);
399 
400             // KBK* or KNK*, always insufficient
401 
402             mul[White] = 4; // 1/4
403 
404          } else if (w_tot == 2 && wn == 2) {
405 
406             ASSERT(w_maj==0);
407             ASSERT(w_min==2);
408 
409             // KNNK*, usually insufficient
410 
411             mul[White] = 4; // 1/4
412 
413          } else if (w_tot-b_tot <= 1 && w_maj <= 2) {
414 
415             // no more than 1 minor up, drawish
416 
417             mul[White] = 8; // 1/2
418          }
419 
420       } else if (br != 0) {
421 
422          // assume black sacrifices a rook against the lone pawn
423 
424          b_maj--;
425          b_tot -= 2;
426 
427          if (false) {
428 
429          } else if (w_tot == 1) {
430 
431             ASSERT(w_maj==0);
432             ASSERT(w_min==1);
433 
434             // KBK* or KNK*, always insufficient
435 
436             mul[White] = 4; // 1/4
437 
438          } else if (w_tot == 2 && wn == 2) {
439 
440             ASSERT(w_maj==0);
441             ASSERT(w_min==2);
442 
443             // KNNK*, usually insufficient
444 
445             mul[White] = 4; // 1/4
446 
447          } else if (w_tot-b_tot <= 1 && w_maj <= 2) {
448 
449             // no more than 1 minor up, drawish
450 
451             mul[White] = 8; // 1/2
452          }
453       }
454    }
455 
456    // black multiplier
457 
458    if (bp == 0) { // black has no pawns
459 
460       int w_maj = wq * 2 + wr;
461       int w_min = wb + wn;
462       int w_tot = w_maj * 2 + w_min;
463 
464       int b_maj = bq * 2 + br;
465       int b_min = bb + bn;
466       int b_tot = b_maj * 2 + b_min;
467 
468       if (false) {
469 
470       } else if (b_tot == 1) {
471 
472          ASSERT(b_maj==0);
473          ASSERT(b_min==1);
474 
475          // KBK* or KNK*, always insufficient
476 
477          mul[Black] = 0;
478 
479       } else if (b_tot == 2 && bn == 2) {
480 
481          ASSERT(b_maj==0);
482          ASSERT(b_min==2);
483 
484          // KNNK*, usually insufficient
485 
486          if (w_tot != 0 || wp == 0) {
487             mul[Black] = 0;
488          } else { // KNNKP+, might not be draw
489             mul[Black] = 1; // 1/16
490          }
491 
492       } else if (b_tot == 2 && bb == 2 && w_tot == 1 && wn == 1) {
493 
494          ASSERT(b_maj==0);
495          ASSERT(b_min==2);
496          ASSERT(w_maj==0);
497          ASSERT(w_min==1);
498 
499          // KBBKN*, barely drawish (not at all?)
500 
501          mul[Black] = 8; // 1/2
502 
503       } else if (b_tot-w_tot <= 1 && b_maj <= 2) {
504 
505          // no more than 1 minor up, drawish
506 
507          mul[Black] = 2; // 1/8
508       }
509 
510    } else if (bp == 1) { // black has one pawn
511 
512       int w_maj = wq * 2 + wr;
513       int w_min = wb + wn;
514       int w_tot = w_maj * 2 + w_min;
515 
516       int b_maj = bq * 2 + br;
517       int b_min = bb + bn;
518       int b_tot = b_maj * 2 + b_min;
519 
520       if (false) {
521 
522       } else if (w_min != 0) {
523 
524          // assume white sacrifices a minor against the lone pawn
525 
526          w_min--;
527          w_tot--;
528 
529          if (false) {
530 
531          } else if (b_tot == 1) {
532 
533             ASSERT(b_maj==0);
534             ASSERT(b_min==1);
535 
536             // KBK* or KNK*, always insufficient
537 
538             mul[Black] = 4; // 1/4
539 
540          } else if (b_tot == 2 && bn == 2) {
541 
542             ASSERT(b_maj==0);
543             ASSERT(b_min==2);
544 
545             // KNNK*, usually insufficient
546 
547             mul[Black] = 4; // 1/4
548 
549          } else if (b_tot-w_tot <= 1 && b_maj <= 2) {
550 
551             // no more than 1 minor up, drawish
552 
553             mul[Black] = 8; // 1/2
554          }
555 
556       } else if (wr != 0) {
557 
558          // assume white sacrifices a rook against the lone pawn
559 
560          w_maj--;
561          w_tot -= 2;
562 
563          if (false) {
564 
565          } else if (b_tot == 1) {
566 
567             ASSERT(b_maj==0);
568             ASSERT(b_min==1);
569 
570             // KBK* or KNK*, always insufficient
571 
572             mul[Black] = 4; // 1/4
573 
574          } else if (b_tot == 2 && bn == 2) {
575 
576             ASSERT(b_maj==0);
577             ASSERT(b_min==2);
578 
579             // KNNK*, usually insufficient
580 
581             mul[Black] = 4; // 1/4
582 
583          } else if (b_tot-w_tot <= 1 && b_maj <= 2) {
584 
585             // no more than 1 minor up, drawish
586 
587             mul[Black] = 8; // 1/2
588          }
589       }
590    }
591 
592    // potential draw for white
593 
594    if (wt == wb+wp && wp >= 1) cflags[White] |= MatRookPawnFlag;
595    if (wt == wb+wp && wb <= 1 && wp >= 1 && bt > bp) cflags[White] |= MatBishopFlag;
596 
597    if (wt == 2 && wn == 1 && wp == 1 && bt > bp) cflags[White] |= MatKnightFlag;
598 
599    // potential draw for black
600 
601    if (bt == bb+bp && bp >= 1) cflags[Black] |= MatRookPawnFlag;
602    if (bt == bb+bp && bb <= 1 && bp >= 1 && wt > wp) cflags[Black] |= MatBishopFlag;
603 
604    if (bt == 2 && bn == 1 && bp == 1 && wt > wp) cflags[Black] |= MatKnightFlag;
605 
606    // draw leaf (likely draw)
607 
608    if (recog == MAT_KQKQ || recog == MAT_KRKR) {
609       mul[White] = 0;
610       mul[Black] = 0;
611    }
612 
613    // king safety
614 
615    if (bq >= 1 && bq+br+bb+bn >= 2) cflags[White] |= MatKingFlag;
616    if (wq >= 1 && wq+wr+wb+wn >= 2) cflags[Black] |= MatKingFlag;
617 
618    // phase (0: opening -> 256: endgame)
619 
620    phase = TotalPhase;
621 
622    phase -= wp * PawnPhase;
623    phase -= wn * KnightPhase;
624    phase -= wb * BishopPhase;
625    phase -= wr * RookPhase;
626    phase -= wq * QueenPhase;
627 
628    phase -= bp * PawnPhase;
629    phase -= bn * KnightPhase;
630    phase -= bb * BishopPhase;
631    phase -= br * RookPhase;
632    phase -= bq * QueenPhase;
633 
634    if (phase < 0) phase = 0;
635 
636    ASSERT(phase>=0&&phase<=TotalPhase);
637    phase = (phase * 256 + (TotalPhase / 2)) / TotalPhase;
638 
639    ASSERT(phase>=0&&phase<=256);
640 
641    // material
642 
643    opening = 0;
644    endgame = 0;
645 
646    /* Thomas */
647    owf = wn*KnightOpening + wb*BishopOpening + wr*RookOpening + wq*QueenOpening;
648    info->pv[White] = owf;
649    opening += owf;
650    opening += wp * PawnOpening;
651 
652    obf = bn*KnightOpening + bb*BishopOpening + br*RookOpening + bq*QueenOpening;
653    info->pv[Black] = obf;
654    opening -= obf;
655    opening -= bp * PawnOpening;
656 
657    ewf = wn*KnightEndgame + wb*BishopEndgame + wr*RookEndgame + wq*QueenEndgame;
658    endgame += wp * PawnEndgame;
659    endgame += ewf;
660 
661    ebf = bn*KnightEndgame + bb*BishopEndgame + br*RookEndgame + bq*QueenEndgame;
662    endgame -= bp * PawnEndgame;
663    endgame -= ebf;
664 
665 /*   WhiteMinors = wn + wb;
666    BlackMinors = bn + bb;
667    WhiteMajors = 2*wq + wr;
668    BlackMajors = 2*bq + br; */
669 
670    // Trade Bonus
671 
672 /*   if (owf > obf && bp > wp){
673 	   opening += OpeningExchangePenalty;
674 	   endgame += OpeningExchangePenalty;
675    }
676    else if (obf > owf && wp > bp){
677 	   opening -= OpeningExchangePenalty;
678 	   endgame -= OpeningExchangePenalty;
679    }  */
680 /*   if (WhiteMinors != BlackMinors) {
681 		if (WhiteMajors == BlackMajors) {
682 		  if (WhiteMinors > BlackMinors){
683 			opening += OpeningExchangePenalty / 2;
684 			endgame += OpeningExchangePenalty / 2;
685 		  }
686 		  else{
687 			opening -= OpeningExchangePenalty / 2;
688 			endgame -= OpeningExchangePenalty / 2;
689 		  }
690 		}
691 	} */
692 
693    // Adjust knight and rook material values
694    // White
695    /* opening += wr * (5 - wp) * PawnOpening/8;
696    endgame += wr * (5 - wp) * PawnEndgame/8;
697 
698    opening += wn * (wp - 5) * PawnOpening/16;
699    endgame += wn * (wp - 5) * PawnEndgame/16;
700 
701    // Black
702    opening -= br * (5 - bp) * PawnOpening/8;
703    endgame -= br * (5 - bp) * PawnEndgame/8;
704 
705    opening -= bn * (bp - 5) * PawnOpening/16;
706    endgame -= bn * (bp - 5) * PawnEndgame/16; */
707 
708    // bishop pair
709 
710    if (wb >= 2) { // HACK: assumes different colours
711       opening += BishopPairOpening;
712       endgame += BishopPairEndgame;
713    }
714 
715    if (bb >= 2) { // HACK: assumes different colours
716       opening -= BishopPairOpening;
717       endgame -= BishopPairEndgame;
718    }
719 
720    // store info
721 
722    info->recog = recog;
723    info->flags = flags;
724    for (colour = 0; colour < ColourNb; colour++) info->cflags[colour] = cflags[colour];
725    for (colour = 0; colour < ColourNb; colour++) info->mul[colour] = mul[colour];
726    info->phase = phase;
727    info->opening = (opening * MaterialWeight) / 256;
728    info->endgame = (endgame * MaterialWeight) / 256;
729 }
730 
731 // end of material.cpp
732 
733