static int CheckExtend(struct Position *p) { int kp = p->kingSq[p->turn]; BitBoard att; att = p->atkFr[kp] & p->mask[OPP(p->turn)][0]; if (CountBits(att) > 1) { /* * double check, the king has to move * count no. of flight squares, if only one, extend deeper * */ BitBoard ff; int i; int cnt = 0; DblExt++; ff = KingEPM[kp] & ~p->mask[p->turn][0]; att &= p->slidingPieces; while (att) { i=FindSetBit(att); ClrBit(att, i); ff &= ~Ray[i][kp]; } while (ff) { i=FindSetBit(ff); ClrBit(ff, i); if (!(p->atkFr[i] & p->mask[OPP(p->turn)][0])) cnt++; if (cnt > 1) return ExtendDoubleCheck; } } else { BitBoard ff; BitBoard def; BitBoard tmp; int atp = FindSetBit(att); int cnt = 0; int i; int nd = 0; /* discovered check */ if (atp != M_TO((p->actLog-1)->gl_Move)) { DiscExt++; nd = ExtendDiscoveredCheck; } ff = KingEPM[kp] & ~p->mask[p->turn][0]; i = FindSetBit(att); if (Sliding[TYPE(p->piece[i])]) ff &= ~Ray[i][kp]; /* check for king flight squares */ while (ff) { i=FindSetBit(ff); ClrBit(ff, i); if (!(p->atkFr[i] & p->mask[OPP(p->turn)][0])) cnt++; if (cnt > 1) return nd; } /* Find all non-pinned defenders */ def = p->mask[p->turn][0] & ~p->mask[p->turn][King]; tmp = (p->mask[OPP(p->turn)][Bishop] | p->mask[OPP(p->turn)][Queen]) & BishopEPM[kp]; while (tmp) { BitBoard tmp2; i=FindSetBit(tmp); ClrBit(tmp, i); tmp2= InterPath[i][kp]; if (tmp2 && !(p->mask[OPP(p->turn)][0] & tmp2)) { tmp2 &= p->mask[p->turn][0]; if (CountBits(tmp2) == 1) { ClrBit(def, FindSetBit(tmp2)); } } } tmp = (p->mask[OPP(p->turn)][Rook] | p->mask[OPP(p->turn)][Queen]) & RookEPM[kp]; while (tmp) { BitBoard tmp2; i=FindSetBit(tmp); ClrBit(tmp, i); tmp2= InterPath[i][kp]; if (tmp2 && !(p->mask[OPP(p->turn)][0] & tmp2)) { tmp2 &= p->mask[p->turn][0]; if (CountBits(tmp2) == 1) { ClrBit(def, FindSetBit(tmp2)); } } } /* All non-pinned defenders are in 'def' */ tmp = p->atkFr[atp] & def; cnt += CountBits(tmp); if (cnt > 1) return nd; /* if possible, try an interposition */ if (Sliding[TYPE(p->piece[atp])]) { tmp = InterPath[atp][kp]; while (tmp) { BitBoard tmp2; i=FindSetBit(tmp); ClrBit(tmp, i); if ((tmp2 = p->atkFr[i] & def)) { cnt+=CountBits(tmp2); } if (p->turn == White && (i-8) > 0 && TstBit(p->mask[White][Pawn], i-8) && TstBit(def, i-8)) cnt++; if (p->turn == Black && (i+8) < 64 && TstBit(p->mask[Black][Pawn], i+8) && TstBit(def, i+8)) cnt++; if (cnt > 1) return nd; } } } /* If we get here, we have only one legal move. */ SingExt++; return ExtendSingularReply; }
static int quies(struct SearchData *sd, int alpha, int beta, int depth) { struct Position *p = sd->position; int best; int move; int talpha; int tmp; QNodes++; EnterNode(sd); /* max search depth reached */ if (sd->ply >= MaxDepth || Repeated(p, FALSE)) { best = 0; goto EXIT; } /* * Probe recognizers. If the probe is successful, use the * recognizer score as evaluation score. * * Otherwise, use ScorePosition() */ switch (ProbeRecognizer(p, &tmp)) { case ExactScore: best = tmp; goto EXIT; case LowerBound: best = tmp; if (best >= beta) { goto EXIT; } break; case UpperBound: best = tmp; if (best <= alpha) { goto EXIT; } break; default: best = ScorePosition(p, alpha, beta); break; } if (best >= beta) { goto EXIT; } talpha = MAX(alpha, best); while ((move = NextMoveQ(sd, alpha) ) != M_NONE) { DoMove(p, move); if (InCheck(p, OPP(p->turn))) UndoMove(p, move); else { tmp = -quies(sd, -beta, -talpha, depth-1); UndoMove(p, move); if (tmp >= beta) { best = tmp; goto EXIT; } if (tmp > best) { best = tmp; if (best > talpha) { talpha = best; } } } } EXIT: LeaveNode(sd); return best; }
void perform_extended_solve( int side_to_move, int actual_move, int book, int exact_solve ) { int i; int mid, wld, exact; int best_move; int disc_diff, corrected_diff; EvaluatedMove temp; EvalResult res; /* Disable all time control mechanisms */ toggle_abort_check( FALSE ); toggle_midgame_abort_check( FALSE ); toggle_perturbation_usage( FALSE ); start_move( 0, 0, disc_count( BLACKSQ ) + disc_count( WHITESQ ) ); clear_ponder_times(); determine_hash_values( side_to_move, board ); reset_counter( &nodes ); /* Set search depths that result in Zebra solving after a brief midgame analysis */ mid = 60; wld = 60; if ( exact_solve ) exact = 60; else exact = 0; game_evaluated_count = 1; /* Calculate the score for the preferred move */ evaluated_list[0].side_to_move = side_to_move; evaluated_list[0].move = actual_move; evaluated_list[0].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); evaluated_list[0].pv_depth = 1; evaluated_list[0].pv[0] = actual_move; prefix_move = actual_move; negate_current_eval( TRUE ); (void) make_move( side_to_move, actual_move, TRUE ); (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, FALSE, book, mid - 1, exact - 1, wld - 1, TRUE, &evaluated_list[0].eval ); if ( evaluated_list[0].eval.type == PASS_EVAL ) { /* Don't allow pass */ (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, book, mid - 1, exact - 1, wld - 1, TRUE, &evaluated_list[0].eval ); if ( evaluated_list[0].eval.type == PASS_EVAL ) { /* Game has ended */ disc_diff = disc_count( side_to_move ) - disc_count( OPP( side_to_move ) ); if ( disc_diff > 0 ) { corrected_diff = 64 - 2 * disc_count( OPP( side_to_move) ); res = WON_POSITION; } else if ( disc_diff == 0 ) { corrected_diff = 0; res = DRAWN_POSITION; } else { corrected_diff = 2 * disc_count( side_to_move ) - 64; res = LOST_POSITION; } evaluated_list[0].eval = create_eval_info( EXACT_EVAL, res, 128 * corrected_diff, 0.0, 60 - disks_played, FALSE ); } } else { /* Sign-correct the score produced */ evaluated_list[0].eval.score = -evaluated_list[0].eval.score; if ( evaluated_list[0].eval.res == WON_POSITION ) evaluated_list[0].eval.res = LOST_POSITION; else if ( evaluated_list[0].eval.res == LOST_POSITION ) evaluated_list[0].eval.res = WON_POSITION; } if ( force_return ) evaluated_list[0].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); else { evaluated_list[0].pv_depth = pv_depth[0] + 1; evaluated_list[0].pv[0] = actual_move; for ( i = 0; i < pv_depth[0]; i++ ) evaluated_list[0].pv[i + 1] = pv[0][i]; } unmake_move( side_to_move, actual_move ); prefix_move = 0; negate_current_eval( FALSE ); max_depth_reached++; /* Compute the score for the best move and store it in the move list if it isn't ACTUAL_MOVE */ best_move = compute_move( side_to_move, FALSE, 0, 0, FALSE, book, mid, exact, wld, TRUE, &evaluated_list[1].eval ); if ( !force_return && (best_move != actual_move) ) { /* Move list will contain best move first and then the actual move */ game_evaluated_count = 2; evaluated_list[1].side_to_move = side_to_move; evaluated_list[1].move = best_move; evaluated_list[1].pv_depth = pv_depth[0]; for ( i = 0; i < pv_depth[0]; i++ ) evaluated_list[1].pv[i] = pv[0][i]; temp = evaluated_list[0]; evaluated_list[0] = evaluated_list[1]; evaluated_list[1] = temp; } /* The PV and current eval should when correspond to the best move when leaving */ pv_depth[0] = evaluated_list[0].pv_depth; for ( i = 0; i < pv_depth[0]; i++ ) pv[0][i] = evaluated_list[0].pv[i]; set_current_eval( evaluated_list[0].eval ); /* Don't forget to enable the time control mechanisms when leaving */ toggle_abort_check( TRUE ); toggle_midgame_abort_check( TRUE ); toggle_perturbation_usage( FALSE ); }
int extended_compute_move( int side_to_move, int book_only, int book, int mid, int exact, int wld ) { int i, j; int index; int changed; int this_move; int disc_diff, corrected_diff; int best_move, temp_move; int best_score; int best_pv_depth; int stored_echo; int shallow_eval; int empties; int current_mid, current_exact, current_wld; int first_iteration; int unsearched; int unsearched_count; int unsearched_move[61]; int best_pv[60]; unsigned int transform1[60], transform2[60]; CandidateMove book_move; EvaluatedMove temp; EvaluationType book_eval_info; EvalResult res; /* Disable all time control mechanisms and randomization */ toggle_abort_check( FALSE ); toggle_midgame_abort_check( FALSE ); toggle_perturbation_usage( FALSE ); start_move( 0, 0, disc_count( BLACKSQ ) + disc_count( WHITESQ ) ); clear_ponder_times(); determine_hash_values( side_to_move, board ); empties = 60 - disks_played; best_move = 0; game_evaluated_count = 0; reset_counter( &nodes ); generate_all( side_to_move ); if ( book_only || book ) { /* Evaluations for database moves */ int flags = 0; if ( empties <= exact ) flags = FULL_SOLVED; else if ( empties <= wld ) flags = WLD_SOLVED; fill_move_alternatives( side_to_move, flags ); game_evaluated_count = get_candidate_count(); for ( i = 0; i < game_evaluated_count; i++ ) { int child_flags; book_move = get_candidate( i ); evaluated_list[i].side_to_move = side_to_move; evaluated_list[i].move = book_move.move; evaluated_list[i].pv_depth = 1; evaluated_list[i].pv[0] = book_move.move; evaluated_list[i].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, book_move.score, 0.0, 0, TRUE ); child_flags = book_move.flags & book_move.parent_flags; if ( child_flags & (FULL_SOLVED | WLD_SOLVED) ) { if ( child_flags & FULL_SOLVED ) evaluated_list[i].eval.type = EXACT_EVAL; else evaluated_list[i].eval.type = WLD_EVAL; if ( book_move.score > 0 ) { evaluated_list[i].eval.res = WON_POSITION; /* Normalize the scores so that e.g. 33-31 becomes +256 */ evaluated_list[i].eval.score -= CONFIRMED_WIN; evaluated_list[i].eval.score *= 128; } else if ( book_move.score == 0 ) evaluated_list[i].eval.res = DRAWN_POSITION; else { /* score < 0 */ evaluated_list[i].eval.res = LOST_POSITION; /* Normalize the scores so that e.g. 30-34 becomes -512 */ evaluated_list[i].eval.score += CONFIRMED_WIN; evaluated_list[i].eval.score *= 128; } } else evaluated_list[i].eval.type = MIDGAME_EVAL; } } if ( book_only ) { /* Only book moves are to be considered */ if ( game_evaluated_count > 0 ) { best_move = get_book_move( side_to_move, FALSE, &book_eval_info ); set_current_eval( book_eval_info ); } else { pv_depth[0] = 0; best_move = PASS; book_eval_info = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); set_current_eval( book_eval_info ); } } else { /* Make searches for moves not in the database */ int shallow_depth; int empties = 60 - disks_played; book = FALSE; best_score = -INFINITE_EVAL; if ( game_evaluated_count > 0 ) { /* Book PV available */ best_score = evaluated_list[0].eval.score; best_move = evaluated_list[0].move; } negate_current_eval( TRUE ); /* Store the available moves, clear their evaluations and sort them on shallow evaluation. */ if ( empties < 12 ) shallow_depth = 1; else { int max_depth = MAX( mid, MAX( exact, wld ) ); if ( max_depth >= 16 ) shallow_depth = 6; else shallow_depth = 4; } unsearched_count = 0; for ( i = 0; i < move_count[disks_played]; i++ ) { this_move = move_list[disks_played][i]; unsearched = TRUE; for ( j = 0; j < game_evaluated_count; j++ ) if ( evaluated_list[j].move == this_move ) unsearched = FALSE; if ( !unsearched ) continue; unsearched_move[unsearched_count] = this_move; unsearched_count++; (void) make_move( side_to_move, this_move, TRUE ); if ( shallow_depth == 1 ) /* Compute move doesn't allow depth 0 */ shallow_eval = -static_evaluation( OPP( side_to_move ) ); else { EvaluationType shallow_info; (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, FALSE, book, shallow_depth - 1, 0, 0, TRUE, &shallow_info ); if ( shallow_info.type == PASS_EVAL ) { /* Don't allow pass */ (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, book, shallow_depth - 1, 0, 0, TRUE, &shallow_info ); if ( shallow_info.type == PASS_EVAL ) { /* Game over */ disc_diff = disc_count( side_to_move ) - disc_count( OPP( side_to_move ) ); if ( disc_diff > 0 ) corrected_diff = 64 - 2 * disc_count( OPP( side_to_move) ); else if ( disc_diff == 0 ) corrected_diff = 0; else corrected_diff = 2 * disc_count( side_to_move ) - 64; shallow_eval = 128 * corrected_diff; } else shallow_eval = shallow_info.score; } else /* Sign-correct the score produced */ shallow_eval = -shallow_info.score; } unmake_move( side_to_move, this_move ); evals[disks_played][this_move] = shallow_eval; } do { changed = FALSE; for ( i = 0; i < unsearched_count - 1; i++ ) if ( evals[disks_played][unsearched_move[i]] < evals[disks_played][unsearched_move[i + 1]] ) { temp_move = unsearched_move[i]; unsearched_move[i] = unsearched_move[i + 1]; unsearched_move[i + 1] = temp_move; changed = TRUE; } } while ( changed ); /* Initialize the entire list as being empty */ for ( i = 0, index = game_evaluated_count; i < unsearched_count; i++, index++ ) { evaluated_list[index].side_to_move = side_to_move; evaluated_list[index].move = unsearched_move[i]; evaluated_list[index].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); evaluated_list[index].pv_depth = 1; evaluated_list[index].pv[0] = unsearched_move[i]; if ( empties > MAX( wld, exact ) ) { transform1[i] = abs( my_random() ); transform2[i] = abs( my_random() ); } else { transform1[i] = 0; transform2[i] = 0; } } stored_echo = echo; echo = FALSE; best_pv_depth = 0; if ( mid == 1 ) { /* compute_move won't be called */ pv_depth[0] = 0; piece_count[BLACKSQ][disks_played] = disc_count( BLACKSQ ); piece_count[WHITESQ][disks_played] = disc_count( WHITESQ ); } /* Perform iterative deepening if the search depth is large enough */ #define ID_STEP 2 if ( exact > empties ) exact = empties; if ( (exact < 12) || (empties > exact) ) current_exact = exact; else current_exact = (8 + (exact % 2)) - ID_STEP; if ( wld > empties ) wld = empties; if ( (wld < 14) || (empties > wld) ) current_wld = wld; else current_wld = (10 + (wld % 2)) - ID_STEP; if ( ((empties == exact) || (empties == wld)) && (empties > 16) && (mid < empties - 12) ) mid = empties - 12; if ( mid < 10 ) current_mid = mid; else current_mid = (6 + (mid % 2)) - ID_STEP; first_iteration = TRUE; do { if ( current_mid < mid ) { current_mid += ID_STEP; /* Avoid performing deep midgame searches if the endgame is reached anyway. */ if ( (empties <= wld) && (current_mid + 7 >= empties) ) { current_wld = wld; current_mid = mid; } if ( (empties <= exact) && (current_mid + 7 >= empties) ) { current_exact = exact; current_mid = mid; } } else if ( current_wld < wld ) current_wld = wld; else current_exact = exact; for ( i = 0; (i < unsearched_count) && !force_return; i++ ) { EvaluationType this_eval; this_move = unsearched_move[i]; /* Locate the current move in the list. This has to be done because the moves might have been reordered during the iterative deepening. */ index = 0; while ( evaluated_list[index].move != this_move ) index++; /* To avoid strange effects when browsing back and forth through a game during the midgame, rehash the hash transformation masks for each move unless the endgame is reached */ set_hash_transformation( transform1[i], transform2[i] ); /* Determine the score for the ith move */ prefix_move = this_move; (void) make_move( side_to_move, this_move, TRUE ); if ( current_mid == 1 ) { /* compute_move doesn't like 0-ply searches */ shallow_eval = static_evaluation( OPP( side_to_move ) ); this_eval = create_eval_info( MIDGAME_EVAL, UNSOLVED_POSITION, shallow_eval, 0.0, 0, FALSE ); } else (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, FALSE, book, current_mid - 1, current_exact - 1, current_wld - 1, TRUE, &this_eval ); if ( force_return ) { /* Clear eval and exit search immediately */ this_eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); unmake_move( side_to_move, this_move ); break; } if ( this_eval.type == PASS_EVAL ) { /* Don't allow pass */ if ( current_mid == 1 ) { /* compute_move doesn't like 0-ply searches */ shallow_eval = static_evaluation( side_to_move ); this_eval = create_eval_info( MIDGAME_EVAL, UNSOLVED_POSITION, shallow_eval, 0.0, 0, FALSE ); } else (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, book, current_mid - 1, current_exact - 1, current_wld - 1, TRUE, &this_eval ); if ( this_eval.type == PASS_EVAL ) { /* Game over */ disc_diff = disc_count( side_to_move ) - disc_count( OPP( side_to_move ) ); if ( disc_diff > 0 ) { corrected_diff = 64 - 2 * disc_count( OPP( side_to_move) ); res = WON_POSITION; } else if ( disc_diff == 0 ) { corrected_diff = 0; res = DRAWN_POSITION; } else { corrected_diff = 2 * disc_count( side_to_move ) - 64; res = LOST_POSITION; } this_eval = create_eval_info( EXACT_EVAL, res, 128 * corrected_diff, 0.0, 60 - disks_played, FALSE ); } } else { /* Sign-correct the score produced */ this_eval.score = -this_eval.score; if ( this_eval.res == WON_POSITION ) this_eval.res = LOST_POSITION; else if ( this_eval.res == LOST_POSITION ) this_eval.res = WON_POSITION; } if ( force_return ) break; else evaluated_list[index].eval = this_eval; /* Store the PV corresponding to the move */ evaluated_list[index].pv_depth = pv_depth[0] + 1; evaluated_list[index].pv[0] = this_move; for ( j = 0; j < pv_depth[0]; j++ ) evaluated_list[index].pv[j + 1] = pv[0][j]; /* Store the PV corresponding to the best move */ if ( evaluated_list[index].eval.score > best_score ) { best_score = evaluated_list[index].eval.score; best_move = this_move; best_pv_depth = pv_depth[0]; for ( j = 0; j < best_pv_depth; j++ ) best_pv[j] = pv[0][j]; } unmake_move( side_to_move, this_move ); /* Sort the moves evaluated */ if ( first_iteration ) game_evaluated_count++; if ( !force_return ) do { changed = FALSE; for ( j = 0; j < game_evaluated_count - 1; j++ ) if ( compare_eval( evaluated_list[j].eval, evaluated_list[j + 1].eval ) < 0 ) { changed = TRUE; temp = evaluated_list[j]; evaluated_list[j] = evaluated_list[j + 1]; evaluated_list[j + 1] = temp; } } while ( changed ); display_status(stdout, FALSE); } first_iteration = FALSE; /* Reorder the moves after each iteration. Each move is moved to the front of the list, starting with the bad moves and ending with the best move. This ensures that unsearched_move will be sorted w.r.t. the order in evaluated_list. */ for ( i = game_evaluated_count - 1; i >= 0; i-- ) { int this_move = evaluated_list[i].move; j = 0; while ( (j != unsearched_count) && (unsearched_move[j] != this_move) ) j++; if ( j == unsearched_count ) /* Must be book move, skip */ continue; /* Move the move to the front of the list. */ while ( j >= 1 ) { unsearched_move[j] = unsearched_move[j - 1]; j--; } unsearched_move[0] = this_move; } } while ( !force_return && ((current_mid != mid) || (current_exact != exact) || (current_wld != wld)) ); echo = stored_echo; game_evaluated_count = move_count[disks_played]; /* Make sure that the PV and the score correspond to the best move */ pv_depth[0] = best_pv_depth + 1; pv[0][0] = best_move; for ( i = 0; i < best_pv_depth; i++ ) pv[0][i + 1] = best_pv[i]; negate_current_eval( FALSE ); if ( move_count[disks_played] > 0 ) set_current_eval( evaluated_list[0].eval ); } /* Reset the hash transformation masks prior to leaving */ set_hash_transformation( 0, 0 ); /* Don't forget to enable the time control mechanisms when leaving */ toggle_abort_check( TRUE ); toggle_midgame_abort_check( TRUE ); toggle_perturbation_usage( TRUE ); max_depth_reached++; prefix_move = 0; return best_move; }
void ponder_move( int side_to_move, int book, int mid, int exact, int wld ) { EvaluationType eval_info; HashEntry entry; double move_start_time, move_stop_time; int i, j; int this_move, hash_move; int expect_count; int stored_echo; int best_pv_depth; int expect_list[64]; int best_pv[61]; /* Disable all time control mechanisms as it's the opponent's time we're using */ toggle_abort_check( FALSE ); toggle_midgame_abort_check( FALSE ); start_move( 0, 0, disc_count( BLACKSQ ) + disc_count( WHITESQ ) ); clear_ponder_times(); determine_hash_values( side_to_move, board ); reset_counter( &nodes ); /* Find the scores for the moves available to the opponent. */ hash_move = 0; find_hash( &entry, ENDGAME_MODE ); if ( entry.draft != NO_HASH_MOVE ) hash_move = entry.move[0]; else { find_hash( &entry, MIDGAME_MODE ); if ( entry.draft != NO_HASH_MOVE ) hash_move = entry.move[0]; } stored_echo = echo; echo = FALSE; (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, FALSE, MIN( PONDER_DEPTH, mid ), 0, 0, FALSE, &eval_info ); echo = stored_echo; /* Sort the opponents on the score and push the table move (if any) to the front of the list */ if ( force_return ) expect_count = 0; else { sort_moves( move_count[disks_played] ); (void) float_move( hash_move, move_count[disks_played] ); expect_count = move_count[disks_played]; for ( i = 0; i < expect_count; i++ ) expect_list[i] = move_list[disks_played][i]; #if TEXT_BASED printf( "%s=%d\n", HASH_MOVE_TEXT, hash_move ); for ( i = 0; i < expect_count; i++ ) { printf( "%c%c %-6.2f ", TO_SQUARE( move_list[disks_played][i] ), evals[disks_played][move_list[disks_played][i]] / 128.0 ); if ( (i % 7 == 6) || (i == expect_count - 1) ) puts( "" ); } #endif } /* Go through the expected moves in order and prepare responses. */ best_pv_depth = 0; for ( i = 0; !force_return && (i < expect_count); i++ ) { move_start_time = get_real_timer(); set_ponder_move( expect_list[i] ); this_move = expect_list[i]; prefix_move = this_move; (void) make_move( side_to_move, this_move, TRUE ); (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, TRUE, FALSE, mid, exact, wld, FALSE, &eval_info ); unmake_move( side_to_move, this_move ); clear_ponder_move(); move_stop_time = get_real_timer(); add_ponder_time( expect_list[i], move_stop_time - move_start_time ); ponder_depth[expect_list[i]] = MAX( ponder_depth[expect_list[i]], max_depth_reached - 1 ); if ( (i == 0) && !force_return ) { /* Store the PV for the first move */ best_pv_depth = pv_depth[0]; for ( j = 0; j < pv_depth[0]; j++ ) best_pv[j] = pv[0][j]; } } /* Make sure the PV looks reasonable when leaving - either by clearing it altogether or, preferrably, using the stored PV for the first move if it is available. */ max_depth_reached++; prefix_move = 0; if ( best_pv_depth == 0 ) pv_depth[0] = 0; else { pv_depth[0] = best_pv_depth + 1; pv[0][0] = expect_list[0]; for ( i = 0; i < best_pv_depth; i++ ) pv[0][i + 1] = best_pv[i]; } /* Don't forget to enable the time control mechanisms when leaving */ toggle_abort_check( TRUE ); toggle_midgame_abort_check( TRUE ); }
JNIEXPORT void JNIFn(zebra, ZebraEngine, zePlay)(JNIEnv *env, jobject thiz, jint providedMoveCount, jbyteArray providedMoves) { EvaluationType eval_info; const char *black_name; const char *white_name; const char *opening_name; const char *op; double move_start, move_stop; int i; int side_to_move; int curr_move; int timed_search; int black_hash1, black_hash2, white_hash1, white_hash2; ui_event_t evt; int provided_move_count; int provided_move_index; int provided_move[65]; int silent = FALSE; int use_book = s_use_book; DROIDZEBRA_JNI_SETUP; force_exit = 0; if (skill[BLACKSQ] < 0 || skill[WHITESQ] < 0) { fatal_error("Set Player Info first"); } /* copy provided moves */ provided_move_index = 0; provided_move_count = 0; if (providedMoveCount > 0 && providedMoves) { jbyte *providedMovesJNI; provided_move_count = providedMoveCount; i = (*env)->GetArrayLength(env, providedMoves); if (provided_move_count > i) fatal_error("Provided move count is greater than array size %d>%d", provided_move_count, i); if (provided_move_count > 64) fatal_error("Provided move count is greater that 64: %d", provided_move_count); providedMovesJNI = (*env)->GetByteArrayElements(env, providedMoves, 0); if (!providedMovesJNI) fatal_error("failed to get provide moves (jni)"); for (i = 0; i < provided_move_count; i++) { provided_move[i] = providedMovesJNI[i]; } (*env)->ReleaseByteArrayElements(env, providedMoves, providedMovesJNI, 0); } /* Set up the position and the search engine */ game_init(NULL, &side_to_move); setup_hash(TRUE); clear_stored_game(); set_slack(floor(s_slack * 128.0)); set_perturbation(floor(s_perturbation * 128.0)); toggle_human_openings(s_human_opening); set_forced_opening(s_forced_opening_seq); opening_name = NULL; reset_book_search(); set_deviation_value(0, 0, 0.0); if (skill[BLACKSQ] == 0) black_name = "Player"; else black_name = "Zebra"; if (skill[WHITESQ] == 0) white_name = "Player"; else white_name = "Zebra"; set_names(black_name, white_name); set_move_list(black_moves, white_moves, score_sheet_row); set_evals(0.0, 0.0); for (i = 0; i < 60; i++) { black_moves[i] = PASS; white_moves[i] = PASS; } black_hash1 = my_random(); black_hash2 = my_random(); white_hash1 = my_random(); white_hash2 = my_random(); droidzebra_msg_game_start(); AGAIN: curr_move = PASS; while (game_in_progress() && !force_exit) { force_return = 0; silent = (provided_move_index < provided_move_count); droidzebra_enable_messaging(!silent); droidzebra_msg_move_start(side_to_move); remove_coeffs(disks_played); clear_evaluated(); if (SEPARATE_TABLES) { /* Computer players won't share hash tables */ if (side_to_move == BLACKSQ) { hash1 ^= black_hash1; hash2 ^= black_hash2; } else { hash1 ^= white_hash1; hash2 ^= white_hash2; } } generate_all(side_to_move); if (side_to_move == BLACKSQ) score_sheet_row++; // echo droidzebra_msg_candidate_moves(); set_move_list(black_moves, white_moves, score_sheet_row); set_times(floor(player_time[BLACKSQ]), floor(player_time[WHITESQ])); op = find_opening_name(); if (op != NULL && (!opening_name || strcmp(op, opening_name))) { opening_name = op; } droidzebra_msg_opening_name(opening_name); droidzebra_msg_last_move(disks_played > 0 ? get_stored_move(disks_played - 1) : PASS); display_board(stdout, board, side_to_move, TRUE, TRUE, TRUE); // echo if (move_count[disks_played] != 0) { move_start = get_real_timer(); clear_panic_abort(); if (provided_move_index >= provided_move_count) { if (skill[side_to_move] == 0) { curr_move = -1; if (auto_make_forced_moves && move_count[disks_played] == 1) { curr_move = move_list[disks_played][0]; } else { // compute evaluations if (s_practice_mode) { _droidzebra_compute_evals(side_to_move); if (force_exit) break; if (force_return) force_return = 0; // interrupted by user input } // wait for user event droidzebra_msg_get_user_input(side_to_move, &evt); if (evt.type == UI_EVENT_EXIT) { force_exit = 1; break; } else if (evt.type == UI_EVENT_MOVE) { curr_move = evt.evt_move.move; _droidzebra_undo_stack_clear(); // once player makes the move undo info is stale } else if (evt.type == UI_EVENT_UNDO) { _droidzebra_undo_turn(&side_to_move); // adjust for increment at the beginning of the game loop if (side_to_move == BLACKSQ) score_sheet_row--; continue; } else if (evt.type == UI_EVENT_REDO) { _droidzebra_redo_turn(&side_to_move); // adjust for increment at the beginning of the game loop if (side_to_move == BLACKSQ) score_sheet_row--; continue; } else if (evt.type == UI_EVENT_SETTINGS_CHANGE) { _droidzebra_on_settings_change(); // repeat move on settings change if (side_to_move == BLACKSQ) score_sheet_row--; // adjust for increment at the beginning of the game loop continue; } else { fatal_error("Unsupported UI event: %d", evt.type); } } assert(curr_move >= 0); } else { start_move(player_time[side_to_move], player_increment[side_to_move], disks_played + 4); determine_move_time(player_time[side_to_move], player_increment[side_to_move], disks_played + 4); timed_search = (skill[side_to_move] >= 60); toggle_experimental(FALSE); curr_move = compute_move(side_to_move, TRUE, player_time[side_to_move], player_increment[side_to_move], timed_search, use_book, skill[side_to_move], exact_skill[side_to_move], wld_skill[side_to_move], FALSE, &eval_info); if (side_to_move == BLACKSQ) set_evals(produce_compact_eval(eval_info), 0.0); else set_evals(0.0, produce_compact_eval(eval_info)); } } else { curr_move = provided_move[provided_move_index]; if (!valid_move(curr_move, side_to_move)) fatal_error("Invalid move %c%c in move sequence", TO_SQUARE(curr_move)); } move_stop = get_real_timer(); if (player_time[side_to_move] != INFINIT_TIME) player_time[side_to_move] -= (move_stop - move_start); store_move(disks_played, curr_move); (void) make_move(side_to_move, curr_move, TRUE); if (side_to_move == BLACKSQ) black_moves[score_sheet_row] = curr_move; else { white_moves[score_sheet_row] = curr_move; } } else { // this is where we pass if (side_to_move == BLACKSQ) black_moves[score_sheet_row] = PASS; else white_moves[score_sheet_row] = PASS; if (!auto_make_forced_moves && skill[side_to_move] == 0) { droidzebra_msg_pass(); } } droidzebra_msg_move_end(side_to_move); side_to_move = OPP(side_to_move); provided_move_index++; } droidzebra_enable_messaging(TRUE); if (side_to_move == BLACKSQ) score_sheet_row++; set_move_list(black_moves, white_moves, score_sheet_row); set_times(floor(player_time[BLACKSQ]), floor(player_time[WHITESQ])); droidzebra_msg_opening_name(opening_name); display_board(stdout, board, side_to_move, TRUE, TRUE, TRUE); /* double node_val, eval_val; adjust_counter( &total_nodes ); node_val = counter_value( &total_nodes ); adjust_counter( &total_evaluations ); eval_val = counter_value( &total_evaluations ); printf( "\nBlack: %d White: %d\n", disc_count( BLACKSQ ), disc_count( WHITESQ ) ); printf( "Nodes searched: %-10.0f\n", node_val ); printf( "Positions evaluated: %-10.0f\n", eval_val ); printf( "Total time: %.1f s\n", total_time ); */ if (!force_exit) droidzebra_msg_game_over(); // loop here until we are told to exit so the user has a chance to undo while (!force_exit) { droidzebra_msg_get_user_input(side_to_move, &evt); if (evt.type == UI_EVENT_EXIT) { force_exit = 1; break; } else if (evt.type == UI_EVENT_UNDO) { _droidzebra_undo_turn(&side_to_move); // adjust for increment at the beginning of the game loop if (side_to_move == BLACKSQ) score_sheet_row--; goto AGAIN; } else if (evt.type == UI_EVENT_SETTINGS_CHANGE) { _droidzebra_on_settings_change(); } } DROIDZEBRA_JNI_CLEAN; }
void Edit(char *args) { int editing = TRUE; int i; int side = White; char buffer[16]; struct Position *p = CurrentPosition; for(i=0; i<64; i++) p->piece[i] = Neutral; p->mask[White][0] = p->mask[Black][0] = 0; while(editing) { int sq; if(!ReadLine(buffer, 256)) break; sq = (buffer[1]-'a') + 8*(buffer[2]-'1'); switch(buffer[0]) { case '.': editing = FALSE; break; case 'c': side = OPP(side); break; case 'P': p->piece[sq] = PIECEID(Pawn, side); SetBit(p->mask[side][0], sq); break; case 'N': p->piece[sq] = PIECEID(Knight, side); SetBit(p->mask[side][0], sq); break; case 'B': p->piece[sq] = PIECEID(Bishop, side); SetBit(p->mask[side][0], sq); break; case 'R': p->piece[sq] = PIECEID(Rook, side); SetBit(p->mask[side][0], sq); break; case 'Q': p->piece[sq] = PIECEID(Queen, side); SetBit(p->mask[side][0], sq); break; case 'K': p->piece[sq] = PIECEID(King, side); SetBit(p->mask[side][0], sq); break; } } p->castle = p->enPassant = 0; RecalcAttacks(p); if(p->piece[e1] == King) { if(p->piece[h1] == Rook) p->castle |= CastleMask[White][0]; if(p->piece[a1] == Rook) p->castle |= CastleMask[White][1]; } if(p->piece[e8] == -King) { if(p->piece[h8] == -Rook) p->castle |= CastleMask[Black][0]; if(p->piece[a8] == -Rook) p->castle |= CastleMask[Black][1]; } RecalcAttacks(p); ShowPosition(p); }