10 Opening Book Data Structure: Index BookData
12 Index: IndexEntry.. (NUM_SECTION times)
14 IndexEntry: SectionPointer SectionSize
16 BookData: Section.. (NUM_SECTION times)
18 Section: [DataEntry]..
20 DataEntry: Header Move...
24 4 byte: position of the section in character
27 2 byte: size of the section in character
30 1 byte: number of bytes for the DataEntry
38 #define BK_SIZE_INDEX 6
39 #define BK_SIZE_HEADER 9
40 #define BK_SIZE_MOVE 4
41 #define BK_MAX_MOVE 32
43 #if ( BK_SIZE_HEADER + BK_SIZE_MOVE * BK_MAX_MOVE > UCHAR_MAX )
44 # error "Maximum size of DataEntry is larger than UCHAR_MAX"
47 typedef struct { unsigned short smove, freq; } book_move_t;
49 typedef struct { int from, to; } ft_t;
51 static int CONV book_read( uint64_t key, book_move_t *pbook_move,
52 unsigned int *pposition );
53 static uint64_t CONV book_hash_func( const tree_t * restrict ptree,
55 static unsigned int CONV bm2move( const tree_t * restrict ptree,
56 unsigned int bmove, int is_flip );
57 static ft_t CONV flip_ft( ft_t ft, int turn, int is_flip );
58 static int CONV normalize_book_move( book_move_t * restrict pbook_move,
65 int iret = file_close( pf_book );
66 if ( iret < 0 ) { return iret; }
68 pf_book = file_open( str_book, "rb+" );
69 if ( pf_book == NULL ) { return -2; }
78 int iret = file_close( pf_book );
79 if ( iret < 0 ) { return iret; }
88 book_probe( tree_t * restrict ptree )
90 book_move_t abook_move[ BK_MAX_MOVE+1 ];
93 unsigned int move, position, freq_lower_limit;
94 int is_flip, i, j, moves, ply;
96 key = book_hash_func( ptree, &is_flip );
98 moves = book_read( key, abook_move, &position );
99 if ( moves <= 0 ) { return moves; }
101 #if ! defined(MINIMUM) || ! defined(NDEBUG)
102 for ( j = i = 0; i < moves; i++ ) { j += abook_move[i].freq; }
103 if ( j != USHRT_MAX )
105 str_error = "normalization error (book.bin)";
110 /* decision of book move based on pseudo-random number */
111 if ( game_status & flag_puzzling ) { j = 0; }
113 drand = (double)rand64() / (double)UINT64_MAX;
115 if ( game_status & flag_narrow_book )
117 #if defined(BK_ULTRA_NARROW)
118 freq_lower_limit = abook_move[0].freq;
120 freq_lower_limit = abook_move[0].freq / 2U;
123 for ( i = 1; i < moves; i++ )
125 if ( abook_move[i].freq < freq_lower_limit ) { break; }
128 normalize_book_move( abook_move, moves );
131 for ( j = moves-1; j > 0; j-- )
133 dscore = (double)( abook_move[j].freq ) / (double)USHRT_MAX;
134 if ( drand <= dscore ) { break; }
137 if ( ! abook_move[j].freq ) { j = 0; }
141 if ( ! ( game_status & ( flag_pondering | flag_puzzling ) ) )
143 Out( " move freq\n" );
144 OutCsaShogi( "info" );
145 for ( i = 0; i < moves; i++ )
149 dscore = (double)abook_move[i].freq / (double)USHRT_MAX;
150 move = bm2move( ptree, (unsigned int)abook_move[i].smove, is_flip );
151 str = str_CSA_move( move );
153 Out( " %c %s %5.1f\n", i == j ? '*' : ' ', str, dscore * 100.0 );
154 OutCsaShogi( " %s(%.0f%%)", str, dscore * 100.0 );
159 move = bm2move( ptree, (unsigned int)abook_move[j].smove, is_flip );
160 if ( ! is_move_valid( ptree, move, root_turn ) )
162 out_warning( "BAD BOOK MOVE!! " );
166 ply = record_game.moves;
167 if ( game_status & flag_pondering ) { ply++; }
169 ptree->current_move[1] = move;
176 book_read( uint64_t key, book_move_t *pbook_move, unsigned int *pposition )
179 const unsigned char *p;
180 unsigned int position, size_section, size, u;
181 int ibook_section, moves;
184 ibook_section = (int)( (unsigned int)key & (unsigned int)( NUM_SECTION-1 ) );
186 if ( fseek( pf_book, BK_SIZE_INDEX*ibook_section, SEEK_SET ) == EOF )
188 str_error = str_io_error;
192 if ( fread( &position, sizeof(int), 1, pf_book ) != 1 )
194 str_error = str_io_error;
198 if ( fread( &s, sizeof(unsigned short), 1, pf_book ) != 1 )
200 str_error = str_io_error;
203 size_section = (unsigned int)s;
204 if ( size_section > MAX_SIZE_SECTION )
206 str_error = str_book_error;
210 if ( fseek( pf_book, (long)position, SEEK_SET ) == EOF )
212 str_error = str_io_error;
215 if ( fread( book_section, sizeof(unsigned char), (size_t)size_section,
216 pf_book ) != (size_t)size_section )
218 str_error = str_io_error;
224 *pposition = position;
225 while ( book_section + size_section > p )
227 size = (unsigned int)p[0];
228 book_key = *(uint64_t *)( p + 1 );
229 if ( book_key == key ) { break; }
233 if ( book_section + size_section <= p ) { return 0; }
235 for ( moves = 0, u = BK_SIZE_HEADER; u < size; moves++, u += BK_SIZE_MOVE )
237 pbook_move[moves].smove = *(unsigned short *)(p+u+0);
238 pbook_move[moves].freq = *(unsigned short *)(p+u+2);
246 flip_ft( ft_t ft, int turn, int is_flip )
248 int ito_rank, ito_file, ifrom_rank, ifrom_file;
250 ito_rank = airank[ft.to];
251 ito_file = aifile[ft.to];
252 if ( ft.from < nsquare )
254 ifrom_rank = airank[ft.from];
255 ifrom_file = aifile[ft.from];
257 else { ifrom_rank = ifrom_file = 0; }
261 ito_rank = rank9 - ito_rank;
262 ito_file = file9 - ito_file;
263 if ( ft.from < nsquare )
265 ifrom_rank = rank9 - ifrom_rank;
266 ifrom_file = file9 - ifrom_file;
272 ito_file = file9 - ito_file;
273 if ( ft.from < nsquare ) { ifrom_file = file9 - ifrom_file; }
276 ft.to = ito_rank * nfile + ito_file;
277 if ( ft.from < nsquare ) { ft.from = ifrom_rank * nfile + ifrom_file; }
283 static unsigned int CONV
284 bm2move( const tree_t * restrict ptree, unsigned int bmove, int is_flip )
291 ft.from = I2From(bmove);
292 ft = flip_ft( ft, root_turn, is_flip );
293 is_promote = I2IsPromote(bmove);
295 move = (unsigned int)( is_promote | From2Move(ft.from) | ft.to );
296 if ( ft.from >= nsquare ) { return move; }
300 move |= Cap2Move(BOARD[ft.to]);
301 move |= Piece2Move(-BOARD[ft.from]);
304 move |= Cap2Move(-BOARD[ft.to]);
305 move |= Piece2Move(BOARD[ft.from]);
313 book_hash_func( const tree_t * restrict ptree, int *pis_flip )
315 uint64_t key, key_flip;
317 int i, iflip, irank, ifile, piece;
320 hand = root_turn ? HAND_W : HAND_B;
321 i = I2HandPawn(hand); if ( i ) { key ^= b_hand_pawn_rand[i-1]; }
322 i = I2HandLance(hand); if ( i ) { key ^= b_hand_lance_rand[i-1]; }
323 i = I2HandKnight(hand); if ( i ) { key ^= b_hand_knight_rand[i-1]; }
324 i = I2HandSilver(hand); if ( i ) { key ^= b_hand_silver_rand[i-1]; }
325 i = I2HandGold(hand); if ( i ) { key ^= b_hand_gold_rand[i-1]; }
326 i = I2HandBishop(hand); if ( i ) { key ^= b_hand_bishop_rand[i-1]; }
327 i = I2HandRook(hand); if ( i ) { key ^= b_hand_rook_rand[i-1]; }
329 hand = root_turn ? HAND_B : HAND_W;
330 i = I2HandPawn(hand); if ( i ) { key ^= w_hand_pawn_rand[i-1]; }
331 i = I2HandLance(hand); if ( i ) { key ^= w_hand_lance_rand[i-1]; }
332 i = I2HandKnight(hand); if ( i ) { key ^= w_hand_knight_rand[i-1]; }
333 i = I2HandSilver(hand); if ( i ) { key ^= w_hand_silver_rand[i-1]; }
334 i = I2HandGold(hand); if ( i ) { key ^= w_hand_gold_rand[i-1]; }
335 i = I2HandBishop(hand); if ( i ) { key ^= w_hand_bishop_rand[i-1]; }
336 i = I2HandRook(hand); if ( i ) { key ^= w_hand_rook_rand[i-1]; }
340 for ( irank = rank1; irank <= rank9; irank++ )
341 for ( ifile = file1; ifile <= file9; ifile++ )
345 i = ( rank9 - irank ) * nfile + file9 - ifile;
346 iflip = ( rank9 - irank ) * nfile + ifile;
347 piece = -(int)BOARD[nsquare-i-1];
350 i = irank * nfile + ifile;
351 iflip = irank * nfile + file9 - ifile;
352 piece = (int)BOARD[i];
355 #define Foo(t_pc) key ^= (t_pc ## _rand)[i]; \
356 key_flip ^= (t_pc ## _rand)[iflip];
359 case pawn: Foo( b_pawn ); break;
360 case lance: Foo( b_lance ); break;
361 case knight: Foo( b_knight ); break;
362 case silver: Foo( b_silver ); break;
363 case gold: Foo( b_gold ); break;
364 case bishop: Foo( b_bishop ); break;
365 case rook: Foo( b_rook ); break;
366 case king: Foo( b_king ); break;
367 case pro_pawn: Foo( b_pro_pawn ); break;
368 case pro_lance: Foo( b_pro_lance ); break;
369 case pro_knight: Foo( b_pro_knight ); break;
370 case pro_silver: Foo( b_pro_silver ); break;
371 case horse: Foo( b_horse ); break;
372 case dragon: Foo( b_dragon ); break;
373 case -pawn: Foo( w_pawn ); break;
374 case -lance: Foo( w_lance ); break;
375 case -knight: Foo( w_knight ); break;
376 case -silver: Foo( w_silver ); break;
377 case -gold: Foo( w_gold ); break;
378 case -bishop: Foo( w_bishop ); break;
379 case -rook: Foo( w_rook ); break;
380 case -king: Foo( w_king ); break;
381 case -pro_pawn: Foo( w_pro_pawn ); break;
382 case -pro_lance: Foo( w_pro_lance ); break;
383 case -pro_knight: Foo( w_pro_knight ); break;
384 case -pro_silver: Foo( w_pro_silver ); break;
385 case -horse: Foo( w_horse ); break;
386 case -dragon: Foo( w_dragon ); break;
391 if ( key > key_flip )
396 else { *pis_flip = 0; }
403 normalize_book_move( book_move_t * restrict pbook_move, int moves )
407 unsigned int u, norm;
410 /* insertion sort by nwin */
411 pbook_move[moves].freq = 0;
412 for ( i = moves-2; i >= 0; i-- )
414 u = pbook_move[i].freq;
415 swap = pbook_move[i];
416 for ( j = i+1; pbook_move[j].freq > u; j++ )
418 pbook_move[j-1] = pbook_move[j];
420 pbook_move[j-1] = swap;
424 for ( norm = 0, i = 0; i < moves; i++ ) { norm += pbook_move[i].freq; }
425 dscale = (double)USHRT_MAX / (double)norm;
426 for ( norm = 0, i = 0; i < moves; i++ )
428 u = (unsigned int)( (double)pbook_move[i].freq * dscale );
429 if ( ! u ) { u = 1U; }
430 if ( u > USHRT_MAX ) { u = USHRT_MAX; }
432 pbook_move[i].freq = (unsigned short)u;
435 if ( norm > (unsigned int)pbook_move[0].freq + USHRT_MAX )
437 str_error = "normalization error";
442 = (unsigned short)( pbook_move[0].freq + USHRT_MAX - norm );
448 #if ! defined(MINIMUM)
450 #define MaxNumCell 0x400000
451 #if defined(BK_SMALL) || defined(BK_TINY)
452 # define MaxPlyBook 64
454 # define MaxPlyBook 128
458 unsigned int nwin, ngame, nwin_bnz, ngame_bnz, move;
463 unsigned short smove;
464 unsigned char result;
467 static unsigned int CONV move2bm( unsigned int move, int turn, int is_flip );
468 static int CONV find_min_cell( const cell_t *pcell, int ntemp );
469 static int CONV read_a_cell( cell_t *pcell, FILE *pf );
470 static int compare( const void * p1, const void *p2 );
471 static int CONV dump_cell( cell_t *pcell, int ncell, int num_tmpfile );
472 static int CONV examine_game( tree_t * restrict ptree, record_t *pr,
473 int *presult, unsigned int *pmoves );
474 static int CONV move_selection( const record_move_t *p, int ngame, int nwin );
475 static int CONV make_cell_csa( tree_t * restrict ptree, record_t *pr,
476 cell_t *pcell, int num_tmpfile );
477 static int CONV merge_cell( record_move_t *precord_move, FILE **ppf,
479 static int CONV read_anti_book( tree_t * restrict ptree, record_t * pr );
482 book_create( tree_t * restrict ptree )
486 char str_filename[SIZE_FILENAME];
487 record_move_t *precord_move;
489 int iret, num_tmpfile, i, j;
494 pcell = memory_alloc( sizeof(cell_t) * MaxNumCell );
495 if ( pcell == NULL ) { return -2; }
497 Out("\n [book.csa]\n");
499 iret = record_open( &record, "book.csa", mode_read, NULL, NULL );
500 if ( iret < 0 ) { return iret; }
502 num_tmpfile = make_cell_csa( ptree, &record, pcell, num_tmpfile );
503 if ( num_tmpfile < 0 )
505 memory_free( pcell );
506 record_close( &record );
510 iret = record_close( &record );
513 memory_free( pcell );
517 memory_free( pcell );
521 str_error = "No book data";
525 if ( num_tmpfile > 100 )
527 str_error = "Number of tmp??.bin files are too large.";
532 if ( iret < 0 ) { return iret; }
534 pf_book = file_open( str_book, "wb" );
535 if ( pf_book == NULL ) { return -2; }
537 precord_move = memory_alloc( sizeof(record_move_t) * (MAX_LEGAL_MOVES+1) );
538 if ( precord_move == NULL ) { return -2; }
540 for ( i = 0; i < num_tmpfile; i++ )
542 snprintf( str_filename, SIZE_FILENAME, "tmp%02d.bin", i );
543 ppf[i] = file_open( str_filename, "rb" );
544 if ( ppf[i] == NULL )
546 memory_free( precord_move );
547 file_close( pf_book );
548 for ( j = 0; j < i; j++ ) { file_close( ppf[j] ); }
553 iret = merge_cell( precord_move, ppf, num_tmpfile );
556 memory_free( precord_move );
557 file_close( pf_book );
558 for ( i = 0; i < num_tmpfile; i++ ) { file_close( ppf[i] ); }
562 memory_free( precord_move );
565 if ( iret < 0 ) { return iret; }
568 iret = record_open( &record, "book_anti.csa", mode_read, NULL, NULL );
569 if ( iret < 0 ) { return iret; }
571 iret = read_anti_book( ptree, &record );
574 record_close( &record );
579 return record_close( &record );
584 read_anti_book( tree_t * restrict ptree, record_t * pr )
587 book_move_t abook_move[ BK_MAX_MOVE+1 ];
589 unsigned int move, position, bm, umoves;
590 int iret, result, istatus, is_flip, i, moves;
594 istatus = examine_game( ptree, pr, &result, &umoves );
595 if ( istatus < 0 ) { return istatus; }
598 str_error = "no result in book_anti.csa";
602 while ( pr->moves < umoves-1U )
604 istatus = in_CSA( ptree, pr, NULL, 0 );
605 if ( istatus != record_misc )
607 str_error = "internal error at book.c";
612 istatus = in_CSA( ptree, pr, &move, flag_nomake_move );
613 if ( istatus < 0 ) { return istatus; }
615 key = book_hash_func( ptree, &is_flip );
617 moves = book_read( key, abook_move, &position );
618 if ( moves < 0 ) { return moves; }
620 bm = move2bm( move, root_turn, is_flip );
621 for ( i = 0; i < moves; i++ )
623 if ( bm == abook_move[i].smove ) { break; }
628 out_board( ptree, stdout, 0, 0 );
629 printf( "%s is not found in the book\n\n", str_CSA_move(move) );
632 abook_move[i].freq = 0;
634 iret = normalize_book_move( abook_move, moves );
635 if ( iret < 0 ) { return iret; }
637 for ( i = 0; i < moves; i++ )
639 *(unsigned short *)( book_section + i*BK_SIZE_MOVE )
640 = abook_move[i].smove;
641 *(unsigned short *)( book_section + i*BK_SIZE_MOVE + 2 )
642 = abook_move[i].freq;
644 size = (size_t)( moves * BK_SIZE_MOVE );
645 if ( fseek( pf_book, (long)(position+BK_SIZE_HEADER), SEEK_SET ) == EOF
646 || fwrite( book_section, sizeof(unsigned char),
647 size, pf_book ) != size )
649 str_error = str_io_error;
653 out_board( ptree, stdout, 0, 0 );
654 printf( "%s is discarded\n\n", str_CSA_move(move) );
657 if ( istatus != record_eof && istatus != record_next )
659 istatus = record_wind( pr );
660 if ( istatus < 0 ) { return istatus; }
662 } while ( istatus != record_eof );
669 make_cell_csa( tree_t * restrict ptree, record_t *pr, cell_t *pcell,
674 unsigned int hand, move;
675 } rep_tbl[MaxPlyBook+1];
677 unsigned int nwhite_win, nblack_win, ndraw, ninvalid, nbnz_black, nbnz_white;
678 unsigned int move, moves, uresult;
679 int icell, result, is_flip, iret, istatus, ply, i, black_bnz, white_bnz;
681 nwhite_win = nblack_win = ndraw = ninvalid = nbnz_white = nbnz_black = 0;
682 icell = black_bnz = white_bnz = 0;
683 istatus = record_next;
685 while ( istatus != record_eof ) {
687 istatus = examine_game( ptree, pr, &result, &moves );
688 if ( istatus < 0 ) { return istatus; }
690 if ( result == -1 ) { nwhite_win++; }
691 else if ( result == 1 ) { nblack_win++; }
692 else if ( result == 0 ) { ndraw++; }
698 if ( moves > MaxPlyBook ) { moves = MaxPlyBook; }
700 for ( ply = 0;; ply++ ) {
701 istatus = in_CSA( ptree, pr, &move, flag_nomake_move );
704 black_bnz = strcmp( pr->str_name1, "Bonanza" ) ? 0 : 1;
705 white_bnz = strcmp( pr->str_name2, "Bonanza" ) ? 0 : 1;
706 if ( ! strcmp( pr->str_name1, "Bonanza" ) )
711 else { black_bnz = 0; }
712 if ( ! strcmp( pr->str_name2, "Bonanza" ) )
717 else { white_bnz = 0; }
719 if ( istatus < 0 ) { return istatus; }
720 if ( istatus == record_resign && ! moves ) { break; }
721 if ( istatus != record_misc )
723 str_error = "internal error at book.c";
727 rep_tbl[ply].hash_key = HASH_KEY;
728 rep_tbl[ply].hand = HAND_B;
729 rep_tbl[ply].move = move;
730 for ( i = ( ply & 1 ); i < ply; i += 2 )
732 if ( rep_tbl[i].hash_key == HASH_KEY
733 && rep_tbl[i].hand == HAND_B
734 && rep_tbl[i].move == move ) { break; }
738 key = book_hash_func( ptree, &is_flip );
739 uresult = (unsigned int)( root_turn ? -1*result+1 : result+1 );
740 if ( ( root_turn == black && black_bnz )
741 || ( root_turn == white && white_bnz ) ) { uresult |= 0x4U; }
743 pcell[icell].key = key;
744 pcell[icell].result = (unsigned char)uresult;
745 pcell[icell].smove = (unsigned short)move2bm( move, root_turn,
748 if ( icell == MaxNumCell ) {
749 iret = dump_cell( pcell, icell, num_tmpfile++ );
750 if ( iret < 0 ) { return iret; }
753 if ( ! ( (icell-1) & 0x1ffff ) ) { Out( "." ); }
756 if ( pr->moves >= moves ) { break; }
758 iret = make_move_root( ptree, move, 0 );
759 if ( iret < 0 ) { return iret; }
762 if ( istatus != record_eof && istatus != record_next )
764 istatus = record_wind( pr );
765 if ( istatus < 0 ) { return istatus; }
769 iret = dump_cell( pcell, icell, num_tmpfile++ );
770 if ( iret < 0 ) { return iret; }
779 " White Bnz: %7u\n", nblack_win + nwhite_win + ndraw + ninvalid,
780 ninvalid, nblack_win, nwhite_win, ndraw, nbnz_black, nbnz_white );
787 merge_cell( record_move_t *precord_move, FILE **ppf, int num_tmpfile )
793 unsigned int book_moves, book_positions, move, size_data, size_section;
794 unsigned int max_size_section, nwin, nwin_bnz, ngame, ngame_bnz, position;
795 unsigned int u, norm;
796 int i, j, iret, ibook_section, imin, nmove;
799 for ( i = 0; i < num_tmpfile; i++ )
801 iret = read_a_cell( acell + i, ppf[i] );
802 if ( iret < 0 ) { return iret; }
805 imin = find_min_cell( acell, num_tmpfile );
806 position = BK_SIZE_INDEX * NUM_SECTION;
807 max_size_section = book_moves = book_positions = 0;
808 for ( ibook_section = 0; ibook_section < NUM_SECTION; ibook_section++ ) {
811 key = acell[imin].key;
812 i = (int)( (unsigned int)key & (unsigned int)(NUM_SECTION-1) );
813 if ( i != ibook_section || key == UINT64_MAX ) { break; }
815 nwin = nmove = nwin_bnz = ngame = ngame_bnz = precord_move[0].move = 0;
817 move = (unsigned int)acell[imin].smove;
818 for ( i = 0; precord_move[i].move && precord_move[i].move != move;
820 if ( ! precord_move[i].move )
822 precord_move[i].nwin = precord_move[i].ngame = 0;
823 precord_move[i].nwin_bnz = precord_move[i].ngame_bnz = 0;
824 precord_move[i].move = move;
825 precord_move[i+1].move = 0;
829 if ( acell[imin].result & b0010 )
831 if ( acell[imin].result & b0100 )
833 precord_move[i].nwin_bnz += 1;
836 precord_move[i].nwin += 1;
840 if ( acell[imin].result & b0100 )
842 precord_move[i].ngame_bnz += 1;
845 precord_move[i].ngame += 1;
848 iret = read_a_cell( acell + imin, ppf[imin] );
849 if ( iret < 0 ) { return iret; }
851 imin = find_min_cell( acell, num_tmpfile );
852 } while ( key == acell[imin].key );
855 while ( nmove > 1 && ngame_bnz >= 128 )
857 double max_rate, rate;
860 for ( i = 0; i < nmove; i++ )
862 rate = ( (double)precord_move[i].nwin_bnz
863 / (double)( precord_move[i].ngame_bnz + 7 ) );
864 if ( rate > max_rate ) { max_rate = rate; }
866 if ( max_rate < 0.1 ) { break; }
871 rate = ( (double)precord_move[i].nwin_bnz
872 / (double)( precord_move[i].ngame_bnz + 7 ) );
874 if ( rate > max_rate ) { i++; }
876 precord_move[i] = precord_move[nmove-1];
879 } while ( i < nmove );
884 if ( ! nmove ) { continue; }
888 if ( move_selection( precord_move + i, ngame, nwin ) ) { i++; }
890 precord_move[i] = precord_move[nmove-1];
893 } while ( i < nmove );
895 if ( ! nmove ) { continue; }
897 size_data = BK_SIZE_HEADER + BK_SIZE_MOVE * nmove;
898 if ( size_section + size_data > MAX_SIZE_SECTION
899 || size_data > UCHAR_MAX )
901 str_error = "book_section buffer overflow";
904 if ( nmove > BK_MAX_MOVE )
906 str_error = "BK_MAX_MOVE is too small";
910 /* insertion sort by nwin */
911 precord_move[nmove].nwin = 0;
912 for ( i = nmove-2; i >= 0; i-- )
914 u = precord_move[i].nwin;
915 swap = precord_move[i];
916 for ( j = i+1; precord_move[j].nwin > u; j++ )
918 precord_move[j-1] = precord_move[j];
920 precord_move[j-1] = swap;
924 for ( norm = 0, i = 0; i < nmove; i++ ) { norm += precord_move[i].nwin; }
925 dscale = (double)USHRT_MAX / (double)norm;
926 for ( norm = 0, i = 0; i < nmove; i++ )
928 u = (unsigned int)( (double)precord_move[i].nwin * dscale );
929 if ( ! u ) { u = 1U; }
930 if ( u > USHRT_MAX ) { u = USHRT_MAX; }
932 precord_move[i].nwin = u;
935 if ( norm > precord_move[0].nwin + USHRT_MAX )
937 str_error = "normalization error\n";
940 precord_move[0].nwin += USHRT_MAX - norm;
942 book_section[size_section+0] = (unsigned char)size_data;
943 *(uint64_t *)(book_section+size_section+1) = key;
945 for ( u = size_section+BK_SIZE_HEADER, i = 0; i < nmove;
946 u += BK_SIZE_MOVE, i++ )
948 *(unsigned short *)(book_section+u)
949 = (unsigned short)precord_move[i].move;
950 *(unsigned short *)(book_section+u+2)
951 = (unsigned short)precord_move[i].nwin;
955 size_section += size_data;
957 if ( fseek( pf_book, BK_SIZE_INDEX * ibook_section, SEEK_SET ) == EOF )
959 str_error = str_io_error;
962 if ( fwrite( &position, sizeof(unsigned int), 1, pf_book ) != 1 )
964 str_error = str_io_error;
967 s = (unsigned short)size_section;
968 if ( fwrite( &s, sizeof(unsigned short), 1, pf_book ) != 1 )
970 str_error = str_io_error;
973 if ( fseek( pf_book, position, SEEK_SET ) == EOF )
975 str_error = str_io_error;
978 if ( fwrite( &book_section, sizeof(unsigned char), (size_t)size_section,
979 pf_book ) != (size_t)size_section )
981 str_error = str_io_error;
985 if ( size_section > max_size_section ) { max_size_section = size_section; }
986 position += size_section;
989 Out( "Positions in the book: %u\n", book_positions );
990 Out( "Moves in the book: %u\n", book_moves );
991 Out( "Max. size of a section: %d\n", max_size_section );
998 move_selection( const record_move_t *p, int ngame, int nwin )
1000 double total_win_norm, win_norm, win, game, win_move, game_move;
1002 #if defined(BK_TINY)
1003 if ( p->nwin < 15 ) { return 0; }
1004 #elif defined(BK_SMALL)
1005 if ( p->nwin < 3 ) { return 0; }
1007 if ( ! p->nwin || p->ngame < 2 ) { return 0; }
1011 game = (double)ngame;
1012 win_move = (double)p->nwin;
1013 game_move = (double)p->ngame;
1015 total_win_norm = win * game_move;
1016 win_norm = win_move * game;
1017 if ( win_norm < total_win_norm * 0.85 ) { return 0; }
1024 find_min_cell( const cell_t *pcell, int num_tmpfile )
1029 for ( i = 1; i < num_tmpfile; i++ )
1031 if ( compare( pcell+imin, pcell+i ) == 1 ) { imin = i; }
1038 read_a_cell( cell_t *pcell, FILE *pf )
1040 if ( fread( &pcell->key, sizeof(uint64_t), 1, pf ) != 1 )
1044 pcell->key = UINT64_MAX;
1047 str_error = str_io_error;
1050 if ( fread( &pcell->smove, sizeof(unsigned short), 1, pf ) != 1 )
1052 str_error = str_io_error;
1055 if ( fread( &pcell->result, sizeof(unsigned char), 1, pf ) != 1 )
1057 str_error = str_io_error;
1066 examine_game( tree_t * restrict ptree, record_t *pr, int *presult,
1067 unsigned int *pmoves )
1070 int iret, istatus, is_lost, is_win;
1075 iret = record_getpos( pr, &rpos );
1076 if ( iret < 0 ) { return iret; }
1078 is_lost = is_win = 0;
1081 istatus = in_CSA( ptree, pr, NULL, flag_detect_hang );
1084 /* the game is end, however the record is invalid */
1085 if ( strstr( str_error, str_bad_record ) != NULL
1086 && ( game_status & mask_game_end ) )
1091 /* a hang-king and a double-pawn are counted as a lost game */
1092 if ( strstr( str_error, str_king_hang ) != NULL
1093 || strstr( str_error, str_double_pawn ) != NULL
1094 || strstr( str_error, str_mate_drppawn ) != NULL )
1102 /* previous move had an error, count as a won game */
1103 else if ( istatus == record_error )
1108 else if ( istatus == record_misc ) { moves++; }
1109 } while ( istatus != record_next && istatus != record_eof );
1111 if ( istatus != record_next && istatus != record_eof )
1113 istatus = record_wind( pr );
1114 if ( istatus < 0 ) { return istatus; }
1117 if ( ! ( is_lost || is_win || ( game_status & mask_game_end ) ) )
1122 if ( is_win ) { *presult = root_turn ? -1 : 1; }
1123 else if ( is_lost || ( game_status & ( flag_mated | flag_resigned ) ) )
1125 *presult = root_turn ? 1 : -1;
1127 else { *presult = 0; }
1131 iret = record_setpos( pr, &rpos );
1132 if ( iret < 0 ) { return iret; }
1139 dump_cell( cell_t *pcell, int ncell, int num_tmpfile )
1141 char str_filename[SIZE_FILENAME];
1146 qsort( pcell, ncell, sizeof(cell_t), compare );
1148 Out( " dump", str_filename );
1149 snprintf( str_filename, SIZE_FILENAME, "tmp%02d.bin", num_tmpfile );
1150 pf = file_open( str_filename, "wb" );
1151 if ( pf == NULL ) { return -2; }
1153 for ( i = 0; i < ncell; i++ )
1155 if ( fwrite( &pcell[i].key, sizeof(uint64_t), 1, pf ) != 1 )
1158 str_error = str_io_error;
1161 if ( fwrite( &pcell[i].smove, sizeof(unsigned short), 1, pf ) != 1 )
1164 str_error = str_io_error;
1167 if ( fwrite( &pcell[i].result, sizeof(unsigned char), 1, pf ) != 1 )
1170 str_error = str_io_error;
1175 iret = file_close( pf );
1176 if ( iret < 0 ) { return iret; }
1178 Out( " done (%s)\n", str_filename );
1184 static int compare( const void * p1, const void * p2 )
1186 const cell_t * pcell1 = p1;
1187 const cell_t * pcell2 = p2;
1188 unsigned int u1, u2;
1190 u1 = (unsigned int)pcell1->key & (unsigned int)(NUM_SECTION-1);
1191 u2 = (unsigned int)pcell2->key & (unsigned int)(NUM_SECTION-1);
1193 if ( u1 < u2 ) { return -1; }
1194 if ( u1 > u2 ) { return 1; }
1195 if ( pcell1->key < pcell2->key ) { return -1; }
1196 if ( pcell1->key > pcell2->key ) { return 1; }
1202 static unsigned int CONV
1203 move2bm( unsigned int move, int turn, int is_flip )
1210 ft.from = I2From(move);
1211 is_promote = I2IsPromote(move);
1213 ft = flip_ft( ft, turn, is_flip );
1215 bmove = (unsigned int)( is_promote | From2Move(ft.from) | ft.to );
1221 #endif /* no MINIMUM */