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