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