1 #include "includes.h"
2 #include "knightcap.h"
3
4 /* the "brain" is an implementation of the permanent brain idea common
5 in chess programs.
6
7 In KnightCap it is also used to develop its own opening book. This
8 is done by pondering the positions in the brain while idle,
9 constantly refining them.
10 */
11
12 extern struct state *state;
13
14 #define MAX_BRAIN_SIZE 10000
15 #define MAX_BRAIN_MOVE 30
16 #define MIN_MULL_TIME (30)
17 #define BRAIN_TEMP_SIZE MAX_GAME_MOVES
18 #define WHITE_THRESHOLD (tanh(0.0*EVAL_SCALE*PAWN_VALUE))
19 #define BLACK_THRESHOLD (tanh(0.0*EVAL_SCALE*PAWN_VALUE))
20 #define FLAG_NEEDS_RESEARCH (1<<0)
21 #define FLAG_NEVER_RESEARCH (1<<1)
22 #define MIN_DEPTH 12
23 #define SAVE_FREQUENCY 300 /* in seconds */
24
25 static int mulled_one_opening;
26 static int max_mull_time[4] = {30, 30, 120, 120};
27 int mull_stage;
28 extern int fill_hash;
29
30 int testing = 0;
31
32 struct brain_entry {
33 uint32 hash1;
34 uint32 hash2;
35 int eval_low;
36 int eval_high;
37 char depth_low;
38 char depth_high;
39 Square from, to;
40 int search_time; /* how long we've spent searching this pos */
41 time_t last_play; /* when we last used this entry */
42 time_t last_search; /* when we did the last search */
43 Piece board[NUM_SQUARES];
44 uint32 flags;
45 uint32 flags2;
46 unsigned short move_num;
47 Square enpassent;
48 uint32 white_wins, black_wins;
49 uint32 unused;
50 };
51
52
53 static int done_lookup;
54 static int brain_size;
55 static struct brain_entry brain[MAX_BRAIN_SIZE + BRAIN_TEMP_SIZE];
56 static struct brain_entry *brain_temp = &brain[MAX_BRAIN_SIZE];
57 static int brain_temp_size;
58 static int mull_entry;
59 static int last_hit;
60 static char *brain_fname;
61 static int load_failed;
62 static int refined_count;
63
64 int mulling=0;
65
66 extern int learning;
67
68 static void consistency_check1(struct brain_entry *br);
69 static void consistency_check2(struct brain_entry *br);
70
converged(struct hash_entry * t)71 static inline int converged(struct hash_entry *t)
72 {
73 return (t->low.v + MTD_THRESHOLD >= t->high.v) &&
74 (t->depth_low == t->depth_high);
75 }
76
consistent(struct hash_entry * t1,struct hash_entry * t2)77 static inline int consistent(struct hash_entry *t1, struct hash_entry *t2)
78 {
79 return ((t1->from == t2->from && t1->to == t2->to) &&
80 !(t1->low.v > t2->high.v || t1->high.v < t2->low.v));
81 }
82
83
save_blunder(Position * b,struct brain_entry * br,Move * next_move)84 static inline void save_blunder(Position *b, struct brain_entry *br, Move *next_move)
85 {
86 static int initialised;
87 static FILE *f;
88
89 if (!initialised) {
90 initialised = 1;
91 f = fopen("blunder.dat", "a");
92 }
93
94 fprintf(f, "%s %s%s %s %d %d\n", position_to_ppn(b), posstr(br->from), posstr(br->to),
95 short_movestr(b, next_move), br->depth_low, br->depth_high);
96
97 }
98
play_offset(int move_num)99 static inline int play_offset(int move_num)
100 {
101 return 60*60*24*move_num;
102 }
103
104 /* return a string describing a brain entry */
entry_str(struct brain_entry * br)105 static char *entry_str(struct brain_entry *br)
106 {
107 Move m1;
108 static char s[1000];
109
110 m1.from = br->from;
111 m1.to = br->to;
112
113 sprintf(s,"depth=%d/%d num=%d time=%d v=%d/%d move=%s hash1=%08x %s",
114 br->depth_low,
115 br->depth_high,
116 br->move_num,
117 br->search_time,
118 br->eval_low,
119 br->eval_high,
120 short_movestr(NULL, &m1),
121 br->hash1,
122 ctime(&br->last_play));
123
124 return s;
125 }
126
brain_compare(const void * bb1,const void * bb2)127 static int brain_compare(const void *bb1, const void *bb2)
128 {
129 struct brain_entry *b1;
130 struct brain_entry *b2;
131
132 b1 = (struct brain_entry *)bb1;
133 b2 = (struct brain_entry *)bb2;
134
135 if (b1->hash1 == 0) return 1;
136 if (b2->hash1 == 0) return -1;
137 if (b1->depth_low == -1) return 1;
138 if (b2->depth_low == -1) return -1;
139 if (b2->hash1 < b1->hash1)
140 return 1;
141 if (b2->hash1 > b1->hash1)
142 return -1;
143 return memcmp(b1->board, b2->board, sizeof(b1->board));
144 }
145
146 /* this one is used when saving to disk so the file remains the same
147 with no changes (good for rsync) */
brain_comp2(const void * bb1,const void * bb2)148 static int brain_comp2(const void *bb1, const void *bb2)
149 {
150 struct brain_entry *b1;
151 struct brain_entry *b2;
152
153 b1 = (struct brain_entry *)bb1;
154 b2 = (struct brain_entry *)bb2;
155
156 if (b1->hash1 == 0) return 1;
157 if (b2->hash1 == 0) return -1;
158 if (b1->last_play < b2->last_play)
159 return 1;
160 if (b1->last_play > b2->last_play)
161 return -1;
162 if (b2->move_num < b1->move_num)
163 return 1;
164 if (b2->move_num > b1->move_num)
165 return -1;
166 return memcmp(b1->board, b2->board, sizeof(b1->board));
167 }
168
169
setup_brain_pos(Position * b,struct brain_entry * br)170 static int setup_brain_pos(Position *b, struct brain_entry *br)
171 {
172 memset(b, 0, sizeof(*b));
173 memcpy(b->board, br->board, sizeof(b->board));
174 b->move_num = br->move_num;
175 b->flags = br->flags;
176 b->enpassent = br->enpassent;
177 b->fifty_count = 0;
178 br->hash1 = 0;
179 br->hash2 = 0;
180
181 if (!create_pboard(b)) {
182 lprintf(0,"brain entry corrupt\n");
183 br->depth_low = -1;
184 br->depth_high = -1;
185 return 0;
186 }
187 br->hash1 = b->hash1;
188 br->hash2 = b->hash2;
189
190 return 1;
191 }
192
brain_resort(void)193 static void brain_resort(void)
194 {
195 int i;
196
197 for (i=0;i<brain_size;i++) {
198 if (brain[i].depth_low == -1)
199 memset(&brain[i], 0, sizeof(brain[i]));
200 }
201
202 qsort(brain, brain_size, sizeof(brain[0]), brain_compare);
203 while (brain_size && brain[brain_size-1].hash1 == 0)
204 brain_size--;
205 }
206
207
208 /* rehash the brain to recreate the hash1 and hash2 entries then sort
209 on hash1 */
brain_rehash(void)210 static void brain_rehash(void)
211 {
212 int i;
213 Position b;
214 unsigned int sum1, sum2;
215 time_t t1;
216
217 /* first work out if the brain needs byte swapping */
218 sum1 = sum2 = 0;
219 for (i=0;i<brain_size;i++) {
220 sum1 += brain[i].move_num;
221 sum2 += swapu16(brain[i].move_num);
222 }
223
224 if (sum1 > sum2) {
225 lprintf(0,"byte swapping brain\n");
226 for (i=0;i<brain_size;i++) {
227 brain[i].eval_low = swap32(brain[i].eval_low);
228 brain[i].eval_high = swap32(brain[i].eval_high);
229 brain[i].search_time = swapu32(brain[i].search_time);
230 brain[i].last_play = swapu32(brain[i].last_play);
231 brain[i].last_search = swapu32(brain[i].last_search);
232 brain[i].flags = swapu32(brain[i].flags);
233 brain[i].flags2 = swapu32(brain[i].flags);
234 brain[i].move_num = swapu16(brain[i].move_num);
235 brain[i].white_wins = swapu32(brain[i].white_wins);
236 brain[i].black_wins = swapu32(brain[i].black_wins);
237 }
238 }
239
240
241 t1 = time(NULL);
242
243 for (i=0;i<brain_size;i++) {
244 if (brain[i].hash1 == 0) {
245 memset(&brain[i], 0, sizeof(brain[i]));
246 continue;
247 }
248
249 setup_brain_pos(&b, &brain[i]);
250
251 if (brain[i].last_play > t1 - play_offset(brain[i].move_num)) {
252 brain[i].last_play = t1 - play_offset(b.move_num);
253 }
254 }
255
256 brain_resort();
257
258 lprintf(0,"rehashed brain\n");
259 }
260
261
262 /* find a brain entry using only hash1 */
brain_find_hash1(uint32 hash1)263 static int brain_find_hash1(uint32 hash1)
264 {
265 int low,high, t;
266
267 if (brain_size == 0) return -1;
268
269 low = 0;
270 high = brain_size-1;
271 while (low < high) {
272 t = (low+high)/2;
273 if (brain[t].hash1 == hash1)
274 return t;
275 if (brain[t].hash1 < hash1) {
276 low = t+1;
277 } else {
278 high = t-1;
279 }
280 }
281 if (brain[low].hash1 == hash1)
282 return low;
283
284 if (state->brain_inserting) {
285 for (t=MAX_BRAIN_SIZE;t<MAX_BRAIN_SIZE+brain_temp_size;t++)
286 if (brain[t].hash1 == hash1)
287 return t;
288 }
289
290 return -1;
291 }
292
293 /* use a bisection search to try to find a brain entry matching the
294 specified position. We could possibly replace this with a hash table
295 lookup later if this proves too expensive */
brain_find(Position * b)296 static int brain_find(Position *b)
297 {
298 int t = brain_find_hash1(b->hash1);
299
300 if (t == -1) return -1;
301
302 if (brain[t].hash1 == b->hash1 &&
303 brain[t].hash2 == b->hash2)
304 return t;
305
306 return -1;
307 }
308
309
brain_fill_hash(Position * b)310 void brain_fill_hash(Position *b)
311 {
312 unsigned size;
313 int i, num;
314 struct hash_entry *t;
315 if (brain_size == 0) return;
316
317 if (mulling)
318 num = brain[mull_entry].move_num;
319 else
320 num = state->position.move_num;
321
322 for (i=0;i<brain_size;i++) {
323 if (brain[i].move_num <= num || brain[i].move_num > num + 20)
324 continue;
325
326 if (mulling && i == mull_entry) {
327 lprintf(0, "not inserted (mull entry): %08x %s", brain[i].flags2, entry_str(&brain[i]));
328 continue;
329 }
330
331 if (brain[i].flags2 & FLAG_NEEDS_RESEARCH) {
332 lprintf(0, "not inserted (needs research): %08x %s", brain[i].flags2, entry_str(&brain[i]));
333 continue;
334 }
335
336 if (ABS(brain[i].eval_low) < FORCED_WIN &&
337 brain[i].eval_low + 0.01*PAWN_VALUE < brain[i].eval_high) {
338 lprintf(0, "not inserted (unconverged): %08x %s", brain[i].flags2, entry_str(&brain[i]));
339 brain[i].flags2 |= FLAG_NEEDS_RESEARCH;
340 continue;
341 }
342
343 if (brain[i].depth_low == -1) {
344 lprintf(0, "not inserted (?): %08x %s", brain[i].flags2, entry_str(&brain[i]));
345 continue;
346 }
347
348 t = hash_ptr(brain[i].hash1);
349
350 size = hts();
351
352 if (num > 0 && t->move_num >= num) {
353 /* hash collision */
354 if (brain[i].move_num > t->move_num) {
355 lprintf(0,"hash collision %08x %08x %d %d\n", brain[i].hash1, t->hash1,
356 brain[i].move_num, t->move_num);
357 continue;
358 }
359 }
360
361 t->hash1 = brain[i].hash1;
362 t->hash2 = brain[i].hash2;
363 t->from = brain[i].from;
364 t->to = brain[i].to;
365 t->tag = 0;
366 t->move_num = brain[i].move_num;
367 t->depth_low = brain[i].depth_low;
368 t->low.v = brain[i].eval_low;
369 t->depth_high = brain[i].depth_high;
370 t->high.v = brain[i].eval_low;
371 }
372
373 lprintf(0,"filled hash table\n");
374
375 }
376
brain_save(void)377 static void brain_save(void)
378 {
379 int fd;
380 char tmpname[200];
381
382 if (brain_size+brain_temp_size == 0) return;
383
384 sprintf(tmpname,"%s.tmp",brain_fname);
385
386 fd = open(tmpname,O_WRONLY|O_CREAT|O_TRUNC, 0666);
387 if (fd == -1) {
388 lprintf(0,"can't open %s\n", tmpname);
389 return;
390 }
391
392 brain_resort();
393
394 qsort(brain, brain_size, sizeof(brain[0]), brain_comp2);
395
396 if (state->brain_inserting && brain_temp_size) {
397 int t = MAX_BRAIN_SIZE - brain_temp_size;
398 if (t > brain_size) {
399 t = brain_size;
400 } else {
401 int i;
402 lprintf(0,"overwriting %d entries\n", brain_size - t);
403 for (i=t;i<brain_size;i++)
404 lprintf(0,"entry %s", entry_str(&brain[i]));
405 }
406 memcpy(&brain[t], brain_temp, sizeof(brain[0])*brain_temp_size);
407
408 lprintf(0,"added %d brain entries\n", brain_temp_size);
409 brain_size = t + brain_temp_size;
410 brain_temp_size = 0;
411 }
412
413 if (Write(fd, (char *)brain, sizeof(brain[0])*brain_size) !=
414 sizeof(brain[0])*brain_size) {
415 lprintf(0,"write to %s failed\n", brain_fname);
416 close(fd);
417 brain_resort();
418 return;
419 }
420
421 close(fd);
422
423 if (rename(tmpname, brain_fname) != 0) {
424 lprintf(0,"rename %s %s failed\n",
425 tmpname, brain_fname);
426 }
427
428 lprintf(0,"brain saved\n");
429 brain_resort();
430 }
431
brain_timer(time_t t)432 static void brain_timer(time_t t)
433 {
434 static time_t lastt;
435
436 if (lastt + SAVE_FREQUENCY > t &&
437 brain_temp_size < BRAIN_TEMP_SIZE/2)
438 return;
439
440 lastt = t;
441
442 brain_save();
443 }
444
brain_open(char * fname)445 int brain_open(char *fname)
446 {
447 struct stat st;
448 int fd;
449
450 brain_size = 0;
451 load_failed = 1;
452
453 brain_fname = fname;
454
455 fd = open(fname,O_RDWR);
456 if (fd == -1) {
457 lprintf(0,"can't open %s\n", fname);
458 return 0;
459 }
460
461 if (fstat(fd, &st) != 0) {
462 lprintf(0,"fstat %s failed\n", fname);
463 close(fd);
464 return 0;
465 }
466
467 if (st.st_size % sizeof(brain[0]) != 0) {
468 lprintf(0,"corrupt brain file %s\n", fname);
469 close(fd);
470 return 0;
471 }
472
473 brain_size = st.st_size / sizeof(brain[0]);
474
475 if (Read(fd, (char *)brain, st.st_size) != st.st_size) {
476 lprintf(0,"brain read failed\n");
477 close(fd);
478 return 0;
479 }
480
481 close(fd);
482
483 load_failed=0;
484 brain_rehash();
485 brain_clean();
486 brain_update();
487
488 return 1;
489 }
490
491
492 /* lookup a position - using the brain as an opening book */
brain_lookup(Position * b,Move * move,Eval * v,int pondering)493 int brain_lookup(Position *b, Move *move, Eval *v, int pondering)
494 {
495 int t, num_moves, m, bm;
496 Position b1;
497 etype v1, max;
498 static Move moves[MAX_MOVES];
499
500 if (mulling || !brain_size || !state->use_pbrain) return 0;
501
502 #if USE_EGTB
503 if (egtb(b)) {
504 EGInit();
505 if (EGTBScore(b, &v1)) {
506 num_moves = generate_moves(b, moves);
507 max = -INFINITY;
508 bm = -1;
509 for (m=0;m<num_moves;m++) {
510 if (!do_move(&b1, b, &moves[m])) continue;
511 if (no_material(&b1) && max < 0) {
512 max = 0;
513 bm = m;
514 continue;
515 }
516 if (EGTBScore(&b1, &v1)) {
517 v1 = -v1;
518 if (v1 > max) {
519 max = v1;
520 bm = m;
521 }
522 }
523 }
524 if (bm < 0)
525 return 0;
526
527 (*v) = makeeval(b, v1);
528 move->from = moves[bm].from;
529 move->to = moves[bm].to;
530 move->v = max;
531
532 if (!legal_move(b, move) || !do_move(&b1, b, move)) {
533 lprintf(0,"Illegal move from EGTB! move=%s\n",
534 short_movestr(b, move));
535 return 0;
536 }
537
538 lprintf(0, "EGTB: %s %s\n", short_movestr(b, move), evalstr(move->v));
539
540 if (!pondering && state->ics_robot) {
541 prog_printf("whisper EGTB: %s %s\n", short_movestr(b, move),
542 evalstr(move->v));
543 }
544
545 return 2;
546 }
547 }
548 #endif
549
550 if (done_lookup == 0)
551 state->last_book_move = 0;
552
553 done_lookup = b->move_num;
554
555
556 t = brain_find(b);
557 if (t == -1) {
558 lprintf(0,"no brain entry\n");
559 return 0;
560 }
561
562 brain[t].last_play = timer_start_time() - play_offset(b->move_num);
563
564 if (brain[t].from == A1 && brain[t].to == A1) {
565 lprintf(0, "null move in brain entry\n");
566 return 0;
567 }
568
569 if (brain[t].eval_low + MTD_THRESHOLD < brain[t].eval_high) {
570 lprintf(0, "unconverged brain lookup %s\n", entry_str(&brain[t]));
571 return 0;
572 }
573
574 #if REJECT_LOW_BRAIN_MOVES
575 if (brain[t].eval_low < -0.4*PAWN_VALUE) {
576 lprintf(0,"book move too weak: %s", entry_str(&brain[t]));
577 return 0;
578 }
579 #endif
580
581 last_hit = b->move_num;
582
583 (*v) = makeeval(b, brain[t].eval_low);
584 move->from = brain[t].from;
585 move->to = brain[t].to;
586 move->v = v->v;
587
588 brain_timer(time(NULL));
589
590 if (!legal_move(b, move) || !do_move(&b1, b, move)) {
591 lprintf(0,"Illegal move from book! move=%s\n",
592 short_movestr(b, move));
593 return 0;
594 }
595
596 if (check_repitition(&b1, 1))
597 return 0;
598
599 lprintf(0, "book: %s low=%d high=%d ww/bw=%d/%d depth=%d/%d searcht=%d\n",
600 short_movestr(b, move),
601 brain[t].eval_low,
602 brain[t].eval_high,
603 brain[t].white_wins,
604 brain[t].black_wins,
605 brain[t].depth_low,
606 brain[t].depth_high,
607 brain[t].search_time);
608
609 if (state->first_book_move) {
610 state->first_book_move = 0;
611 state->first_book_move_index = t;
612 }
613
614 if (!pondering) {
615 brain_temp[brain_temp_size] = brain[t];
616 lprintf(0,"inserted entry %s", entry_str(&(brain_temp[brain_temp_size])));
617 brain_temp_size++;
618 if (state->ics_robot) {
619 prog_printf("whisper Book: %s low=%5.3lf high=%5.3lf ww/bw=%d/%d depth=%d/%d searcht=%d\n",
620 short_movestr(b, move),
621 (double)brain[t].eval_low/PAWN_VALUE,
622 (double)brain[t].eval_high/PAWN_VALUE,
623 brain[t].white_wins,
624 brain[t].black_wins,
625 brain[t].depth_low,
626 brain[t].depth_high,
627 brain[t].search_time);
628 }
629 }
630 return 1;
631 }
632
633
634 /* possibly insert an entry into the brain */
brain_insert(Position * b,Move * move)635 int brain_insert(Position *b, Move *move)
636 {
637 int nohash = 0;
638 int t;
639 struct brain_entry *br;
640 Position b1;
641 struct hash_entry *h;
642
643 if (load_failed) return 0;
644
645 t = brain_find(b);
646
647 if (mulling && t != mull_entry) {
648 return 0;
649 }
650
651 if (state->brain_inserting && t != -1) {
652 br = &brain[t];
653 lprintf(0, "index: %d\n", t);
654 } else {
655 br = &brain_temp[brain_temp_size];
656 if (!mulling) {
657 brain_temp_size++;
658 memset(br, 0, sizeof(*br));
659 }
660 }
661
662 if (!do_move(&b1, b, move)) {
663 lprintf(0,"illegal move passed to brain_insert\n");
664 return 0;
665 }
666
667 h = fetch_hash(&b1);
668
669 if (!h) {
670 h = fetch_hash(b);
671 if (!h) {
672 lprintf(0,"no hash entry for brain_insert move\n");
673 return 0;
674 }
675 nohash = 1;
676 }
677
678 if (!converged(h)) {
679 if (!nohash) {
680 struct hash_entry *h1 = h;
681 h = fetch_hash(b);
682 if (!h) {
683 h = h1;
684 lprintf(0, "No hash entry for brain entry\n");
685 } else
686 nohash = 1;
687 }
688 }
689
690 if (!converged(h)) {
691 if (mulling && ABS(h->low.v) < FORCED_WIN && h->low.v != -INFINITY) {
692 lprintf(0, "not inserting: not converged %d/%d %d/%d\n",h->low.v, h->high.v,
693 h->depth_low, h->depth_high);
694 return 0;
695 }
696 lprintf(0, "inserting unconverged entry: %d/%d %d/%d %s%s\n",
697 h->low.v, h->high.v, h->depth_low, h->depth_high,
698 posstr(h->from), posstr(h->to));
699 state->converged = 0;
700 }
701
702 /* check if it is worth overwriting the old entry. at present
703 we just base the decision on the depths of the entries */
704
705 /* we are happy with this entry: reset the flags */
706 br->flags2 &= ~FLAG_BLUNDER;
707 br->flags2 &= ~FLAG_NEEDS_RESEARCH;
708
709 /* we've decided where to put it, finish it off */
710 br->hash1 = b->hash1;
711 br->hash2 = b->hash2;
712 if (nohash) {
713 br->eval_low = h->low.v;
714 br->eval_high = h->high.v;
715 } else {
716 br->eval_low = -h->high.v;
717 br->eval_high = -h->low.v;
718 }
719
720 if (nohash) {
721 br->depth_low = h->depth_low;
722 br->depth_high = h->depth_high;
723 } else {
724 br->depth_low = h->depth_high+1;
725 br->depth_high = h->depth_low+1;
726 }
727
728 br->from = move->from;
729 br->to = move->to;
730
731 br->search_time = timer_elapsed();
732 memcpy(br->board, b->board, sizeof(b->board));
733 br->flags = b->flags;
734 br->move_num = b->move_num;
735 br->enpassent = b->enpassent;
736 br->last_search = time(NULL);
737
738 if (!mulling) {
739 br->last_play = time(NULL) - play_offset(b->move_num);
740 }
741
742 lprintf(0,"inserted entry %s", entry_str(br));
743
744 if (br->depth_low < state->current_depth)
745 state->converged = 0;
746 else state->converged = 1;
747
748 if (mulling) {
749 br->depth_low = MIN_DEPTH;
750 br->depth_high = MIN_DEPTH;
751 consistency_check1(br);
752 consistency_check2(br);
753 brain_save();
754 }
755 brain_timer(time(NULL));
756
757 return 1;
758 }
759
brain_close(void)760 void brain_close(void)
761 {
762 brain_save();
763 }
764
765
choose_mull(void)766 static int choose_mull(void)
767 {
768 int t, r;
769 int bestt;
770 int last_move;
771 time_t last_play;
772 #if SEARCH_OPENING_VARIATIONS
773 Position b;
774 Move m;
775 #endif
776 lprintf(0,"stage 0 mulling: blunders\n");
777 state->open = 0;
778 /* the first priority is blunders, most recent ones first */
779 mull_stage= 0;
780 bestt = 0;
781 while (bestt != -1) {
782 bestt = -1;
783 last_play = time(NULL);
784
785 for (t=0;t<brain_size;t++) {
786 if (brain[t].hash1 == 0) continue;
787
788 if ((brain[t].flags2 & FLAG_BLUNDER) &&
789 !(brain[t].flags2 & FLAG_NEVER_RESEARCH)) {
790 if (bestt == -1 ||
791 brain[t].last_play < last_play) {
792 bestt = t;
793 last_play = brain[t].last_play;
794 }
795 }
796 }
797 if (bestt != -1) {
798 return bestt;
799 }
800 }
801
802 lprintf(0, "all blunders searched\n");
803
804 /* opening searched, now search longer on any unsearched moves */
805 stage2:
806 lprintf(0, "longer search\n");
807 mull_stage = 1;
808 lprintf(0, "stage 2 mull\n");
809 bestt = 0;
810 while (bestt!= -1) {
811 bestt = -1;
812 last_move = 0;
813
814 for (t=0;t<brain_size;t++) {
815 if (brain[t].hash1 == 0) continue;
816
817 if ((brain[t].flags2 & FLAG_NEEDS_RESEARCH) &&
818 !(brain[t].flags2 & FLAG_NEVER_RESEARCH)) {
819 if (brain[t].move_num >= last_move ||
820 bestt == -1) {
821 bestt = t;
822 last_move = brain[t].move_num;
823 }
824 }
825 }
826 if (bestt != -1) {
827 return bestt;
828 }
829 }
830
831 lprintf(0,"all entries searched\n");
832
833 if (!brain_clean())
834 goto stage2;
835
836 state->open = 1;
837 if (state->notified) {
838 prog_printf("tell %s My brain is now clean and I am accepting challenges\n",
839 state->notifyee);
840 prog_printf("accept\n");
841 state->notified = 0;
842 }
843 prog_printf("seeks\n");
844
845 if ((random() % 1) == 0 && mulled_one_opening) {
846
847 /* choose randomly, weighted towards guys near the start
848 and those that have not been searched for a while */
849
850 mull_stage = 2;
851 lprintf(0, "using random mull\n");
852 bestt = 0;
853 while (!state->quit && state->computer == 0) {
854 t = random() % brain_size;
855
856 if (brain[t].hash1 == 0) continue;
857
858 if (brain[t].flags2 & FLAG_NEVER_RESEARCH) continue;
859
860 if (imax(brain[t].depth_low, brain[t].depth_high) > MAX_DEPTH/2) continue;
861
862 /* don't mull on mate! */
863 if (brain[t].eval_low > (WIN-100) ||
864 brain[t].eval_high < -(WIN-100))
865 continue;
866
867 r = 100;
868
869 if (brain[t].move_num < 20)
870 r += (20 - brain[t].move_num)*(20 - brain[t].move_num)*100;
871
872 if (random() % 40100 >= r)
873 continue;
874
875 return t;
876 }
877 } else {
878 mulled_one_opening = 1;
879 #if SEARCH_OPENING_VARIATIONS
880
881 /* pick a very early move in the brain, follow the
882 resulting variation as far as it goes and then add
883 the end position to the brain and mull it.
884 Choose the opening in the last game played first. */
885
886 mull_stage = 3;
887
888 lprintf(0, "mulling opening variations\n");
889
890 memset(&b, 0, sizeof(b));
891
892 while (!state->quit && state->computer == 0) {
893 if (!state->first_book_move) {
894 t = state->first_book_move_index;
895 state->first_book_move = 1;
896 }
897
898 t = random() % brain_size;
899 if (brain[t].move_num > 10) continue;
900
901 r = (10 - brain[t].move_num)*(10 - brain[t].move_num);
902 if (random() % 100 >= r) continue;
903
904 if (brain[t].hash1 == 0) continue;
905
906 if (brain[t].flags2 & FLAG_NEVER_RESEARCH) continue;
907
908 if (imax(brain[t].depth_low, brain[t].depth_high) > MAX_DEPTH/2) continue;
909
910 /* don't mull on mate! */
911 if (brain[t].eval_low > (WIN-100) ||
912 brain[t].eval_high < -(WIN-100))
913 continue;
914
915 if ((brain[t].move_num & 1) != (brain[t].hash1 & 1)) {
916 brain[t].depth_low = -1;
917 continue;
918 }
919
920 /* now follow the variation */
921 while (!state->quit && state->computer == 0 && t != -1) {
922 if (!setup_brain_pos(&b, &brain[t])) {
923 lprintf(0,"removing brain entry\n");
924 brain[t].depth_low = -1;
925 break;
926 }
927
928 m.from = brain[t].from;
929 m.to = brain[t].to;
930
931 if (!legal_move(&b, &m)) {
932 lprintf(0,"illegal move %s", entry_str(&brain[t]));
933 brain[t].depth_low = -1;
934 break;
935 }
936
937 if (!do_move(&b, &b, &m)) {
938 lprintf(0,"removing brain entry\n");
939 brain[t].depth_low = -1;
940 break;
941 }
942
943 t = brain_find(&b);
944 }
945
946 if (t != -1) continue;
947
948 create_pboard(&b);
949
950 print_board(b.board);
951
952 /* yucky hack to get the entry in the brain without too much effort */
953
954 mulling = 0;
955 state->mulling = 0;
956 testing = 1;
957 timer_reset();
958 hash_reset();
959 order_reset();
960
961 state->move_time = 1;
962 zero_move(&m);
963
964 state->brain_inserting = 1;
965 make_move(&b, &m);
966 mulling = 1;
967 state->mulling = 1;
968 testing = 0;
969
970 brain_save();
971
972 state->brain_inserting = 0;
973
974 t = brain_find(&b);
975 if (t == -1) {
976 lprintf(0, "brain insert unsuccessful\n");
977 continue;
978 }
979
980 return t;
981 }
982 #endif
983 }
984
985 return -1;
986 }
987
988
brain_mull(void)989 void brain_mull(void)
990 {
991
992 Position b;
993 int t;
994 Move move;
995 float old_move_time=0;
996 static int first_mull = 1;
997
998 if (brain_size == 0) {
999 state->open = 1;
1000 return;
1001 }
1002
1003 if (state->auto_exit && state->moves_mulled >= MAX_MOVES_MULLED && state->open) return;
1004
1005 lprintf(0,"starting mulling on %d brain entries\n", brain_size);
1006
1007 mulled_one_opening = 0;
1008 mulling = 1;
1009 state->mulling = 1;
1010 state->brain_inserting = 0;
1011 brain_temp_size = 0;
1012 brain_clean();
1013 while (!state->quit && state->computer == 0 &&
1014 state->use_mulling &&
1015 (!state->auto_exit || (state->moves_mulled < MAX_MOVES_MULLED || !state->open))) {
1016 t = choose_mull();
1017 if (first_mull && state->ics_robot && state->open &&
1018 state->computer == 0 && state->autoplay) {
1019 prog_printf("seeks\n");
1020 first_mull = 0;
1021 }
1022
1023 if (t == -1) continue;
1024 if (!setup_brain_pos(&b, &brain[t]))
1025 continue;
1026
1027 old_move_time = state->move_time;
1028
1029 state->move_time = max_mull_time[mull_stage];
1030
1031 mull_entry = t;
1032
1033 timer_reset();
1034 hash_reset();
1035 order_reset();
1036
1037 move.from = brain[t].from;
1038 move.to = brain[t].to;
1039
1040 if (imax(brain[t].depth_low, brain[t].depth_high) > 40)
1041 brain[t].depth_low = brain[t].depth_high = 1;
1042
1043 lprintf(0,"mulling %d depth=%d/%d mtime=%2.1f ww=%d bw=%d move=%d v=%d/%d %s\n",
1044 t,
1045 brain[t].depth_low,
1046 brain[t].depth_high,
1047 state->move_time,
1048 brain[t].white_wins,
1049 brain[t].black_wins,
1050 brain[t].move_num,
1051 brain[t].eval_low,
1052 brain[t].eval_high,
1053 short_movestr(&b, &move));
1054
1055 if (state->display_position) {
1056 dump_ppn(&b);
1057 }
1058
1059 if (mull_stage == 0) {
1060 if ((brain[t].depth_low < MIN_DEPTH) || (brain[t].depth_high < MIN_DEPTH))
1061 state->current_depth = imax(7,imax(brain[t].depth_low, brain[t].depth_high));
1062 } else {
1063 state->current_depth = 7;
1064 }
1065 lprintf(0,"current depth: %d\n", state->current_depth);
1066
1067 state->brain_inserting = 1;
1068 make_move(&b, &move);
1069 state->brain_inserting = 0;
1070
1071 brain[t].flags2 &= ~FLAG_NEEDS_RESEARCH;
1072 brain[t].flags2 &= ~FLAG_BLUNDER;
1073
1074 brain_save();
1075
1076 ++state->moves_mulled;
1077 lprintf(0,"mulled ***%d\n",state->moves_mulled);
1078 state->move_time = old_move_time;
1079
1080 if (state->computer) continue;
1081
1082 /* This resumes any available match in the adjourned list
1083 (possibly ICS only) */
1084
1085 if (state->ics_robot && state->autoplay && state->open)
1086 prog_printf("resume\n");
1087
1088 }
1089
1090
1091 mulling = 0;
1092 state->mulling = 0;
1093 }
1094
1095 /* This is used when cleaning the brain */
consistency_check0(struct brain_entry * br)1096 static void consistency_check0(struct brain_entry *br)
1097 {
1098 int t1, num_moves, m;
1099 Position b, b1;
1100 static Move moves[MAX_MOVES];
1101 uint32 research_flags;
1102
1103 if (mulling && mull_stage == 0)
1104 research_flags = (FLAG_NEEDS_RESEARCH | FLAG_BLUNDER);
1105 else
1106 research_flags = FLAG_NEEDS_RESEARCH;
1107
1108 /* first some basic sanity checks */
1109 if (br->search_time < 0)
1110 br->search_time = 0;
1111
1112 if (!setup_brain_pos(&b, br)) {
1113 lprintf(0,"removing brain entry\n");
1114 br->depth_low = -1;
1115 return;
1116 }
1117
1118 if ((br->move_num & 1) != (br->hash1 & 1)) {
1119 lprintf(0,"wrong player in consistency_check0 %s",
1120 entry_str(br));
1121 br->depth_low = -1;
1122 return;
1123 }
1124
1125
1126 num_moves = generate_moves(&b, moves);
1127
1128 for (m=0;m<num_moves;m++) {
1129 if (!do_move(&b1, &b, &moves[m])) continue;
1130
1131 t1 = brain_find(&b1);
1132 if (t1 == -1) continue;
1133
1134 if (!(brain[t1].flags2 & FLAG_NEEDS_RESEARCH) &&
1135 br->eval_high < -brain[t1].eval_high) {
1136 br->flags2 |= research_flags;
1137 brain[t1].flags2 |= research_flags;
1138 lprintf(0, "refined entry0: %s", entry_str(br));
1139 lprintf(0, "by: %s\n", entry_str(&brain[t1]));
1140 }
1141 }
1142 }
1143
1144
1145
1146 /* this is used when inserting a move into the brain. The insert may
1147 obsolete later brain entries */
consistency_check1(struct brain_entry * br)1148 static void consistency_check1(struct brain_entry *br)
1149 {
1150 int t2, num_moves, m;
1151 Move m1;
1152 Position b, b1, b2;
1153 static Move moves[MAX_MOVES];
1154 struct hash_entry *h;
1155 uint32 research_flags;
1156
1157 if (mulling && mull_stage == 0)
1158 research_flags = (FLAG_NEEDS_RESEARCH | FLAG_BLUNDER);
1159 else
1160 research_flags = FLAG_NEEDS_RESEARCH;
1161
1162
1163 /* first some basic sanity checks */
1164 if (br->search_time < 0)
1165 br->search_time = 0;
1166
1167 if (!setup_brain_pos(&b, br)) {
1168 lprintf(0,"removing brain entry\n");
1169 br->depth_low = -1;
1170 return;
1171 }
1172
1173 if ((br->move_num & 1) != (br->hash1 & 1)) {
1174 lprintf(0,"wrong player in consistency_check1 %s",
1175 entry_str(br));
1176 br->depth_low = -1;
1177 return;
1178 }
1179
1180 /* Now see if this brain entry leads to another brain entry.
1181 If it does then the value of that brain entry is bounded by
1182 the value of the position in the hash table. This relies on
1183 the fact that the brain entry would have been overwritten
1184 by the hash table entry, and hence the hash table entry
1185 must be "better".
1186
1187 However, this may not be the best thing to do. For example,
1188 if the hash table entry has the same move as the brain
1189 entry, but a significantly wider gap between eval_high and
1190 eval_low, and in addition has only been searched 1-ply
1191 deeper, then it is not really a better entry. A hack at
1192 improving this is given below */
1193
1194 m1.from = br->from;
1195 m1.to = br->to;
1196
1197 if (!do_move(&b1, &b, &m1)) {
1198 lprintf(0,"removing brain entry\n");
1199 br->depth_low = -1;
1200 return;
1201 }
1202
1203 t2 = brain_find(&b1);
1204
1205 if (t2 != -1 && (h = fetch_hash(&b1)) && brain[t2].move_num > br->move_num) {
1206 /* only replace the brain entry if the move has
1207 changed or if the new eval is inconsistent with the
1208 old eval */
1209 if (brain[t2].from != h->from ||
1210 brain[t2].to != h->to ||
1211 h->high.v < brain[t2].eval_low ||
1212 h->low.v > brain[t2].eval_high) {
1213 brain[t2].eval_high = h->high.v;
1214 brain[t2].eval_low = h->low.v;
1215 brain[t2].depth_low = h->depth_low;
1216 brain[t2].depth_high = h->depth_high;
1217 brain[t2].from = h->from;
1218 brain[t2].to = h->to;
1219 if (!converged(h)) {
1220 brain[t2].flags2 |= research_flags;
1221 }
1222 lprintf(0,"refined entry1 %s", entry_str(&brain[t2]));
1223 } else {
1224 if (h->depth_low > brain[t2].depth_low &&
1225 h->low.v > -INFINITY) {
1226 brain[t2].eval_low = h->low.v;
1227 brain[t2].depth_low = h->depth_low;
1228 brain[t2].flags2 |= research_flags;
1229 lprintf(0,"refined entry1 %s", entry_str(&brain[t2]));
1230 }
1231 if (h->depth_high > brain[t2].depth_high &&
1232 h->high.v < INFINITY) {
1233 brain[t2].eval_high = h->high.v;
1234 brain[t2].depth_high = h->depth_high;
1235 brain[t2].flags2 |= research_flags;
1236 lprintf(0,"refined entry1 %s", entry_str(&brain[t2]));
1237 }
1238 }
1239 }
1240
1241 /* now generate and try all moves from this position. If they
1242 lead to positions in the brain then the hash entries for these
1243 positions also bound the brain entry evals */
1244
1245 num_moves = generate_moves(&b1, moves);
1246
1247 for (m=0;m<num_moves;m++) {
1248 if (!do_move(&b2, &b1, &moves[m])) continue;
1249
1250 t2 = brain_find(&b2);
1251 if (t2 == -1) continue;
1252
1253 if (t2 != -1 && (h = fetch_hash(&b2)) && brain[t2].move_num > br->move_num) {
1254 /* only replace the brain entry if the move has
1255 changed or if the new eval is inconsistent with the
1256 old eval */
1257 if (brain[t2].from != h->from ||
1258 brain[t2].to != h->to ||
1259 h->high.v < brain[t2].eval_low ||
1260 h->low.v > brain[t2].eval_high) {
1261 brain[t2].eval_high = h->high.v;
1262 brain[t2].eval_low = h->low.v;
1263 brain[t2].depth_low = h->depth_low;;
1264 brain[t2].depth_high = h->depth_high;
1265 brain[t2].from = h->from;
1266 brain[t2].to = h->to;
1267 if (!converged(h))
1268 brain[t2].flags2 |= research_flags;
1269 lprintf(0,"refined entry2 %s", entry_str(&brain[t2]));
1270 } else {
1271 if (h->depth_low > brain[t2].depth_low &&
1272 h->low.v > -INFINITY) {
1273 brain[t2].eval_low = h->low.v;
1274 brain[t2].depth_low = h->depth_low;
1275 brain[t2].flags2 |= research_flags;
1276 lprintf(0,"refined entry2 %s", entry_str(&brain[t2]));
1277 }
1278 if (h->depth_high > brain[t2].depth_high &&
1279 h->high.v < INFINITY) {
1280 brain[t2].eval_high = h->high.v;
1281 brain[t2].depth_high = h->depth_high;
1282 brain[t2].flags2 |= research_flags;
1283 lprintf(0,"refined entry2 %s", entry_str(&brain[t2]));
1284 }
1285 }
1286 }
1287 }
1288
1289 /* we don't go any deeper because it is very unlikely that any
1290 brain entries this deep would have been overwritten in the hash table (?) */
1291
1292 }
1293
1294
1295
1296 /* this is used when thinking about using an entry in the brain, or
1297 when mulling entries. It may invalidate the current entry based on
1298 later entries */
consistency_check2(struct brain_entry * br)1299 static void consistency_check2(struct brain_entry *br)
1300 {
1301 int t1, t2, num_moves, m;
1302 Move m1;
1303 Position b, b1, b2;
1304 static Move moves[MAX_MOVES];
1305 struct hash_entry *h;
1306 uint32 research_flags;
1307
1308 if (mulling && mull_stage == 0)
1309 research_flags = (FLAG_NEEDS_RESEARCH | FLAG_BLUNDER);
1310 else
1311 research_flags = FLAG_NEEDS_RESEARCH;
1312
1313
1314 /* first some basic sanity checks */
1315 if (br->search_time < 0)
1316 br->search_time = 0;
1317
1318 /* now see if this brain entry leads to another brain entry.
1319 If it does then the value of this position is bounded by
1320 the value of the other position */
1321 if (!setup_brain_pos(&b, br)) {
1322 lprintf(0,"removing brain entry\n");
1323 br->depth_low = -1;
1324 return;
1325 }
1326
1327 if ((br->move_num & 1) != (br->hash1 & 1)) {
1328 lprintf(0,"wrong player in consistency_check2 %s",
1329 entry_str(br));
1330 br->depth_low = -1;
1331 return;
1332 }
1333
1334
1335 m1.from = br->from;
1336 m1.to = br->to;
1337
1338 if (!legal_move(&b, &m1)) {
1339 lprintf(0,"illegal move %s", entry_str(br));
1340 br->depth_low = -1;
1341 return;
1342 }
1343
1344 if (!do_move(&b1, &b, &m1)) {
1345 lprintf(0,"removing brain entry\n");
1346 br->depth_low = -1;
1347 return;
1348 }
1349
1350 t1 = brain_find(&b1);
1351 h = fetch_hash(&b1);
1352
1353 if (t1 != -1 && !(brain[t1].flags2 & FLAG_NEEDS_RESEARCH) && brain[t1].move_num > br->move_num) {
1354 if (br->eval_low > -brain[t1].eval_high) {
1355 br->eval_low = -brain[t1].eval_high;
1356 if (br->eval_high + brain[t1].eval_high > 0.01*PAWN_VALUE) {
1357 br->flags2 |= research_flags;
1358 brain[t1].flags2 |= research_flags;
1359 lprintf(0,"refined entry3: %s", entry_str(br));
1360 lprintf(0, "by %s", entry_str(&brain[t1]));
1361 if (h)
1362 lprintf(0, "hash entry: %d/%d %d/%d\n", h->low.v, h->high.v,
1363 h->depth_low, h->depth_high);
1364 else
1365 lprintf(0,"brain entry not in hash table!\n");
1366 }
1367 }
1368 }
1369
1370 /* now generate and try all moves from this position. If they
1371 lead to positions in the brain then those positions also
1372 bound the eval at the current position */
1373 num_moves = generate_moves(&b1, moves);
1374
1375 for (m=0;m<num_moves;m++) {
1376 if (!do_move(&b2, &b1, &moves[m])) continue;
1377
1378 if (b2.hash1 == br->hash1 &&
1379 b2.hash2 == br->hash2)
1380 continue;
1381 t2 = brain_find(&b2);
1382 if (t2 == -1) continue;
1383
1384 h = fetch_hash(&b2);
1385 if (!((brain[t2].flags2 & FLAG_NEEDS_RESEARCH) ||
1386 (brain[t2].flags2 & FLAG_BLUNDER)) && brain[t2].move_num > br->move_num) {
1387 if (brain[t2].eval_low + 0.01*PAWN_VALUE < brain[t2].eval_high) {
1388 brain[t2].flags2 |= research_flags;
1389 lprintf(0, "unconverged entry: %s", entry_str(&brain[t2]));
1390 } else {
1391 if (br->eval_low > brain[t2].eval_low) {
1392 if (br->eval_low - brain[t2].eval_low >
1393 0.01*PAWN_VALUE) {
1394 br->flags2 |= research_flags;
1395 lprintf(0,"refined entry4: %s", entry_str(br));
1396 lprintf(0,"by: %s", entry_str(&brain[t2]));
1397 if (t1 != -1) {
1398 lprintf(0, "after: %s", entry_str(&brain[t1]));
1399 brain[t1].flags2 |= research_flags;
1400 }
1401 br->eval_low = brain[t2].eval_low;
1402 if (h)
1403 lprintf(0, "hash entry: %d/%d %d/%d\n",
1404 h->low.v, h->high.v,
1405 h->depth_low, h->depth_high);
1406 else {
1407 lprintf(0,"brain entry not in hash table!\n");
1408 }
1409 brain[t2].flags2 |= research_flags;
1410 ++refined_count;
1411 if (mulling)
1412 state->stop_search = 1;
1413 }
1414 }
1415 }
1416 }
1417 }
1418 }
1419
1420
analyse_game(void)1421 void analyse_game(void)
1422 {
1423 int i, j, t;
1424 int winner=0;
1425 int num_moves = state->position.move_num;
1426 int losing_move=0;
1427 int insert=0;
1428 int last_move=0;
1429 int first_move = -1;
1430 double threshold;
1431 FILE *result;
1432
1433
1434 done_lookup = 0;
1435 if (state->analysed) {
1436 if (!state->use_mulling)
1437 state->open = 1;
1438 return;
1439 }
1440
1441 state->open = 0;
1442
1443 #if LEARN_EVAL
1444 if (learning) {
1445 td_update();
1446 td_dump("coeffs.dat");
1447 }
1448 #endif
1449
1450 /* couldn't think of a more reliable place to reset this */
1451 state->rating_change = -2;
1452
1453 lprintf(0,"analysis: %d moves\n", num_moves);
1454
1455 /* work out who won (or was winning when it ended) */
1456 for (i=num_moves-1;i>=0;i--) {
1457 lprintf(0,"move %d eval=%d\n", i, state->game_record[i].v);
1458 if (state->game_record[i].v != INFINITY) {
1459 if (state->game_record[i].v > 0.4*PAWN_VALUE) {
1460 winner = 1;
1461 } else if (state->game_record[i].v < -0.4*PAWN_VALUE) {
1462 winner = -1;
1463 }
1464 break;
1465 }
1466 }
1467
1468 for (i=0; i<num_moves; i++) {
1469 if (first_move == -1 && state->game_record[i].v != 0)
1470 first_move = i;
1471 if (state->game_record[i].v != INFINITY && first_move != -1)
1472 lprintf(0,"%d %d\n", i - first_move, state->converged_record[i].v);
1473 }
1474
1475 if (num_moves - first_move < 6) {
1476 if (!state->brain_inserting)
1477 brain_temp_size = 0;
1478 state->analysed = 1;
1479 if (!state->use_mulling) {
1480 state->open = 1;
1481 if (state->ics_robot && state->computer == 0 && state->autoplay) {
1482 prog_printf("seeks\n");
1483 }
1484 }
1485 return;
1486 }
1487
1488 lprintf(0,"game analysis winner=%d moves=%d colour=%d\n",
1489 winner, num_moves, state->colour);
1490
1491 result = fopen("result.txt", "a");
1492 if (winner == state->colour)
1493 fprintf(result, "1\n");
1494 else if (winner == 0)
1495 fprintf(result, "0\n");
1496 else
1497 fprintf(result, "-1\n");
1498 fclose(result);
1499 dump_history();
1500
1501 if (!state->use_mulling) {
1502 state->open = 1;
1503 state->analysed = 1;
1504 if (state->ics_robot && state->computer == 0 && state->notified) {
1505 prog_printf("tell %s My brain is now clean and I am accepting challenges\n",
1506 state->notifyee);
1507 prog_printf("accept\n");
1508 state->notified = 0;
1509 }
1510 if (state->ics_robot && state->computer == 0 && state->autoplay) {
1511 prog_printf("seeks\n");
1512 }
1513 return;
1514 }
1515
1516 if (!state->brain_inserting) {
1517 if (winner == -state->colour || winner == 0) {
1518 int forced_win=0;
1519 etype last_eval;
1520 double tanhv[MAX_GAME_MOVES];
1521
1522 /* find the "losing move". we look for the
1523 largest transition from above -half a pawn
1524 to below 0 pawns. Do this for losses but
1525 not the inverse for wins because often a
1526 win comes through a mistake of the
1527 opponent, a mistake the opponent could well
1528 repeat. draws are tough because they often
1529 only show up when the 50 move rule is
1530 reached, so we handle them separately */
1531 for (i=first_move, j=0; i<num_moves; i++) {
1532 if (state->game_record[i].v != INFINITY) {
1533 /* kludge to fix up problem with wrong values after mate */
1534 if (!forced_win && ABS(state->converged_record[i].v) >
1535 FORCED_WIN && ABS(state->converged_record[i].v) <
1536 INFINITY) {
1537 forced_win = 1;
1538 last_eval = state->converged_record[i].v;
1539 }
1540 if (forced_win)
1541 state->converged_record[i].v = last_eval;
1542 tanhv[j] = tanh(EVAL_SCALE*state->converged_record[i].v);
1543 lprintf(0,"%d %lf\n", j, tanhv[j]);
1544 if (i==state->last_book_move)
1545 state->last_book_move = j;
1546 ++j;
1547 }
1548 }
1549 tanhv[j] = -1;
1550 last_move = j;
1551
1552 memset(state->converged_record, 0,
1553 MAX_GAME_MOVES*sizeof(state->converged_record[0]));
1554 memset(state->game_record, 0,
1555 MAX_GAME_MOVES*sizeof(state->game_record[0]));
1556
1557 /* now look for the last time the evaluation
1558 was above 0.0 pawns for more than three
1559 consecutive moves (-0.2 pawns for black) */
1560 losing_move = 0;
1561 if (state->colour == 1) {
1562 threshold = WHITE_THRESHOLD;
1563 } else {
1564 threshold = BLACK_THRESHOLD;
1565 }
1566 for (i=last_move; i>=2; i--) {
1567 if (tanhv[i] > threshold &&
1568 tanhv[i-1] > threshold &&
1569 tanhv[i-2] > threshold) {
1570 losing_move = i;
1571 break;
1572 }
1573 }
1574
1575 lprintf(0,"losing move: %d \n", losing_move);
1576 result = fopen("losing_move.txt", "a");
1577 fprintf(result, "%d\n", losing_move);
1578 fclose(result);
1579 insert = 1;
1580 } else if (!state->auto_exit && state->won == STALEMATE) {
1581 /* just record the last position, we can't reliably
1582 conclude anything else
1583 losing_move = brain_temp_size-1;
1584 lprintf(0,"losing move (draw): %d \n", losing_move);
1585 */
1586 }
1587
1588 if ((losing_move > 0 && losing_move < 120) || insert) {
1589 int new_entries = 0;
1590 state->brain_inserting = 0;
1591 if (losing_move < state->last_book_move)
1592 last_move = imin(state->last_book_move+6, brain_temp_size);
1593 else
1594 last_move = imin(losing_move+MAX_MOVES_MULLED, brain_temp_size);
1595 for (i=losing_move; i<last_move; i++) {
1596 t = brain_find_hash1(brain_temp[i].hash1);
1597 if (t != -1) {
1598 brain[t].flags2 |= FLAG_NEEDS_RESEARCH;
1599 brain[t].flags2 |= FLAG_BLUNDER;
1600 } else {
1601 brain_temp[new_entries] = brain_temp[i];
1602 brain_temp[new_entries].flags2 |=
1603 FLAG_NEEDS_RESEARCH;
1604 brain_temp[new_entries].flags2 |=
1605 FLAG_BLUNDER;
1606 ++new_entries;
1607 }
1608 }
1609 brain_temp_size = new_entries;
1610 state->brain_inserting = 1;
1611 brain_save();
1612 state->brain_inserting = 0;
1613 }
1614 brain_temp_size = 0;
1615 }
1616
1617 for (i=num_moves-3;i>=0;i--) {
1618 t = brain_find_hash1(state->hash_list[i]);
1619
1620 if (t == -1) continue;
1621
1622 if (winner == 1)
1623 brain[t].white_wins++;
1624 else if (winner == -1)
1625 brain[t].black_wins++;
1626 }
1627
1628
1629
1630 lprintf(0,"game analysis did %d moves\n",
1631 num_moves);
1632
1633 brain_save();
1634 if (losing_move == 0 && state->auto_exit)
1635 state->moves_mulled = MAX_MOVES_MULLED;
1636
1637 state->analysed = 1;
1638 }
1639
1640
clean_comp(const void * ii1,const void * ii2)1641 static int clean_comp(const void *ii1, const void *ii2)
1642 {
1643 int *i1;
1644 int *i2;
1645
1646 i1 = (int *)ii1;
1647 i2 = (int *)ii2;
1648
1649 if (brain[*i1].move_num != brain[*i2].move_num)
1650 return brain[*i1].move_num - brain[*i2].move_num;
1651 return memcmp(brain[*i1].board, brain[*i2].board,
1652 sizeof(brain[0].board));
1653 }
1654
1655
1656 /* clean the brain. This means finding inconsisant brain entries
1657 and fixing them */
brain_clean(void)1658 int brain_clean(void)
1659 {
1660 int i, t;
1661 int clean=1;
1662 int brindex[MAX_BRAIN_SIZE];
1663 int duplicates=0;
1664 uint32 research_flags;
1665
1666 brain_save();
1667
1668 if (!brain_size) return clean;
1669
1670 lprintf(0,"cleaning brain\n");
1671
1672 if (mulling && mull_stage == 0)
1673 research_flags = (FLAG_NEEDS_RESEARCH | FLAG_BLUNDER);
1674 else
1675 research_flags = FLAG_NEEDS_RESEARCH;
1676
1677 for (i=0;i<brain_size-1;i++) {
1678 brain[i].flags2 &= ~FLAG_NEVER_RESEARCH;
1679 /* first sanity */
1680 if (ABS(brain[i].eval_low) > INFINITY || ABS(brain[i].eval_high) > INFINITY) {
1681 brain[i].flags2 &= ~FLAG_NEVER_RESEARCH;
1682 brain[i].flags2 |= research_flags;
1683 lprintf(0, "out of bounds: %s", entry_str(&brain[i]));
1684 clean = 0;
1685 } else if ((brain[i].depth_low == MAX_DEPTH || brain[i].depth_high == MAX_DEPTH) &&
1686 !((ABS(brain[i].eval_low) >= FORCED_WIN && ABS(brain[i].eval_low) <= WIN) ||
1687 (ABS(brain[i].eval_high) >= FORCED_WIN && ABS(brain[i].eval_high) <= WIN))) {
1688 brain[i].flags2 &= ~FLAG_NEVER_RESEARCH;
1689 brain[i].flags2 |= research_flags;
1690 clean = 0;
1691 } else {
1692 /* don't research mates */
1693 if ((ABS(brain[i].eval_low) >= FORCED_WIN && ABS(brain[i].eval_low) <= WIN) ||
1694 (ABS(brain[i].eval_high) >= FORCED_WIN && ABS(brain[i].eval_high) <= WIN)) {
1695 brain[i].flags2 &= ~research_flags;
1696 brain[i].flags2 |= FLAG_NEVER_RESEARCH;
1697 brain[i].depth_low = brain[i].depth_high = MAX_DEPTH;
1698 } else if (brain[i].flags2 & FLAG_NEVER_RESEARCH) {
1699 brain[i].depth_low = brain[i].depth_high = -1;
1700 } else if (brain[i].eval_low + 0.01*PAWN_VALUE < brain[i].eval_high &&
1701 ABS(brain[i].eval_low) < FORCED_WIN) {
1702 lprintf(0,"unconverged brain entry: %d %s", i,
1703 entry_str(&brain[i]));
1704 brain[i].flags2 |= research_flags;
1705 clean = 0;
1706 } else if (((brain[i].depth_low <= 5 && brain[i].depth_low > 0) ||
1707 (brain[i].depth_high <= 5 && brain[i].depth_high > 0)) &&
1708 ABS(brain[i].eval_low) < FORCED_WIN) {
1709 lprintf(0,"shallow brain entry: %s",
1710 entry_str(&brain[i]));
1711 brain[i].flags2 |= research_flags;
1712 clean = 0;
1713 }
1714 }
1715
1716 if (brain[i].move_num > 200) {
1717 printf("removing late entry %s", entry_str(&brain[i]));
1718 brain[i].depth_low = -1;
1719 brain[i].depth_high = -1;
1720 }
1721
1722 #if STORE_ONLY_NEGATIVE
1723 if (!(brain[i].flags2 & FLAG_NEEDS_RESEARCH) &&
1724 (((brain[i].eval_high > -0.25*PAWN_VALUE) && (brain[i].move_num & 1)) ||
1725 ((brain[i].eval_high > 0) && !(brain[i].move_num & 1)))) {
1726 printf("removing positive entry %s", entry_str(&brain[i]));
1727 brain[i].depth_low = -1;
1728 brain[i].depth_high = -1;
1729 }
1730 #endif
1731 if (brain[i].hash1 == brain[i+1].hash1) {
1732 if (brain[i].hash2 == brain[i+1].hash2) {
1733 lprintf(0,"duplicate entry %s",
1734 entry_str(&brain[i]));
1735 lprintf(0,"duplicate entry %s",
1736 entry_str(&brain[i+1]));
1737 brain[i+1].depth_low = -1;
1738 brain[i+1].depth_high = -1;
1739 duplicates++;
1740 } else {
1741 lprintf(0,"duplicate hash1 values\n");
1742 }
1743 }
1744 }
1745
1746 brain_resort();
1747
1748 /* build a list of indexes sorted by move number */
1749 for (i=0;i<brain_size;i++) brindex[i] = i;
1750 qsort(brindex, brain_size, sizeof(brindex[0]), clean_comp);
1751
1752
1753 /* now run through the moves in move order */
1754 for (i=0;i<brain_size;i++) {
1755 t = brindex[i];
1756
1757 /* first some basic sanity checks */
1758 if (brain[t].search_time < 0)
1759 brain[t].search_time = 0;
1760 /* check consistency of this entry with later ones */
1761 if (!(brain[t].flags2 & FLAG_NEEDS_RESEARCH)) {
1762 consistency_check0(&brain[t]);
1763 consistency_check2(&brain[t]);
1764 }
1765
1766 if (!(brain[t].flags2 & FLAG_NEEDS_RESEARCH)) {
1767 brain[t].depth_low = MIN_DEPTH;
1768 brain[t].depth_high = MIN_DEPTH;
1769 } else {
1770 clean = 0;
1771 }
1772 if (state->computer != 0)
1773 return clean;
1774 }
1775
1776 brain_save();
1777
1778 lprintf(0,"finished cleaning brain\n");
1779
1780 return clean;
1781 }
1782
1783
brain_update()1784 void brain_update()
1785 {
1786 int i;
1787
1788 for (i=0; i<brain_size; i++)
1789 if (brain[i].move_num > 15)
1790 brain[i].flags2 &= ~FLAG_NEEDS_RESEARCH;
1791
1792 brain_save();
1793 }
1794