14 #if ! defined(MINIMUM)
16 # define SEARCH_DEPTH 2
18 # define MAX_RECORD_LENGTH 1024
19 # define DOT_INTERVAL 10
20 # define MAX_BOOK_PLY 64
21 # define NumBookCluster 256
22 # define NumBookEntry 0x1000
23 # define SIZE_PV_BUFFER 0x100000
24 # define MOVE_VOID 0x80000000U
25 # define Move2S(move) (unsigned short)((move) & 0x7fffU)
29 struct { uint64_t a,b; } cluster[NumBookCluster];
36 book_entry_t *pbook_entry;
39 unsigned int max_games, id;
43 uint64_t result[ NUM_RESULT ];
44 uint64_t num_moves_counted, num_moves, result_norm, num_nodes;
45 double target, target_out_window;
46 unsigned int illegal_moves, max_pos_buf;
50 unsigned int record_moves[ MAX_RECORD_LENGTH ];
51 unsigned int amove_legal[ MAX_LEGAL_MOVES ];
52 unsigned int record_length, pos_buf;
53 unsigned short buf[ SIZE_PV_BUFFER ];
68 uint64_t num_moves_counted;
73 unsigned short buf[ SIZE_PV_BUFFER ];
74 unsigned int pv[ PLY_MAX + 2 ];
79 static unsigned int __stdcall parse1_worker( void *arg );
80 static unsigned int __stdcall parse2_worker( void *arg );
82 static void *parse1_worker( void *arg );
83 static void *parse2_worker( void *arg );
85 static void ini_book( book_entry_t *pbook_entry );
86 static void make_pv( parse1_data_t *pdata, unsigned int record_move );
87 static int read_game( parse1_data_t *pdata );
88 static int read_buf( unsigned short *buf, FILE *pf );
89 static int calc_deriv( parse2_data_t *pdata, int pos_buf, int turn );
90 static int learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry,
91 FILE *pf_tmp, record_t *precord,
92 unsigned int max_games, double *ptarget_out_window,
93 double *pobj_norm, int tlp1 );
94 static int learn_parse2( tree_t * restrict ptree, FILE *pf_tmp,
95 int nsteps, double target_out_window,
96 double obj_norm, int tlp2 );
97 static int book_probe_learn( const tree_t * restrict ptree,
98 book_entry_t *pbook_entry, int ply,
100 static int rep_check_learn( tree_t * restrict ptree, int ply );
101 static unsigned int s2move( const tree_t * restrict ptree, unsigned int move,
103 static double func( double x );
104 static double dfunc( double x );
107 learn( tree_t * restrict ptree, int is_ini, int nsteps, unsigned int max_games,
108 int max_iterations, int nworker1, int nworker2 )
111 book_entry_t *pbook_entry;
113 double target_out_window, obj_norm;
114 int iret, niterations;
116 pbook_entry = memory_alloc( sizeof(book_entry_t) * NumBookEntry );
117 if ( pbook_entry == NULL ) { return -2; }
122 fmg_misc = fmg_cap = fmg_drop = fmg_mt = 0;
123 fmg_misc_king = fmg_cap_king = 0;
130 fmg_misc_king = FMG_MISC_KING;
131 fmg_cap_king = FMG_CAP_KING;
134 game_status |= flag_learning;
135 root_alpha = - ( score_max_eval + 1 );
136 root_beta = + ( score_max_eval + 1 );
140 for ( niterations = 1; niterations <= max_iterations; niterations++ )
142 Out( "\n Iteration %03d\n", niterations );
144 iret = record_open( &record, "records.csa", mode_read, NULL, NULL );
145 if ( iret < 0 ) { break; }
147 pf_tmp = file_open( "tmp.bin", "wb" );
148 if ( pf_tmp == NULL )
150 record_close( &record );
155 iret = learn_parse1( ptree, pbook_entry, pf_tmp, &record, max_games,
156 &target_out_window, &obj_norm, nworker1 );
160 record_close( &record );
161 file_close( pf_tmp );
165 iret = file_close( pf_tmp );
168 record_close( &record );
172 pf_tmp = file_open( "tmp.bin", "rb" );
173 if ( pf_tmp == NULL )
175 record_close( &record );
180 iret = learn_parse2( ptree, pf_tmp, nsteps, target_out_window, obj_norm,
184 file_close( pf_tmp );
185 record_close( &record );
189 iret = file_close( pf_tmp );
192 record_close( &record );
196 iret = record_close( &record );
197 if ( iret < 0 ) { break; }
199 if ( ! ( game_status & flag_learning ) )
201 out_warning( "flag_learning is not set." );
205 memory_free( pbook_entry );
206 game_status &= ~flag_learning;
213 learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry, FILE *pf_tmp,
214 record_t *precord, unsigned int max_games,
215 double *ptarget_out_window, double *pobj_norm, int nworker )
217 parse1_data_t *pdata[ TLP_MAX_THREADS ];
220 ini_book( pbook_entry );
222 for ( id = 0; id < nworker; id++ )
224 pdata[id] = memory_alloc( sizeof(parse1_data_t) );
225 if ( pdata[id] == NULL ) { return -1; }
227 pdata[id]->ptree = NULL;
228 pdata[id]->pbook_entry = pbook_entry;
229 pdata[id]->pf_tmp = pf_tmp;
230 pdata[id]->precord = precord;
231 pdata[id]->max_games = max_games;
233 pdata[id]->nworker = nworker;
238 for ( id = 1; id < nworker; id++ )
241 pdata[id]->ptree = tlp_atree_work + id;
242 if ( ! _beginthreadex( 0, 0, parse1_worker, pdata[id], 0, 0 ) )
244 str_error = "_beginthreadex() failed.";
250 pdata[id]->ptree = tlp_atree_work + id;
251 if ( pthread_create( &pt, &pthread_attr, parse1_worker, pdata[id] ) )
253 str_error = "pthread_create() failed.";
260 pdata[0]->ptree = ptree;
261 parse1_worker( pdata[0] );
264 while ( tlp_num ) { tlp_yield(); }
267 for ( id = 0; id < nworker; id++ )
269 if ( pdata[id]->info < 0 ) { return -1; }
272 for ( id = 1; id < nworker; id++ )
274 for ( i = 0; i < NUM_RESULT; i++ )
276 pdata[0]->result[i] += pdata[id]->result[i];
278 pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
279 pdata[0]->num_moves += pdata[id]->num_moves;
280 pdata[0]->num_nodes += pdata[id]->num_nodes;
281 pdata[0]->result_norm += pdata[id]->result_norm;
282 pdata[0]->target += pdata[id]->target;
283 pdata[0]->target_out_window += pdata[id]->target_out_window;
284 pdata[0]->illegal_moves += pdata[id]->illegal_moves;
285 if ( pdata[0]->max_pos_buf < pdata[id]->max_pos_buf )
287 pdata[0]->max_pos_buf = pdata[id]->max_pos_buf;
290 if ( pdata[0]->result_norm == 0 ) { pdata[0]->result_norm = 1; }
291 if ( pdata[0]->num_moves == 0 ) { pdata[0]->num_moves = 1; }
292 *ptarget_out_window = pdata[0]->target_out_window;
293 *pobj_norm = (double)pdata[0]->num_moves;
297 int misc, drop, cap, mt, misc_king, cap_king;
300 Out( " Number of Games : %u\n", precord->games );
301 Out( " Total Moves : %"PRIu64"\n",pdata[0]->num_moves );
302 Out( " Moves Counted : %"PRIu64"\n",pdata[0]->num_moves_counted);
303 Out( " Illegal Moves : %u\n", pdata[0]->illegal_moves );
304 Out( " Nodes Searched : %"PRIu64"\n",pdata[0]->num_nodes );
305 Out( " Max pos_buf : %x\n", pdata[0]->max_pos_buf );
306 Out( " Prediction (%) :" );
307 for ( i = 0, dtemp = 0.0; i < NUM_RESULT; i++ )
309 dtemp += (double)pdata[0]->result[i] * 100.0;
310 Out( " %4.2f", dtemp / (double)pdata[0]->result_norm );
314 pdata[0]->target /= *pobj_norm;
315 dtemp = *ptarget_out_window / *pobj_norm;
316 Out( " Target : %f (%f)\n", pdata[0]->target, dtemp );
322 misc_king = fmg_misc_king / 2;
323 cap_king = fmg_cap_king / 2;
324 Out( " Futility : misc=%d drop=%d cap=%d mt=%d misc(k)=%d "
325 "cap(k)=%d\n", misc, drop, cap, mt, misc_king, cap_king );
328 for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
334 # if defined(_MSC_VER)
335 static unsigned int __stdcall parse1_worker( void *arg )
337 static void *parse1_worker( void *arg )
340 parse1_data_t *pdata;
342 unsigned int record_move;
346 pdata = (parse1_data_t *)arg;
347 ptree = pdata->ptree;
349 for ( i = 0; i < NUM_RESULT; i++ ) { pdata->result[i] = 0; }
350 pdata->num_moves_counted = 0;
351 pdata->num_moves = 0;
352 pdata->num_nodes = 0;
353 pdata->max_pos_buf = 0;
354 pdata->result_norm = 0;
355 pdata->record_length = 0;
356 pdata->illegal_moves = 0;
359 pdata->target_out_window = 0.0;
364 for ( imove = 0; imove < (int)pdata->record_length; imove++ )
366 record_move = pdata->record_moves[imove];
368 pdata->buf[ pdata->pos_buf++ ] = Move2S(record_move);
370 if ( record_move & MOVE_VOID ) { record_move &= ~MOVE_VOID; }
371 else { make_pv( pdata, record_move ); }
373 pdata->buf[ pdata->pos_buf++ ] = 0;
375 MakeMove( pdata->root_turn, record_move, 1 );
376 pdata->root_turn = Flip( pdata->root_turn );
377 ptree->move_last[1] = ptree->move_last[0];
378 ptree->nsuc_check[0] = 0;
380 = (unsigned char)( InCheck( pdata->root_turn ) ? 1U : 0 );
388 if ( pdata->record_length )
390 if ( pdata->pos_buf > pdata->max_pos_buf )
392 pdata->max_pos_buf = pdata->pos_buf;
394 pdata->buf[0] = (unsigned short)( pdata->pos_buf / 0x10000U );
395 pdata->buf[1] = (unsigned short)( pdata->pos_buf % 0x10000U );
397 if ( fwrite( pdata->buf, sizeof(unsigned short), pdata->pos_buf,
398 pdata->pf_tmp ) != pdata->pos_buf )
400 str_error = str_io_error;
406 while ( iret >= 0 ) {
407 iret = read_game( pdata );
408 if ( iret == 1 ) { break; } /* end of record */
409 if ( pdata->record_length ) { break; } /* read a record */
416 if ( iret < 0 ) { break; }
417 if ( iret == 1 ) { break; }
432 make_pv( parse1_data_t *pdata, unsigned int record_move )
437 unsigned int move, pos_buf;
438 int i, imove, record_value, nth, nc, nmove_legal;
439 int value, alpha, beta, depth, ply, tt, new_depth;
441 record_value = INT_MIN;
444 depth = PLY_INC * SEARCH_DEPTH + PLY_INC / 2;
445 tt = Flip(pdata->root_turn);
446 pos_buf = pdata->pos_buf;
447 ptree = pdata->ptree;
448 ptree->node_searched = 0;
449 ptree->save_eval[0] = INT_MAX;
450 ptree->save_eval[1] = INT_MAX;
452 ptree->tlp_abort = 0;
454 for ( ply = 0; ply < PLY_MAX; ply++ )
456 ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2 = 0U;
457 ptree->killers[ply].no1 = ptree->killers[ply].no2 = 0U;
459 for ( i = 0; i < (int)HIST_SIZE; i++ )
461 ptree->hist_good[i] /= 256U;
462 ptree->hist_tried[i] /= 256U;
464 evaluate( ptree, 1, pdata->root_turn );
466 pmove = GenCaptures ( pdata->root_turn, pdata->amove_legal );
467 pmove = GenNoCaptures ( pdata->root_turn, pmove );
468 pmove = GenDrop ( pdata->root_turn, pmove );
469 pmove = GenCapNoProEx2 ( pdata->root_turn, pmove );
470 pmove = GenNoCapNoProEx2( pdata->root_turn, pmove );
471 nmove_legal = (int)( pmove - pdata->amove_legal );
473 for ( i = 0; pdata->amove_legal[i] != record_move; i++ );
474 move = pdata->amove_legal[0];
475 pdata->amove_legal[0] = pdata->amove_legal[i];
476 pdata->amove_legal[i] = move;
478 for ( imove = 0; imove < nmove_legal; imove++ ) {
480 move = pdata->amove_legal[imove];
481 ptree->current_move[1] = move;
484 alpha = record_value - FV_WINDOW;
485 beta = record_value + FV_WINDOW;
486 if ( alpha < root_alpha ) { alpha = root_alpha; }
487 if ( beta > root_beta ) { beta = root_beta; }
494 MakeMove( pdata->root_turn, move, 1 );
495 if ( InCheck(pdata->root_turn) )
497 UnMakeMove( pdata->root_turn, move, 1 );
503 new_depth = depth + PLY_INC;
504 ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
508 ptree->nsuc_check[2] = 0;
511 ptree->current_move[1] = move;
512 ptree->pv[1].type = no_rep;
514 value = -search( ptree, -beta, -alpha, tt, new_depth, 2,
515 node_do_mate | node_do_null | node_do_futile
516 | node_do_recap | node_do_recursion | node_do_hashcut );
518 UnMakeMove( pdata->root_turn, move, 1 );
520 if ( abs(value) > score_mate1ply )
522 out_warning( "value is larger than mate1ply!" );
527 func_value = func( value - record_value );
528 pdata->target += func_value;
529 pdata->num_moves += 1U;
530 if ( alpha < value && value < beta )
534 else { pdata->target_out_window += func_value; }
535 if ( value >= record_value ) { nth += 1; }
537 else if ( alpha < value && value < beta )
540 record_value = value;
542 else { break; } /* record move failed high or low. */
544 if ( alpha < value && value < beta )
546 pdata->buf[ pos_buf++ ] = Move2S(move);
547 for ( ply = 2; ply <= ptree->pv[1].length; ply++ )
549 pdata->buf[ pos_buf++ ] = Move2S(ptree->pv[1].a[ply]);
551 pdata->buf[ pos_buf - 1 ] |= 0x8000U;
557 pdata->result_norm += 1;
558 if ( nth-1 < NUM_RESULT ) { pdata->result[nth-1] += 1; }
563 pdata->pos_buf = pos_buf;
564 pdata->num_moves_counted += nc;
566 pdata->num_nodes += ptree->node_searched;
571 read_game( parse1_data_t *pdata )
575 unsigned int record_move;
576 int istatus, iret, imove;
580 if ( pdata->precord->games == pdata->max_games ) { return 1; }
582 if ( pdata->precord->games == 0 ) { Out( " Parse 1 " ); }
584 if ( ! ( (pdata->precord->games+1) % DOT_INTERVAL ) )
586 if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 10 ) ) )
589 if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 50 ) ) )
591 Out( "%7d\n ", pdata->precord->games+1 );
597 for ( imove = 0; imove < MAX_RECORD_LENGTH; imove++ )
599 istatus = in_CSA( ptree, pdata->precord, &record_move,
600 flag_nomake_move | flag_detect_hang | flag_nofmargin );
603 pdata->illegal_moves += 1;
606 if ( istatus >= record_eof ) { break; }
609 && ( root_turn != min_posi_no_handicap.turn_to_move
610 || HAND_B != min_posi_no_handicap.hand_black
611 || HAND_W != min_posi_no_handicap.hand_white
612 || memcmp( BOARD, min_posi_no_handicap.asquare, nsquare ) ) )
619 *(pdata->ptree) = *ptree;
620 pdata->root_turn = root_turn;
623 if ( rep_check_learn( ptree, 1 ) == four_fold_rep
624 || ( pdata->precord->moves < MAX_BOOK_PLY
625 && book_probe_learn( ptree, pdata->pbook_entry,
626 pdata->precord->moves, record_move ) ) )
628 pdata->record_moves[ imove ] = record_move | MOVE_VOID;
630 else { pdata->record_moves[ imove ] = record_move; }
632 iret = make_move_root( ptree, record_move, 0 );
633 if ( iret < 0 ) { return iret; }
636 if ( istatus != record_next && istatus != record_eof )
638 istatus = record_wind( pdata->precord );
639 if ( istatus < 0 ) { return istatus; }
642 if ( ! imove && istatus == record_eof ) { return 1; }
643 pdata->record_length = imove;
650 learn_parse2( tree_t * restrict ptree, FILE *pf_tmp, int nsteps,
651 double target_out_window, double obj_norm, int nworker )
653 parse2_data_t *pdata[ TLP_MAX_THREADS ];
656 for ( id = 0; id < nworker; id++ )
658 pdata[id] = memory_alloc( sizeof(parse2_data_t) );
659 if ( pdata[id] == NULL ) { return -1; }
661 pdata[id]->ptree = NULL;
662 pdata[id]->pf_tmp = pf_tmp;
664 pdata[id]->nworker = nworker;
674 for ( id = 1; id < nworker; id++ )
677 pdata[id]->ptree = tlp_atree_work + id;
678 if ( ! _beginthreadex( 0, 0, parse2_worker, pdata[id], 0, 0 ) )
680 str_error = "_beginthreadex() failed.";
686 pdata[id]->ptree = tlp_atree_work + id;
687 if ( pthread_create( &pt, &pthread_attr, parse2_worker, pdata[id] ) )
689 str_error = "pthread_create() failed.";
696 pdata[0]->ptree = ptree;
697 parse2_worker( pdata[0] );
700 while ( tlp_num ) { tlp_yield(); }
703 for ( id = 0; id < nworker; id++ )
705 if ( pdata[id]->info < 0 ) { return -1; }
708 for ( id = 1; id < nworker; id++ )
710 add_param( &pdata[0]->param, &pdata[id]->param );
711 pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
712 pdata[0]->target += pdata[id]->target;
717 double target, penalty, objective_function;
719 penalty = calc_penalty() / obj_norm;
720 target = ( pdata[0]->target + target_out_window ) / obj_norm;
721 objective_function = target + penalty;
722 Out( " Moves Counted : %d\n", pdata[0]->num_moves_counted );
723 Out( " Objective Func. : %.8f %.8f %.8f\n",
724 objective_function, target, penalty );
728 param_sym( &pdata[0]->param );
730 renovate_param( &pdata[0]->param );
732 if ( istep < nsteps ) { Out( "." ); }
739 for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
745 # if defined(_MSC_VER)
746 static unsigned int __stdcall parse2_worker( void *arg )
748 static void *parse2_worker( void *arg )
751 parse2_data_t *pdata;
753 unsigned int record_move;
754 int iret, imove, nbuf, pos_buf, turn;
757 pdata = (parse2_data_t *)arg;
758 ptree = pdata->ptree;
760 pdata->num_moves_counted = 0;
763 ini_param( &pdata->param );
769 iret = read_buf( pdata->buf, pdata->pf_tmp );
774 if ( iret <= 0 ) { break; } /* 0: eof, -2: error */
777 iret = ini_game( ptree, &min_posi_no_handicap, flag_nofmargin,
779 if ( iret < 0 ) { break; }
783 for ( imove = 0; pos_buf < nbuf; imove++ )
785 record_move = s2move( ptree, pdata->buf[pos_buf++], turn );
787 if ( pdata->buf[pos_buf] )
789 pos_buf = calc_deriv( pdata, pos_buf, turn );
793 MakeMove( turn, record_move, 1 );
795 ptree->move_last[1] = ptree->move_last[0];
796 ptree->nsuc_check[0] = 0;
797 ptree->nsuc_check[1] = (unsigned char)( InCheck( turn ) ? 1U : 0 );
813 read_buf( unsigned short *buf, FILE *pf )
817 size = fread( buf, sizeof(unsigned short), 2, pf );
818 if ( ! size && feof( pf ) ) { return 0; }
821 str_error = str_io_error;
825 size = (size_t)buf[1] + (size_t)buf[0] * 0x10000 - 2;
826 if ( fread( buf+2, sizeof(unsigned short), size, pf ) != size )
828 str_error = str_io_error;
837 calc_deriv( parse2_data_t *pdata, int pos0, int turn0 )
839 double target, dT, sum_dT;
840 tree_t * restrict ptree;
841 const unsigned short *buf;
843 int ply, turn, pv_length, pos, record_value, value;
845 ptree = pdata->ptree;
855 pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
856 MakeMove( turn, pdata->pv[ply], ply );
858 if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
863 record_value = evaluate( ptree, ply+1, turn );
864 if ( turn != turn0 ) { record_value = -record_value; }
868 UnMakeMove( turn, pdata->pv[ply], ply );
869 if ( ply == 1 ) { break; }
874 while ( buf[ pos ] ) {
877 pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
878 MakeMove( turn, pdata->pv[ply], ply );
880 if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
885 value = evaluate( ptree, ply+1, turn );
886 if ( turn != turn0 ) { value = -value; }
887 target += func( value - record_value );
889 dT = dfunc( value - record_value );
890 if ( turn0 ) { dT = -dT; }
892 inc_param( ptree, &pdata->param, -dT );
896 UnMakeMove( turn, pdata->pv[ply], ply );
897 if ( ply == 1 ) { break; }
907 pdata->pv[ply] = s2move( ptree, buf[ pos0+ply-1 ] & 0x7fffU, turn );
908 MakeMove( turn, pdata->pv[ply], ply );
910 if ( buf[ pos0+ply-1 ] & 0x8000U ) { break; }
914 inc_param( ptree, &pdata->param, sum_dT );
918 UnMakeMove( turn, pdata->pv[ply], ply );
919 if ( ply == 1 ) { break; }
923 pdata->num_moves_counted += nc;
924 pdata->target += target;
933 const double delta = (double)FV_WINDOW / 7.0;
936 if ( x < -FV_WINDOW ) { x = -FV_WINDOW; }
937 else if ( x > FV_WINDOW ) { x = FV_WINDOW; }
938 d = 1.0 / ( 1.0 + exp(-x/delta) );
947 const double delta = (double)FV_WINDOW / 7.0;
948 double dd, dn, dtemp, dret;
950 if ( x <= -FV_WINDOW ) { dret = 0.0; }
951 else if ( x >= FV_WINDOW ) { dret = 0.0; }
953 dn = exp( - x / delta );
955 dd = delta * dtemp * dtemp;
964 s2move( const tree_t * restrict ptree, unsigned int move, int tt )
969 if ( from < nsquare )
972 move |= tt ? (Piece2Move(-BOARD[from])|Cap2Move( BOARD[to]))
973 : (Piece2Move( BOARD[from])|Cap2Move(-BOARD[to]));
980 ini_book( book_entry_t *pbook_entry )
984 for ( i = 0; i < NumBookEntry; i++ )
985 for ( j = 0; j < NumBookCluster; j++ ) {
986 pbook_entry[i].cluster[j].a = (uint64_t)0;
987 pbook_entry[i].cluster[j].b = (uint64_t)0x1ffU << 41;
1001 book_probe_learn( const tree_t * restrict ptree,
1002 book_entry_t *pbook_entry,
1003 int ply, unsigned int move )
1010 + ((unsigned int)HASH_KEY & (unsigned int)(NumBookEntry-1));
1012 for ( i = 0; i < NumBookCluster; i++ )
1013 if ( p->cluster[i].a == HASH_KEY
1014 && ((unsigned int)p->cluster[i].b & 0x1fffffU) == HAND_B
1015 && ( (((unsigned int)p->cluster[i].b>>21) & 0x1U)
1016 == (unsigned int)root_turn )
1017 && ((unsigned int)(p->cluster[i].b>>22) & 0x7ffffU) == move ) {
1021 for ( i = 0; i < NumBookCluster; i++ )
1022 if ( ( (unsigned int)( p->cluster[i].b >> 41 ) & 0x1ffU )
1023 > (unsigned int)ply ) { break; }
1025 if ( i < NumBookCluster ) {
1026 for ( j = NumBookCluster-1; j > i; j-- ) {
1027 p->cluster[j].a = p->cluster[j-1].a;
1028 p->cluster[j].b = p->cluster[j-1].b;
1031 p->cluster[i].a = HASH_KEY;
1033 = ( (uint64_t)move<<22 ) | ( (uint64_t)ply << 41 )
1034 | (uint64_t)( (root_turn<<21) | HAND_B );
1042 rep_check_learn( tree_t * restrict ptree, int ply )
1046 n = ptree->nrep + ply - 1;
1047 imin = n - REP_MAX_PLY;
1048 if ( imin < 0 ) { imin = 0; }
1050 for ( i = n-2; i >= imin; i -= 2 )
1051 if ( ptree->rep_board_list[i] == HASH_KEY
1052 && ptree->rep_hand_list[i] == HAND_B ) { return four_fold_rep; }
1057 #endif /* no MINIMUM */