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 ) ) )
148 Out( SIGN " move freq\n" );
149 OutCsaShogi( "info" );
150 for ( i = 0; i < moves; i++ )
154 dscore = (double)abook_move[i].freq / (double)USHRT_MAX;
155 move = bm2move( ptree, (unsigned int)abook_move[i].smove, is_flip );
156 str = str_CSA_move( move );
158 Out( " %c %s %5.1f\n", i == j ? '*' : ' ', str, dscore * 100.0 );
159 OutCsaShogi( " %s(%.0f%%)", str, dscore * 100.0 );
164 move = bm2move( ptree, (unsigned int)abook_move[j].smove, is_flip );
165 if ( ! is_move_valid( ptree, move, root_turn ) )
167 out_warning( "BAD BOOK MOVE!! " );
171 ply = record_game.moves;
172 if ( game_status & flag_pondering ) { ply++; }
174 ptree->current_move[1] = move;
181 book_read( uint64_t key, book_move_t *pbook_move, unsigned int *pposition )
184 const unsigned char *p;
185 unsigned int position, size_section, size, u;
186 int ibook_section, moves;
189 ibook_section = (int)( (unsigned int)key & (unsigned int)( NUM_SECTION-1 ) );
191 if ( fseek( pf_book, BK_SIZE_INDEX*ibook_section, SEEK_SET ) == EOF )
193 str_error = str_io_error;
197 if ( fread( &position, sizeof(int), 1, pf_book ) != 1 )
199 str_error = str_io_error;
203 if ( fread( &s, sizeof(unsigned short), 1, pf_book ) != 1 )
205 str_error = str_io_error;
208 size_section = (unsigned int)s;
209 if ( size_section > MAX_SIZE_SECTION )
211 str_error = str_book_error;
215 if ( fseek( pf_book, (long)position, SEEK_SET ) == EOF )
217 str_error = str_io_error;
220 if ( fread( book_section, sizeof(unsigned char), (size_t)size_section,
221 pf_book ) != (size_t)size_section )
223 str_error = str_io_error;
229 *pposition = position;
230 while ( book_section + size_section > p )
232 size = (unsigned int)p[0];
233 book_key = *(uint64_t *)( p + 1 );
234 if ( book_key == key ) { break; }
238 if ( book_section + size_section <= p ) { return 0; }
240 for ( moves = 0, u = BK_SIZE_HEADER; u < size; moves++, u += BK_SIZE_MOVE )
242 pbook_move[moves].smove = *(unsigned short *)(p+u+0);
243 pbook_move[moves].freq = *(unsigned short *)(p+u+2);
251 flip_ft( ft_t ft, int turn, int is_flip )
253 int ito_rank, ito_file, ifrom_rank, ifrom_file;
255 ito_rank = airank[ft.to];
256 ito_file = aifile[ft.to];
257 if ( ft.from < nsquare )
259 ifrom_rank = airank[ft.from];
260 ifrom_file = aifile[ft.from];
262 else { ifrom_rank = ifrom_file = 0; }
266 ito_rank = rank9 - ito_rank;
267 ito_file = file9 - ito_file;
268 if ( ft.from < nsquare )
270 ifrom_rank = rank9 - ifrom_rank;
271 ifrom_file = file9 - ifrom_file;
277 ito_file = file9 - ito_file;
278 if ( ft.from < nsquare ) { ifrom_file = file9 - ifrom_file; }
281 ft.to = ito_rank * nfile + ito_file;
282 if ( ft.from < nsquare ) { ft.from = ifrom_rank * nfile + ifrom_file; }
288 static unsigned int CONV
289 bm2move( const tree_t * restrict ptree, unsigned int bmove, int is_flip )
296 ft.from = I2From(bmove);
297 ft = flip_ft( ft, root_turn, is_flip );
298 is_promote = I2IsPromote(bmove);
300 move = (unsigned int)( is_promote | From2Move(ft.from) | ft.to );
301 if ( ft.from >= nsquare ) { return move; }
305 move |= Cap2Move(BOARD[ft.to]);
306 move |= Piece2Move(-BOARD[ft.from]);
309 move |= Cap2Move(-BOARD[ft.to]);
310 move |= Piece2Move(BOARD[ft.from]);
318 book_hash_func( const tree_t * restrict ptree, int *pis_flip )
320 uint64_t key, key_flip;
322 int i, iflip, irank, ifile, piece;
325 hand = root_turn ? HAND_W : HAND_B;
326 i = I2HandPawn(hand); if ( i ) { key ^= b_hand_pawn_rand[i-1]; }
327 i = I2HandLance(hand); if ( i ) { key ^= b_hand_lance_rand[i-1]; }
328 i = I2HandKnight(hand); if ( i ) { key ^= b_hand_knight_rand[i-1]; }
329 i = I2HandSilver(hand); if ( i ) { key ^= b_hand_silver_rand[i-1]; }
330 i = I2HandGold(hand); if ( i ) { key ^= b_hand_gold_rand[i-1]; }
331 i = I2HandBishop(hand); if ( i ) { key ^= b_hand_bishop_rand[i-1]; }
332 i = I2HandRook(hand); if ( i ) { key ^= b_hand_rook_rand[i-1]; }
334 hand = root_turn ? HAND_B : HAND_W;
335 i = I2HandPawn(hand); if ( i ) { key ^= w_hand_pawn_rand[i-1]; }
336 i = I2HandLance(hand); if ( i ) { key ^= w_hand_lance_rand[i-1]; }
337 i = I2HandKnight(hand); if ( i ) { key ^= w_hand_knight_rand[i-1]; }
338 i = I2HandSilver(hand); if ( i ) { key ^= w_hand_silver_rand[i-1]; }
339 i = I2HandGold(hand); if ( i ) { key ^= w_hand_gold_rand[i-1]; }
340 i = I2HandBishop(hand); if ( i ) { key ^= w_hand_bishop_rand[i-1]; }
341 i = I2HandRook(hand); if ( i ) { key ^= w_hand_rook_rand[i-1]; }
345 for ( irank = rank1; irank <= rank9; irank++ )
346 for ( ifile = file1; ifile <= file9; ifile++ )
350 i = ( rank9 - irank ) * nfile + file9 - ifile;
351 iflip = ( rank9 - irank ) * nfile + ifile;
352 piece = -(int)BOARD[nsquare-i-1];
355 i = irank * nfile + ifile;
356 iflip = irank * nfile + file9 - ifile;
357 piece = (int)BOARD[i];
360 #define Foo(t_pc) key ^= (t_pc ## _rand)[i]; \
361 key_flip ^= (t_pc ## _rand)[iflip];
364 case pawn: Foo( b_pawn ); break;
365 case lance: Foo( b_lance ); break;
366 case knight: Foo( b_knight ); break;
367 case silver: Foo( b_silver ); break;
368 case gold: Foo( b_gold ); break;
369 case bishop: Foo( b_bishop ); break;
370 case rook: Foo( b_rook ); break;
371 case king: Foo( b_king ); break;
372 case pro_pawn: Foo( b_pro_pawn ); break;
373 case pro_lance: Foo( b_pro_lance ); break;
374 case pro_knight: Foo( b_pro_knight ); break;
375 case pro_silver: Foo( b_pro_silver ); break;
376 case horse: Foo( b_horse ); break;
377 case dragon: Foo( b_dragon ); break;
378 case -pawn: Foo( w_pawn ); break;
379 case -lance: Foo( w_lance ); break;
380 case -knight: Foo( w_knight ); break;
381 case -silver: Foo( w_silver ); break;
382 case -gold: Foo( w_gold ); break;
383 case -bishop: Foo( w_bishop ); break;
384 case -rook: Foo( w_rook ); break;
385 case -king: Foo( w_king ); break;
386 case -pro_pawn: Foo( w_pro_pawn ); break;
387 case -pro_lance: Foo( w_pro_lance ); break;
388 case -pro_knight: Foo( w_pro_knight ); break;
389 case -pro_silver: Foo( w_pro_silver ); break;
390 case -horse: Foo( w_horse ); break;
391 case -dragon: Foo( w_dragon ); break;
396 if ( key > key_flip )
401 else { *pis_flip = 0; }
408 normalize_book_move( book_move_t * restrict pbook_move, int moves )
412 unsigned int u, norm;
415 /* insertion sort by nwin */
416 pbook_move[moves].freq = 0;
417 for ( i = moves-2; i >= 0; i-- )
419 u = pbook_move[i].freq;
420 swap = pbook_move[i];
421 for ( j = i+1; pbook_move[j].freq > u; j++ )
423 pbook_move[j-1] = pbook_move[j];
425 pbook_move[j-1] = swap;
429 for ( norm = 0, i = 0; i < moves; i++ ) { norm += pbook_move[i].freq; }
430 dscale = (double)USHRT_MAX / (double)norm;
431 for ( norm = 0, i = 0; i < moves; i++ )
433 u = (unsigned int)( (double)pbook_move[i].freq * dscale );
434 if ( ! u ) { u = 1U; }
435 if ( u > USHRT_MAX ) { u = USHRT_MAX; }
437 pbook_move[i].freq = (unsigned short)u;
440 if ( norm > (unsigned int)pbook_move[0].freq + USHRT_MAX )
442 str_error = "normalization error";
447 = (unsigned short)( pbook_move[0].freq + USHRT_MAX - norm );
453 #if ! defined(MINIMUM)
455 #define MaxNumCell 0x400000
456 #if defined(BK_SMALL) || defined(BK_TINY)
457 # define MaxPlyBook 64
459 # define MaxPlyBook 128
463 unsigned int nwin, ngame, nwin_bnz, ngame_bnz, move;
468 unsigned short smove;
469 unsigned char result;
472 static unsigned int CONV move2bm( unsigned int move, int turn, int is_flip );
473 static int CONV find_min_cell( const cell_t *pcell, int ntemp );
474 static int CONV read_a_cell( cell_t *pcell, FILE *pf );
475 static int compare( const void * p1, const void *p2 );
476 static int CONV dump_cell( cell_t *pcell, int ncell, int num_tmpfile );
477 static int CONV examine_game( tree_t * restrict ptree, record_t *pr,
478 int *presult, unsigned int *pmoves );
479 static int CONV move_selection( const record_move_t *p, int ngame, int nwin );
480 static int CONV make_cell_csa( tree_t * restrict ptree, record_t *pr,
481 cell_t *pcell, int num_tmpfile );
482 static int CONV merge_cell( record_move_t *precord_move, FILE **ppf,
484 static int CONV read_anti_book( tree_t * restrict ptree, record_t * pr );
487 book_create( tree_t * restrict ptree )
491 char str_filename[SIZE_FILENAME];
492 record_move_t *precord_move;
494 int iret, num_tmpfile, i, j;
499 pcell = memory_alloc( sizeof(cell_t) * MaxNumCell );
500 if ( pcell == NULL ) { return -2; }
502 Out("\n [book.csa]\n");
504 iret = record_open( &record, "book.csa", mode_read, NULL, NULL );
505 if ( iret < 0 ) { return iret; }
507 num_tmpfile = make_cell_csa( ptree, &record, pcell, num_tmpfile );
508 if ( num_tmpfile < 0 )
510 memory_free( pcell );
511 record_close( &record );
515 iret = record_close( &record );
518 memory_free( pcell );
522 memory_free( pcell );
526 str_error = "No book data";
530 if ( num_tmpfile > 100 )
532 str_error = "Number of tmp??.bin files are too large.";
537 if ( iret < 0 ) { return iret; }
539 pf_book = file_open( str_book, "wb" );
540 if ( pf_book == NULL ) { return -2; }
542 precord_move = memory_alloc( sizeof(record_move_t) * (MAX_LEGAL_MOVES+1) );
543 if ( precord_move == NULL ) { return -2; }
545 for ( i = 0; i < num_tmpfile; i++ )
547 snprintf( str_filename, SIZE_FILENAME, "tmp%02d.bin", i );
548 ppf[i] = file_open( str_filename, "rb" );
549 if ( ppf[i] == NULL )
551 memory_free( precord_move );
552 file_close( pf_book );
553 for ( j = 0; j < i; j++ ) { file_close( ppf[j] ); }
558 iret = merge_cell( precord_move, ppf, num_tmpfile );
561 memory_free( precord_move );
562 file_close( pf_book );
563 for ( i = 0; i < num_tmpfile; i++ ) { file_close( ppf[i] ); }
567 memory_free( precord_move );
570 if ( iret < 0 ) { return iret; }
573 iret = record_open( &record, "book_anti.csa", mode_read, NULL, NULL );
574 if ( iret < 0 ) { return iret; }
576 iret = read_anti_book( ptree, &record );
579 record_close( &record );
584 return record_close( &record );
589 read_anti_book( tree_t * restrict ptree, record_t * pr )
592 book_move_t abook_move[ BK_MAX_MOVE+1 ];
594 unsigned int move, position, bm, umoves;
595 int iret, result, istatus, is_flip, i, moves;
599 istatus = examine_game( ptree, pr, &result, &umoves );
600 if ( istatus < 0 ) { return istatus; }
603 str_error = "no result in book_anti.csa";
607 while ( pr->moves < umoves-1U )
609 istatus = in_CSA( ptree, pr, NULL, 0 );
610 if ( istatus != record_misc )
612 str_error = "internal error at book.c";
617 istatus = in_CSA( ptree, pr, &move, flag_nomake_move );
618 if ( istatus < 0 ) { return istatus; }
620 key = book_hash_func( ptree, &is_flip );
622 moves = book_read( key, abook_move, &position );
623 if ( moves < 0 ) { return moves; }
625 bm = move2bm( move, root_turn, is_flip );
626 for ( i = 0; i < moves; i++ )
628 if ( bm == abook_move[i].smove ) { break; }
633 out_board( ptree, stdout, 0, 0 );
634 printf( "%s is not found in the book\n\n", str_CSA_move(move) );
637 abook_move[i].freq = 0;
639 iret = normalize_book_move( abook_move, moves );
640 if ( iret < 0 ) { return iret; }
642 for ( i = 0; i < moves; i++ )
644 *(unsigned short *)( book_section + i*BK_SIZE_MOVE )
645 = abook_move[i].smove;
646 *(unsigned short *)( book_section + i*BK_SIZE_MOVE + 2 )
647 = abook_move[i].freq;
649 size = (size_t)( moves * BK_SIZE_MOVE );
650 if ( fseek( pf_book, (long)(position+BK_SIZE_HEADER), SEEK_SET ) == EOF
651 || fwrite( book_section, sizeof(unsigned char),
652 size, pf_book ) != size )
654 str_error = str_io_error;
658 out_board( ptree, stdout, 0, 0 );
659 printf( "%s is discarded\n\n", str_CSA_move(move) );
662 if ( istatus != record_eof && istatus != record_next )
664 istatus = record_wind( pr );
665 if ( istatus < 0 ) { return istatus; }
667 } while ( istatus != record_eof );
674 make_cell_csa( tree_t * restrict ptree, record_t *pr, cell_t *pcell,
679 unsigned int hand, move;
680 } rep_tbl[MaxPlyBook+1];
682 unsigned int nwhite_win, nblack_win, ndraw, ninvalid, nbnz_black, nbnz_white;
683 unsigned int move, moves, uresult;
684 int icell, result, is_flip, iret, istatus, ply, i, black_bnz, white_bnz;
686 nwhite_win = nblack_win = ndraw = ninvalid = nbnz_white = nbnz_black = 0;
687 icell = black_bnz = white_bnz = 0;
688 istatus = record_next;
690 while ( istatus != record_eof ) {
692 istatus = examine_game( ptree, pr, &result, &moves );
693 if ( istatus < 0 ) { return istatus; }
695 if ( result == -1 ) { nwhite_win++; }
696 else if ( result == 1 ) { nblack_win++; }
697 else if ( result == 0 ) { ndraw++; }
703 if ( moves > MaxPlyBook ) { moves = MaxPlyBook; }
705 for ( ply = 0;; ply++ ) {
706 istatus = in_CSA( ptree, pr, &move, flag_nomake_move );
709 black_bnz = strcmp( pr->str_name1, "Bonanza" ) ? 0 : 1;
710 white_bnz = strcmp( pr->str_name2, "Bonanza" ) ? 0 : 1;
711 if ( ! strcmp( pr->str_name1, "Bonanza" ) )
716 else { black_bnz = 0; }
717 if ( ! strcmp( pr->str_name2, "Bonanza" ) )
722 else { white_bnz = 0; }
724 if ( istatus < 0 ) { return istatus; }
725 if ( istatus == record_resign && ! moves ) { break; }
726 if ( istatus != record_misc )
728 str_error = "internal error at book.c";
732 rep_tbl[ply].hash_key = HASH_KEY;
733 rep_tbl[ply].hand = HAND_B;
734 rep_tbl[ply].move = move;
735 for ( i = ( ply & 1 ); i < ply; i += 2 )
737 if ( rep_tbl[i].hash_key == HASH_KEY
738 && rep_tbl[i].hand == HAND_B
739 && rep_tbl[i].move == move ) { break; }
743 key = book_hash_func( ptree, &is_flip );
744 uresult = (unsigned int)( root_turn ? -1*result+1 : result+1 );
745 if ( ( root_turn == black && black_bnz )
746 || ( root_turn == white && white_bnz ) ) { uresult |= 0x4U; }
748 pcell[icell].key = key;
749 pcell[icell].result = (unsigned char)uresult;
750 pcell[icell].smove = (unsigned short)move2bm( move, root_turn,
753 if ( icell == MaxNumCell ) {
754 iret = dump_cell( pcell, icell, num_tmpfile++ );
755 if ( iret < 0 ) { return iret; }
758 if ( ! ( (icell-1) & 0x1ffff ) ) { Out( "." ); }
761 if ( pr->moves >= moves ) { break; }
763 iret = make_move_root( ptree, move, 0 );
764 if ( iret < 0 ) { return iret; }
767 if ( istatus != record_eof && istatus != record_next )
769 istatus = record_wind( pr );
770 if ( istatus < 0 ) { return istatus; }
774 iret = dump_cell( pcell, icell, num_tmpfile++ );
775 if ( iret < 0 ) { return iret; }
784 " White Bnz: %7u\n", nblack_win + nwhite_win + ndraw + ninvalid,
785 ninvalid, nblack_win, nwhite_win, ndraw, nbnz_black, nbnz_white );
792 merge_cell( record_move_t *precord_move, FILE **ppf, int num_tmpfile )
798 unsigned int book_moves, book_positions, move, size_data, size_section;
799 unsigned int max_size_section, nwin, nwin_bnz, ngame, ngame_bnz, position;
800 unsigned int u, norm;
801 int i, j, iret, ibook_section, imin, nmove;
804 for ( i = 0; i < num_tmpfile; i++ )
806 iret = read_a_cell( acell + i, ppf[i] );
807 if ( iret < 0 ) { return iret; }
810 imin = find_min_cell( acell, num_tmpfile );
811 position = BK_SIZE_INDEX * NUM_SECTION;
812 max_size_section = book_moves = book_positions = 0;
813 for ( ibook_section = 0; ibook_section < NUM_SECTION; ibook_section++ ) {
816 key = acell[imin].key;
817 i = (int)( (unsigned int)key & (unsigned int)(NUM_SECTION-1) );
818 if ( i != ibook_section || key == UINT64_MAX ) { break; }
820 nwin = nmove = nwin_bnz = ngame = ngame_bnz = precord_move[0].move = 0;
822 move = (unsigned int)acell[imin].smove;
823 for ( i = 0; precord_move[i].move && precord_move[i].move != move;
825 if ( ! precord_move[i].move )
827 precord_move[i].nwin = precord_move[i].ngame = 0;
828 precord_move[i].nwin_bnz = precord_move[i].ngame_bnz = 0;
829 precord_move[i].move = move;
830 precord_move[i+1].move = 0;
834 if ( acell[imin].result & b0010 )
836 if ( acell[imin].result & b0100 )
838 precord_move[i].nwin_bnz += 1;
841 precord_move[i].nwin += 1;
845 if ( acell[imin].result & b0100 )
847 precord_move[i].ngame_bnz += 1;
850 precord_move[i].ngame += 1;
853 iret = read_a_cell( acell + imin, ppf[imin] );
854 if ( iret < 0 ) { return iret; }
856 imin = find_min_cell( acell, num_tmpfile );
857 } while ( key == acell[imin].key );
860 while ( nmove > 1 && ngame_bnz >= 128 )
862 double max_rate, rate;
865 for ( i = 0; i < nmove; i++ )
867 rate = ( (double)precord_move[i].nwin_bnz
868 / (double)( precord_move[i].ngame_bnz + 7 ) );
869 if ( rate > max_rate ) { max_rate = rate; }
871 if ( max_rate < 0.1 ) { break; }
876 rate = ( (double)precord_move[i].nwin_bnz
877 / (double)( precord_move[i].ngame_bnz + 7 ) );
879 if ( rate > max_rate ) { i++; }
881 precord_move[i] = precord_move[nmove-1];
884 } while ( i < nmove );
889 if ( ! nmove ) { continue; }
893 if ( move_selection( precord_move + i, ngame, nwin ) ) { i++; }
895 precord_move[i] = precord_move[nmove-1];
898 } while ( i < nmove );
900 if ( ! nmove ) { continue; }
902 size_data = BK_SIZE_HEADER + BK_SIZE_MOVE * nmove;
903 if ( size_section + size_data > MAX_SIZE_SECTION
904 || size_data > UCHAR_MAX )
906 str_error = "book_section buffer overflow";
909 if ( nmove > BK_MAX_MOVE )
911 str_error = "BK_MAX_MOVE is too small";
915 /* insertion sort by nwin */
916 precord_move[nmove].nwin = 0;
917 for ( i = nmove-2; i >= 0; i-- )
919 u = precord_move[i].nwin;
920 swap = precord_move[i];
921 for ( j = i+1; precord_move[j].nwin > u; j++ )
923 precord_move[j-1] = precord_move[j];
925 precord_move[j-1] = swap;
929 for ( norm = 0, i = 0; i < nmove; i++ ) { norm += precord_move[i].nwin; }
930 dscale = (double)USHRT_MAX / (double)norm;
931 for ( norm = 0, i = 0; i < nmove; i++ )
933 u = (unsigned int)( (double)precord_move[i].nwin * dscale );
934 if ( ! u ) { u = 1U; }
935 if ( u > USHRT_MAX ) { u = USHRT_MAX; }
937 precord_move[i].nwin = u;
940 if ( norm > precord_move[0].nwin + USHRT_MAX )
942 str_error = "normalization error\n";
945 precord_move[0].nwin += USHRT_MAX - norm;
947 book_section[size_section+0] = (unsigned char)size_data;
948 *(uint64_t *)(book_section+size_section+1) = key;
950 for ( u = size_section+BK_SIZE_HEADER, i = 0; i < nmove;
951 u += BK_SIZE_MOVE, i++ )
953 *(unsigned short *)(book_section+u)
954 = (unsigned short)precord_move[i].move;
955 *(unsigned short *)(book_section+u+2)
956 = (unsigned short)precord_move[i].nwin;
960 size_section += size_data;
962 if ( fseek( pf_book, BK_SIZE_INDEX * ibook_section, SEEK_SET ) == EOF )
964 str_error = str_io_error;
967 if ( fwrite( &position, sizeof(unsigned int), 1, pf_book ) != 1 )
969 str_error = str_io_error;
972 s = (unsigned short)size_section;
973 if ( fwrite( &s, sizeof(unsigned short), 1, pf_book ) != 1 )
975 str_error = str_io_error;
978 if ( fseek( pf_book, position, SEEK_SET ) == EOF )
980 str_error = str_io_error;
983 if ( fwrite( &book_section, sizeof(unsigned char), (size_t)size_section,
984 pf_book ) != (size_t)size_section )
986 str_error = str_io_error;
990 if ( size_section > max_size_section ) { max_size_section = size_section; }
991 position += size_section;
994 Out( "Positions in the book: %u\n", book_positions );
995 Out( "Moves in the book: %u\n", book_moves );
996 Out( "Max. size of a section: %d\n", max_size_section );
1003 move_selection( const record_move_t *p, int ngame, int nwin )
1005 double total_win_norm, win_norm, win, game, win_move, game_move;
1007 #if defined(BK_TINY)
1008 if ( p->nwin < 15 ) { return 0; }
1009 #elif defined(BK_SMALL)
1010 if ( p->nwin < 3 ) { return 0; }
1012 if ( ! p->nwin || p->ngame < 2 ) { return 0; }
1016 game = (double)ngame;
1017 win_move = (double)p->nwin;
1018 game_move = (double)p->ngame;
1020 total_win_norm = win * game_move;
1021 win_norm = win_move * game;
1022 if ( win_norm < total_win_norm * 0.85 ) { return 0; }
1029 find_min_cell( const cell_t *pcell, int num_tmpfile )
1034 for ( i = 1; i < num_tmpfile; i++ )
1036 if ( compare( pcell+imin, pcell+i ) == 1 ) { imin = i; }
1043 read_a_cell( cell_t *pcell, FILE *pf )
1045 if ( fread( &pcell->key, sizeof(uint64_t), 1, pf ) != 1 )
1049 pcell->key = UINT64_MAX;
1052 str_error = str_io_error;
1055 if ( fread( &pcell->smove, sizeof(unsigned short), 1, pf ) != 1 )
1057 str_error = str_io_error;
1060 if ( fread( &pcell->result, sizeof(unsigned char), 1, pf ) != 1 )
1062 str_error = str_io_error;
1071 examine_game( tree_t * restrict ptree, record_t *pr, int *presult,
1072 unsigned int *pmoves )
1075 int iret, istatus, is_lost, is_win;
1080 iret = record_getpos( pr, &rpos );
1081 if ( iret < 0 ) { return iret; }
1083 is_lost = is_win = 0;
1086 istatus = in_CSA( ptree, pr, NULL, flag_detect_hang );
1089 /* the game is end, however the record is invalid */
1090 if ( strstr( str_error, str_bad_record ) != NULL
1091 && ( game_status & mask_game_end ) )
1096 /* a hang-king and a double-pawn are counted as a lost game */
1097 if ( strstr( str_error, str_king_hang ) != NULL
1098 || strstr( str_error, str_double_pawn ) != NULL
1099 || strstr( str_error, str_mate_drppawn ) != NULL )
1107 /* previous move had an error, count as a won game */
1108 else if ( istatus == record_error )
1113 else if ( istatus == record_misc ) { moves++; }
1114 } while ( istatus != record_next && istatus != record_eof );
1116 if ( istatus != record_next && istatus != record_eof )
1118 istatus = record_wind( pr );
1119 if ( istatus < 0 ) { return istatus; }
1122 if ( ! ( is_lost || is_win || ( game_status & mask_game_end ) ) )
1127 if ( is_win ) { *presult = root_turn ? -1 : 1; }
1128 else if ( is_lost || ( game_status & ( flag_mated | flag_resigned ) ) )
1130 *presult = root_turn ? 1 : -1;
1132 else { *presult = 0; }
1136 iret = record_setpos( pr, &rpos );
1137 if ( iret < 0 ) { return iret; }
1144 dump_cell( cell_t *pcell, int ncell, int num_tmpfile )
1146 char str_filename[SIZE_FILENAME];
1151 qsort( pcell, ncell, sizeof(cell_t), compare );
1153 Out( " dump", str_filename );
1154 snprintf( str_filename, SIZE_FILENAME, "tmp%02d.bin", num_tmpfile );
1155 pf = file_open( str_filename, "wb" );
1156 if ( pf == NULL ) { return -2; }
1158 for ( i = 0; i < ncell; i++ )
1160 if ( fwrite( &pcell[i].key, sizeof(uint64_t), 1, pf ) != 1 )
1163 str_error = str_io_error;
1166 if ( fwrite( &pcell[i].smove, sizeof(unsigned short), 1, pf ) != 1 )
1169 str_error = str_io_error;
1172 if ( fwrite( &pcell[i].result, sizeof(unsigned char), 1, pf ) != 1 )
1175 str_error = str_io_error;
1180 iret = file_close( pf );
1181 if ( iret < 0 ) { return iret; }
1183 Out( " done (%s)\n", str_filename );
1189 static int compare( const void * p1, const void * p2 )
1191 const cell_t * pcell1 = p1;
1192 const cell_t * pcell2 = p2;
1193 unsigned int u1, u2;
1195 u1 = (unsigned int)pcell1->key & (unsigned int)(NUM_SECTION-1);
1196 u2 = (unsigned int)pcell2->key & (unsigned int)(NUM_SECTION-1);
1198 if ( u1 < u2 ) { return -1; }
1199 if ( u1 > u2 ) { return 1; }
1200 if ( pcell1->key < pcell2->key ) { return -1; }
1201 if ( pcell1->key > pcell2->key ) { return 1; }
1207 static unsigned int CONV
1208 move2bm( unsigned int move, int turn, int is_flip )
1215 ft.from = I2From(move);
1216 is_promote = I2IsPromote(move);
1218 ft = flip_ft( ft, turn, is_flip );
1220 bmove = (unsigned int)( is_promote | From2Move(ft.from) | ft.to );
1226 #endif /* no MINIMUM */