Exemple #1
0
void
do_perft(position_t *pos, scored_move_t *ms, int ply, int depth)
{
	scored_move_t *msbase = ms;
	uint8 stm = Stm(ply);
	scored_move_t *mv;

	if (Checked(stm^1))
		return;

	if (Checked(stm)) {
		ms = generate_evasions(pos, ms, ply);
		for (mv = msbase; mv < ms; mv++)
			if (PieceType(Capture(mv->move)) == KING)
				return;
	} else {
		ms = generate_captures(pos, ms, ply);
		for (mv = msbase; mv < ms; mv++)
			if (PieceType(Capture(mv->move)) == KING)
				return;
		ms = generate_noncaptures(pos, ms, ply);
	}

	for (mv = msbase; mv < ms; mv++) {
		make_move(pos, mv->move, ply);
		if (depth - 1)
			do_perft(pos, ms, ply + 1, depth - 1);
		else if (!Checked(stm))
			total_moves++;
		unmake_move(pos, mv->move, ply);
	}
}
Exemple #2
0
int quiescence(int alpha, int beta)
{
    int static_evaluation = evaluate(alpha, beta);
    if(static_evaluation >= beta)
        return beta;
    if(static_evaluation > alpha)
        alpha = static_evaluation;
    
    Move movelist[256];
    int n = generate_captures(movelist);
    sorting_captures(movelist, n);
    for(int i = 0; i < n; i += 1)
    {
        Move i_move = movelist[i];
        make_move(i_move);
        int score = -quiescence(-beta, -alpha);
        unmake_move(i_move);
        
        if(score >= beta)
        {
            return beta;
        }
        if(score > alpha)
        {
            alpha = score;
        }
    }
    return alpha;
}
Exemple #3
0
void perft_divide(FILE* stream, Board* board, unsigned int depth)
{
	int i, totalMoves = 0;
	Move moves[256];

	if (depth <= 0)
	{
		return;
	}

	int num_moves = generate_moves(board, moves);

	for (i = 0; i < num_moves; ++i)
	{
		int numDividedMoves = 0;
		char moveString[8];
		sprint_move(moveString, moves[i]);
		printf("%s ", moveString);

		make_move(board, moves[i]);
		numDividedMoves = perft_perft(board, depth - 1);
		unmake_move(board, moves[i]);

		totalMoves += numDividedMoves;
		printf("%i\n", numDividedMoves);
	}

	fprintf(stream, "\nMoves: %i\n", num_moves);
	fprintf(stream, "Nodes: %i\n", totalMoves);
}
void backtrack(int a[], int k, void* input)
{
    int c[MAXCANDIDATES];
    int ncandidates;

    if (is_a_solution(a, k, input))
    {
        process_solution(a, k, input);
    }
    else
    {
        k = k + 1;

        construct_candidates(a, k, input, c, &ncandidates);

        for (int i = 0; i < ncandidates; i++)
        {
            a[k] = c[i];

            make_move(a, k, input);
            backtrack(a, k, input);
            unmake_move(a, k, input);

            if (finished)
                return;
        }
    }
}
Exemple #5
0
void record_a_move(int x, int y, int to_x, int to_y, int captures_only, int depth)
	{
//printf("record(%d,%d,%d,%d,%d,%d)\n",x,y,to_x,to_y,captures_only,depth);
	if (captures_only && board.cells[to_x][to_y] == 0)
		return;
	if (board.cells[x][y])
		++attacked_squares[depth][to_x][to_y];

	if (attacked_squares_only == 0)
		{
		int check;

		moves[depth][move_counter[depth]].x = x;
		moves[depth][move_counter[depth]].y = y;
		moves[depth][move_counter[depth]].piece = board.cells[x][y];
		moves[depth][move_counter[depth]].to_x = to_x;
		moves[depth][move_counter[depth]].to_y = to_y;
		moves[depth][move_counter[depth]].captured_piece = board.cells[to_x][to_y];

		make_move(&moves[depth][move_counter[depth]]);
		board.side = !board.side; // these switches are dumb
		check = in_check(depth);
		board.side = !board.side;
		unmake_move(&moves[depth][move_counter[depth]]);

		if (!check) ++move_counter[depth];
		}
	}
Exemple #6
0
Bitmap xperft(int depth) {
    Bitmap x, k, desde, hasta, r;

    desde = (Bitmap) board.ply_moves[board.ply - 1];
    hasta = (Bitmap) board.ply_moves[board.ply];

    if (depth > 1) {
        x = 0;
        // xfen();xl();
        for (k = desde; k < hasta; k++) {
            // b0 = board; //DBG

            make_move(board.moves[k]);

            movegen();

            r = xperft(depth - 1);
            x += r;
            unmake_move();

        }
        return x;
    } else {
        return hasta - desde;
    }
}
Exemple #7
0
int PVS(int alpha, int beta, int depth)
{
    if(is_draw_by_repetition_or_50_moves()) return DRAW;
    
    if(depth == 0) return quiescence(alpha, beta);
    
    Move movelist[256];
    int n = generate_moves(movelist);
    if(n == 0)
    {
        if(!in_check(turn_to_move))
            return DRAW;
        return LOSING + ply - begin_ply;
    }
    sorting_moves(movelist, n);
    
    int bool_search_pv = 1;
    Move bestmove = 0;

    for(int i = 0; i < n; i += 1)
    {
        Move i_move = movelist[i];
        make_move(i_move);
        int score;
        if(bool_search_pv)
        {
            score = -PVS(-beta, -alpha, depth - 1);
        }
        else
        {
            score = -ZWS(-alpha, depth - 1, 1);
            if(score > alpha)
                score = -PVS(-beta, -alpha, depth - 1);
        }
        unmake_move(i_move);
        
        if(score >= beta)
        {
            hash_save_entry(depth, beta, i_move, MORE_THAN_BETA);
            if(!move_broken(i_move))
            {
                history[board[move_from(i_move)]][move_to(i_move)] = depth * depth;
            }
            return beta;
        }
        if(score > alpha)
        {
            bestmove = i_move;
            alpha = score;
        }
        bool_search_pv = 0;
    }
    if(bestmove != 0)
        hash_save_entry(depth, alpha, bestmove, BETWEEN_ALPHA_AND_BETA);
    else
        hash_save_entry(depth, alpha, 0, LESS_THAN_ALPHA);
    return alpha;
}
Exemple #8
0
void
hash_expand_pv( int side_to_move,
		int mode,
		int flags,
		int max_selectivity ) {
  int i;
  int pass_count;
  int new_pv_depth;
  int new_pv[61];
  int new_side_to_move[61];
  HashEntry entry;

  determine_hash_values( side_to_move, board );
  new_pv_depth = 0;
  pass_count = 0;

  while ( pass_count < 2 ) {
    new_side_to_move[new_pv_depth] = side_to_move;
    if ( (new_pv_depth < pv_depth[0]) && (new_pv_depth == 0) ) {
      if ( (board[pv[0][new_pv_depth]] == EMPTY) &&
	   make_move( side_to_move, pv[0][new_pv_depth], TRUE ) ) {
	new_pv[new_pv_depth] = pv[0][new_pv_depth];
	new_pv_depth++;
	pass_count = 0;
      }
      else {
	hash1 ^= hash_flip_color1;
	hash2 ^= hash_flip_color2;
	pass_count++;
      }
    }
    else {
      find_hash( &entry, mode );
      if ( (entry.draft != NO_HASH_MOVE) &&
	   (entry.flags & flags) &&
	   (entry.selectivity <= max_selectivity) &&
	   (board[entry.move[0]] == EMPTY) &&
	   make_move( side_to_move, entry.move[0], TRUE ) ) {
	new_pv[new_pv_depth] = entry.move[0];
	new_pv_depth++;
	pass_count = 0;
      }
      else {
	hash1 ^= hash_flip_color1;
	hash2 ^= hash_flip_color2;
	pass_count++;
      }
    }
    side_to_move = OPP( side_to_move );
  }
  for ( i = new_pv_depth - 1; i >= 0; i-- )
    unmake_move( new_side_to_move[i], new_pv[i] );
  for ( i = 0; i < new_pv_depth; i++ )
    pv[0][i] = new_pv[i];
  pv_depth[0] = new_pv_depth;
}
Exemple #9
0
int ZWS(int beta, int depth, int can_reduce)
{
    if(is_draw_by_repetition_or_50_moves()) return DRAW;
    
    Entry *entry = hash_get_entry();
    if(entry != NULL && entry->depth >= depth)
    {
        int eval = entry->eval, flag = entry->flag;
        if(flag != LESS_THAN_ALPHA && eval >= beta)
            return beta;
        if(flag != MORE_THAN_BETA && eval < beta)
            return beta - 1;
    }
    
    if(depth == 0) return quiescence(beta - 1, beta);
    
    /*if(depth <= 6 && evaluate(beta - 1, beta) >= beta)
    {
        return beta;
    }*/
    
    if(depth > 2 && can_reduce && !in_check(turn_to_move))
    {
        int R = depth > 6 ? 3: 2;
        make_null_move();
        int score = -ZWS(-beta + 1, depth - R - 1, 0);
        unmake_null_move();
        if(score >= beta) return beta;
    }
    
    Move movelist[256];
    int n = generate_moves(movelist);
    if(n == 0)
    {
        if(!in_check(turn_to_move))
            return DRAW;
        return LOSING + ply - begin_ply;
    }
    sorting_moves(movelist, n);
    for(int i = 0; i < n; i += 1)
    {
        Move i_move = movelist[i];
        make_move(i_move);
        int score = -ZWS(-beta + 1, depth - 1, can_reduce);
        unmake_move(i_move);
        
        if(score >= beta)
        {
            hash_save_entry(depth, beta, i_move, MORE_THAN_BETA);
            return beta;
        }
    }
    hash_save_entry(depth, beta - 1, 0, LESS_THAN_ALPHA);
    return beta - 1;
}
Exemple #10
0
BOOL test_make_unmake() {

    BOOL ok = TRUE;
    int i, j;

    struct t_move_list moves[1];
    struct t_undo undo[1];

    set_fen(position, "rnbqkb1r/ppppp1pp/7n/5p2/4P3/8/PPPP1PPP/RNBQKBNR w KQkq -");
    assert(integrity(position));
    for (j = WHITE; j <= BLACK; j++) {
        generate_moves(position, moves);
        for (i = 0; i < moves->count; i++) {
            assert(integrity(position));
            if (make_move(position, moves->pinned_pieces, moves->move[i], undo)) {
                assert(integrity(position));
                unmake_move(position, undo);
                assert(integrity(position));
            }
        }
        flip_board(position);
    }
    ok = integrity(position);

    set_fen(position, "r3Rbk1/2p2p1p/p2p4/1p1P2q1/8/PBPQ2pP/1P3P1P/3R2K1 b - -");
    assert(integrity(position));
    for (j = WHITE; j <= BLACK; j++) {
        generate_moves(position, moves);
        for (i = 0; i < moves->count; i++) {
            assert(integrity(position));
            if (make_move(position, moves->pinned_pieces, moves->move[i], undo)) {
                assert(integrity(position));
                unmake_move(position, undo);
                assert(integrity(position));
            }
        }
        flip_board(position);
    }
    ok &= integrity(position);

    return ok;
}
Exemple #11
0
/**
pgn_save():
pgn_save saves the current game into a pgn file. If the file already exists, it appends the game to the end.
Created 091407; last modified 091407
**/
void pgn_save(char *file_name)
{
	FILE *pgn_file;
	char text[80];
	GAME_ENTRY *current_entry;

	pgn_file = fopen(file_name, "at");
	if (pgn_file == NULL)
	{
		print("%s: file not found.\n");
		return;
	}
	/* Make sure we have the game result, then print the PGN tags. */
	check_result(FALSE);
	strcpy(pgn_game.tag.result, result_str[zct->game_result]);
	fprintf(pgn_file, "[Event \"%s\"]\n", pgn_game.tag.event);
	fprintf(pgn_file, "[Site \"%s\"]\n", pgn_game.tag.site);
	fprintf(pgn_file, "[Date \"%s\"]\n", pgn_game.tag.date);
	fprintf(pgn_file, "[Round \"%s\"]\n", pgn_game.tag.round);
	fprintf(pgn_file, "[White \"%s\"]\n", pgn_game.tag.white);
	fprintf(pgn_file, "[Black \"%s\"]\n", pgn_game.tag.black);
	fprintf(pgn_file, "[Result \"%s\"]\n", pgn_game.tag.result);
	if (strcmp(pgn_game.tag.fen, "") != 0)
		fprintf(pgn_file, "[FEN \"%s\"]\n", pgn_game.tag.fen);
	fprintf(pgn_file, "\n");
	/* Return to the beginning of the game. */
	current_entry = board.game_entry;
	while (board.game_entry > board.game_stack)
		unmake_move();

	/* Start with the proper move number indicator, depending on the side.
		We have to check that at least one move has been made before this. */
	if (board.game_entry < current_entry)
	{
		sprint(text, 80, "%i.%s%M ", board.move_number,
			board.side_tm == WHITE ? "" : "..", board.game_entry->move);
		make_move(board.game_entry->move);
	}
	/* Wade through the rest of the game. */
	while (board.game_entry < current_entry)
	{
		if (board.side_tm == WHITE)
			sprint(text, 80, "%s%i.", text, board.move_number);
		sprint(text, 80, "%s%M ", text, board.game_entry->move);
		make_move(board.game_entry->move);
		if (strlen(text) >= 70)
		{
			fprintf(pgn_file, "%s\n", text);
			strcpy(text, "");
		}
	}
	fprintf(pgn_file, "%s%s\n\n", text, result_str[zct->game_result]);
	fclose(pgn_file);
}
// undo moves until player is a human and he can make a move
void _droidzebra_undo_turn(int *side_to_move) {
    int human_can_move = 0;
    int curr_move;

    if (score_sheet_row == 0 && *side_to_move == BLACKSQ) return;

    _droidzebra_undo_stack_push(disks_played);

    do {
        *side_to_move = OPP(*side_to_move);

        if (*side_to_move == WHITESQ)
            score_sheet_row--;

        human_can_move =
                skill[*side_to_move] == 0 &&
                !(
                        (auto_make_forced_moves && move_count[disks_played - 1] == 1)
                        || (*side_to_move == WHITESQ && white_moves[score_sheet_row] == PASS)
                        || (*side_to_move == BLACKSQ && black_moves[score_sheet_row] == PASS)
                );

        if (*side_to_move == WHITESQ) {
            curr_move = white_moves[score_sheet_row];
            if (white_moves[score_sheet_row] != PASS)
                unmake_move(WHITESQ, white_moves[score_sheet_row]);
            white_moves[score_sheet_row] = PASS;
        } else {
            curr_move = black_moves[score_sheet_row];
            if (black_moves[score_sheet_row] != PASS)
                unmake_move(BLACKSQ, black_moves[score_sheet_row]);
            black_moves[score_sheet_row] = PASS;
        }

        droidzebra_message_debug(
                "undo: side_to_move %d, undo_move %d, score_sheet_row %d, disks_played %d, move_count %d",
                *side_to_move, curr_move, score_sheet_row, disks_played, move_count[disks_played]);
    } while (!(score_sheet_row == 0 && *side_to_move == BLACKSQ) && !human_can_move);
    clear_endgame_performed();
}
Exemple #13
0
t_nodes do_perft(struct t_board *board, int depth)
{
    struct t_move_list move_list[1];
	struct t_move_list bad_move_list[1];
	bad_move_list->count = 0;
	bad_move_list->imove = 0;
    struct t_undo undo[1];

    t_nodes nodes = 0;
    int i;

    assert(integrity(board));
    if (board->in_check) {
        generate_evade_check(board, move_list);
        if (depth == 1) return move_list->count;
    }
    else {

        //generate_captures(board, move_list);
        //generate_quiet_moves(board, move_list);
        generate_moves(board, move_list);
        //if (!equal_move_lists(move_list, xmove_list)){
        //	write_board(board, "board.txt");
        //	write_move_list(xmove_list, "all.txt");
        //	write_move_list(move_list, "inc.txt");
        //}
        if (depth == 1) return legal_move_count(board, move_list);
    }

    for (i = move_list->count - 1; i >= 0; i--) {
        assert(lookup_move(board, move_as_str(move_list->move[i])) == move_list->move[i]);
        if (make_next_move(board, move_list, bad_move_list, undo)) {
            assert(integrity(board));

            //nodes++;
            if (depth > 1)
                nodes += do_perft(board, depth - 1);
            else
                nodes++;
            unmake_move(board, undo);
            assert(integrity(board));
        }
        else
            assert(integrity(board));
    }

    return nodes;

}
Exemple #14
0
void add_root_move(position_t *pos, search_stack_t *sstack,
              move_t move, root_move_list_t *list) {
  undo_info_t u[1];
  if(move_is_legal(pos, move)) {
    list->moves[list->num].move = move;
    list->moves[list->num].nodes = 0;
    list->moves[list->num].cumulative_nodes = 0;
    sstack[0].move = move;
    make_move(pos, move, u);
//  list->moves[list->num].depth_1_score = search(pos, sstack, 1, 0, 0);
    list->moves[list->num].score = WORSTSCORE;
    
    unmake_move(pos, move, u);
    list->num++;
  }
}
Exemple #15
0
void record_a_spawn(piece, to_x, to_y, depth)
	{
	int check;
	moves[depth][move_counter[depth]].x = -1;
	moves[depth][move_counter[depth]].y = -1;
	moves[depth][move_counter[depth]].piece = piece;
	moves[depth][move_counter[depth]].to_x = to_x;
	moves[depth][move_counter[depth]].to_y = to_y;
	moves[depth][move_counter[depth]].captured_piece = 0;

	make_move(&moves[depth][move_counter[depth]]);
	board.side = !board.side; // these switches are dumb
	check = in_check(depth);
	board.side = !board.side;
	unmake_move(&moves[depth][move_counter[depth]]);

	if (!check) ++move_counter[depth];
	}
Exemple #16
0
U64 perft(int depth)
{
    Move movelist[256];
    int n;
    U64 result = 0;
    
    if(depth == 0) return 1;
    
    n = generate_moves(movelist);
    for(int i = 0; i < n; i += 1)
    {
        Move i_move = movelist[i];
        make_move(i_move);
        result += perft(depth - 1);
        unmake_move(i_move);
    }
    return result;
}
Exemple #17
0
int Search::capture_quiescence_eval_search(bool white_turn, int alpha, int beta, Board& board) {
	if (board.b[WHITE][KING] == 0) {
		return -10000;
	} else if (board.b[BLACK][KING] == 0) {
		return 10000;
	}

	int static_eval = evaluate(board);
	if (static_eval > alpha && white_turn) {
		return static_eval;
	}
	if (static_eval < beta && !white_turn) {
		return static_eval;
	}

	MoveList capture_moves = get_captures(board, white_turn);
	if (capture_moves.empty()) {
		// the end point of the quiescence search
		return static_eval;
	}
	for (unsigned int i = 0; i < capture_moves.size(); ++i) {
		pick_next_move(capture_moves, i);
		Move move = capture_moves[i];
		quiescence_node_count++;
		make_move(board, move);
		int res = capture_quiescence_eval_search(!white_turn, alpha, beta, board);
		unmake_move(board, move);
		if (res > alpha && white_turn) {
			alpha = res;
		}
		if (res < beta && !white_turn) {
			beta = res;
		}
		if (beta <= alpha || time_to_stop()) {
			break;
		}
	}
	if (white_turn) {
		return alpha;
	}
	return beta;
}
Exemple #18
0
BOOL test_ep_capture()
{
	uci_set_mode();
	uci_isready();

	set_hash(512);
	set_own_book(TRUE);

	uci_position(position, "position fen 2r2bk1/1pNb4/3p3q/p2Pp2n/2P1PpPP/5P2/PPn1Q3/2KR3R b - g3");

	struct t_move_list moves[1];
	t_undo undo[1];

	generate_moves(position, moves);
	for (int i = 0; i < moves->count; i++){
		if (make_move(position, moves->pinned_pieces, moves->move[i], undo))
			unmake_move(position, undo);
	}

	return TRUE;
}
void backtrack(int a[], int k, data input)
{
  int c[MAXCANDIDATES];         /* candidates for next position */
  int ncandidates;              /* next position candidates count */
  int i;


  if (is_a_solution(a, k, input))
    process_solution(a, k, input);
  else {
    ++k;
    construct_candidates(a, k, input, c, &ncandidates);
    for (i=0; i<ncandidates; ++i) {
      a[k] = c[i];
      make_move(a, k, input);
      backtrack(a, k, input);
      unmake_move(a, k, input);
      if (finished) return;
    }
  }
} 
Exemple #20
0
void update_best_line_from_hash(struct t_board *board, int ply)
{
	struct t_pv_data *pv = &(board->pv_data[ply]);
	t_move_record *move;
	t_hash_record *hash_record;
	t_undo undo[1];

	hash_record = probe(board->hash);
	if (hash_record != NULL && hash_record->bound == HASH_EXACT && hash_record->move != NULL){
		move = hash_record->move;
		hash_record->age = hash_age;
		if (is_move_legal(board, move))
			make_move(board, 0, move, undo);
		else
			return;
		pv->best_line[pv->best_line_length++] = move;
		if (!repetition_draw(board))
			update_best_line_from_hash(board, ply);
		unmake_move(board, undo);
	}
}
Exemple #21
0
unsigned int perft_perft(Board* board, unsigned int depth)
{
	int i, nperft = 0;
	Move moves[256];

	if (depth == 0)
	{
		return 1;
	}

	TTEntry* ttentry = get_tt_entry_at_depth(board->zobrist, depth);
	if (ttentry)
	{
		return ttentry->score;
	}

	unsigned int numMoves = generate_moves(board, moves);

	for (i = 0; i < numMoves; ++i)
	{
		make_move(board, moves[i]);
		if ((board->sideToMove == BLACK &&
			!black_attacks_square(board, bit_scan_forward(board->pieces[WHITE_KING]))) ||
			(board->sideToMove == WHITE &&
			!white_attacks_square(board, bit_scan_forward(board->pieces[BLACK_KING]))))
		{
			nperft += perft_perft(board, depth - 1);
		}
		unmake_move(board, moves[i]);
	}

	TTEntry new_entry;
	new_entry.key = board->zobrist;
	new_entry.score = nperft;
	new_entry.depth = depth;

	put_tt_entry(&new_entry);

	return nperft;
}
Exemple #22
0
void
complete_pv( int side_to_move ) {
  int i;
  int actual_side_to_move[60];

  full_pv_depth = 0;
  for ( i = 0; i < pv_depth[0]; i++ ) {
    if ( make_move( side_to_move, pv[0][i], TRUE ) ) {
      actual_side_to_move[i] = side_to_move;
      full_pv[full_pv_depth] = pv[0][i];
      full_pv_depth++;
    }
    else {
      full_pv[full_pv_depth] = PASS;
      full_pv_depth++;
      side_to_move = OPP( side_to_move );
      if ( make_move( side_to_move, pv[0][i], TRUE ) ) {
	actual_side_to_move[i] = side_to_move;
	full_pv[full_pv_depth] = pv[0][i];
	full_pv_depth++;
      }
      else {
#ifdef TEXT_BASED
	int j;

	printf( "pv_depth[0] = %d\n", pv_depth[0] );
	for ( j = 0; j < pv_depth[0]; j++ )
	  printf( "%c%c ", TO_SQUARE( pv[0][j] ) );
	puts( "" );
	printf( "i=%d\n", i );
#endif
	fatal_error( PV_ERROR );
      }
    }
    side_to_move = OPP( side_to_move );
  }
  for ( i = pv_depth[0] - 1; i >= 0; i-- )
    unmake_move( actual_side_to_move[i], pv[0][i] );
}
Exemple #23
0
backtrack(int a[], int k, data input)
{
        int c[MAXCANDIDATES];           /* candidates for next position */
        int ncandidates;                /* next position candidate count */
        int i;                          /* counter */

        if (is_a_solution(a,k,input))
                process_solution(a,k,input);
        else {
                k = k+1;
                construct_candidates(a,k,input,c,&ncandidates);
                for (i=0; i<ncandidates; i++) {
                        a[k] = c[i];
			make_move(a,k,input);

                        backtrack(a,k,input);
			if (finished) return;	/* terminate early */

			unmake_move(a,k,input);
                }
        }
}
Exemple #24
0
t_nodes perft(struct t_board *board, int depth) {

    struct t_move_list move_list[1];
    struct t_undo undo[1];

    t_nodes total_nodes = 0;
    t_nodes move_nodes = 0;

    unsigned long start = time_now();

    int i;

    if (board->in_check)
        generate_evade_check(board, move_list);
    else
        generate_moves(board, move_list);

    for (i = move_list->count - 1; i >= 0; i--) {
        if (make_move(board, move_list->pinned_pieces, move_list->move[i], undo)) {
            move_nodes = 0;
            if (depth > 1)
                move_nodes += do_perft(board, depth - 1);
            printf(move_as_str(move_list->move[i]));
            printf(" = %u\n", move_nodes);
            unmake_move(board, undo);
            total_nodes += move_nodes;
        }
    }

    unsigned long finish = time_now();

    if (finish == start)
        printf("Total Nodes: %I64d\n", total_nodes);
    else
        printf("Total Nodes: %I64d in %d milliseconds = nps %I64d\n", total_nodes, finish - start, 1000 * total_nodes / (finish - start));

    return total_nodes;
}
Exemple #25
0
 void generate_subsequences(const std::string& from
         , int index
         , std::string& to
         , std::unordered_set<std::string>& subsequences)
 {
     if(be_a_solution(from, index))
     {
         process_solution(to, subsequences);
     }
     else
     {
         //construct_candidates
         char candidates[2] = {from[index], '\0'};
         int sz=to.size();
         for(size_t i=0; i<2; ++i)
         {
             if(candidates[i]!='\0')
                 to.push_back(candidates[i]);
             //make_move
             generate_subsequences(from, index+1, to, subsequences);
             unmake_move(to, sz);
         }
     }
 }
Exemple #26
0
/**
stop_search():
This checks for time and input to see if need to stop searching.
Created 091006; last modified 030709
**/
BOOL stop_search(void)
{
	CMD_RESULT cmd_result;
	BOOL stop = FALSE;
	GAME_ENTRY *current;

	if (zct->stop_search)
		stop = TRUE;
	/* Check for input, because we might enter this function more than once
		before fully stopping when unwinding the stack. */
	else if (zct->input_buffer[0])
		stop = TRUE;
	else if (time_is_up())
		stop = TRUE;
	else if (input_available())
	{
		/* Return to the root position. Some commands, such as "display" work
			on the root position instead of the current one. */
		current = board.game_entry;
		while (board.game_entry > root_entry)
			unmake_move();
		/* When pondering, the root entry is after the ponder move. */
		if (zct->engine_state == PONDERING)
			unmake_move();
		/* Read the command and parse it. */
		read_line();
		cmd_result = command(zct->input_buffer);
		/* Command() returns CMD_STOP_SEARCH when we need to exit the search to
			handle a command. */
		if (cmd_result == CMD_STOP_SEARCH)
			stop = TRUE;
		/* If the command was a move, either stop or make the move. */
		else if (zct->engine_state != NORMAL && cmd_result == CMD_BAD &&
			input_move(zct->input_buffer, INPUT_CHECK_MOVE))
		{
			/* If we are pondering, check if the move entered was the ponder
				move. If so, we don't need to stop. */
			if (zct->engine_state == PONDERING && input_move(zct->input_buffer,
				INPUT_GET_MOVE) == zct->ponder_move)
			{
				zct->input_buffer[0] = '\0';
				make_move(zct->ponder_move);
				zct->engine_state = NORMAL;
				update_clocks();
			}
			else
				stop = TRUE;
		}
		else if (cmd_result == CMD_BAD)
		{
			zct->input_buffer[0] = '\0';
			if (zct->protocol != UCI)
				print("Error.\n");
		}

		/* Check for ping here in UCI mode. */
		if (zct->ping && zct->protocol == UCI)
		{
			print("readyok\n");
			zct->ping = 0;
		}
		/* Go back to the position we were in before checking. This is kind of
			hacky in that it relies on the game history after undoing all the
			moves to be the same. */
		while (board.game_entry < current)
			make_move(board.game_entry->move);
	}

	/* If we're stopping the search, set a flag to make sure we don't come
		back here and decide to keep going, thereby introducing bugs... */
	if (stop)
		zct->stop_search = TRUE;

	return stop;
}
Exemple #27
0
/**
search_maintenance():
In every node during a search, do some checks for SMP events, timeout, etc.
If the search needs to exit, we store the return value in return_value and
return TRUE, otherwise we return FALSE.
Created 031609; last modified 031609
**/
BOOL search_maintenance(SEARCH_BLOCK **sb, VALUE *return_value)
{
#ifdef SMP
	int r;

	/* Handle any asynchronous messages we have. */
	if (smp_block[board.id].message_count)
		handle_smp_messages(sb);

	/* Check for synchronous messages, and exit if necessary. */
	if (smp_block[board.id].input)
	{
		if (handle_smp_input(*sb))
		{
			*return_value = 0;
			return TRUE;
		}
	}

	/* If another processor has backed up to the root, they set a flag
	   because only the main processor can return to search_root(). */
	if (board.id == 0 && smp_data->return_flag)
	{
		ASSERT(board.split_point == board.split_point_stack);
		ASSERT(smp_data->split_count == 0);

		/* Back up the game board. */
		while (board.game_entry > root_entry + 1)
			unmake_move();

		/* This is kind of hacky... */
		if (board.game_entry == root_entry)
			make_move((zct->next_root_move - 1)->move);

		SMP_DEBUG(print("cpu 0 returning...\n%B",&board));
		smp_data->return_flag = FALSE;
		set_active();

		/* Return the score and PV. */
		copy_pv(board.pv_stack[1], smp_data->return_pv);
		*return_value = smp_data->return_value;
		return TRUE;
	}
#endif

	/* Do the standard periodic check for time or input. */
	if (search_check())
	{
#ifdef SMP
		/* Flag the other processors down. */
		for (r = 1; r < zct->process_count; r++)
			smp_tell(r, SMP_PARK, 0);
		/* Unsplit all of our split points, after waiting for the
		   child processors to detach. */
		while (*board.split_point != NULL)
		{
			while ((*board.split_point)->child_count > 1)
				;
			unsplit(*sb, (*board.split_point)->id);
		}
#endif
		/* We're good to go. Stop the search. */
		while (board.game_entry > root_entry + 1)
			unmake_move();

		/* This is kind of hacky... */
		if (board.game_entry == root_entry)
			make_move((zct->next_root_move - 1)->move);

		/* Return a really good score, so the root move appears to
		   be a mated-in-0. This just invalidates the score. */
		*return_value = MATE;
		return TRUE;
	}

	return FALSE;
}
Exemple #28
0
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;
}
Exemple #29
0
uint64_t test_perft_rec(state_t *state, int depth, int verbose)
{
    /* Given a position, it will recursivly apply every possible
     * move for a given depth and count the leaf nodes. */

    if (depth == 0)
    {
        return 1;
    }

    hash_node_t *hash_node = hash_get_node(state->zobrist);
    /* Check if hashing is enabled */
    if (hash_node)
    {
        if (hash_node->hash == state->zobrist && hash_node->depth == depth)
        {
            ++_cache_hits;
            return hash_node->score;
        }
        else
        {
            ++_cache_misses;
        }
    }

    int moves[100];
    int count = 0, count2 = 0;

    move_generate_moves(state, moves, &count);
    move_generate_tactical(state, moves + count, &count2);
    count += count2;

    /* Check for invalid position or board with no pieces :) */
    if (count <= 0)
    {
        return 0;
    }

    uint64_t nodes = 0;

    int i;
    for (i = 0; i < count; ++i)
    {
        make_move(state, moves[i], depth);

        if (move_is_attacked(state, state->king_idx[Flip(state->turn)], state->turn))
        {
            unmake_move(state, moves[i], depth);
            continue;
        }

        uint64_t res = test_perft_rec(state, depth - 1, 0);
        nodes += res;

        if (verbose && res > 0)
        {
            char move_str[16];
            util_move_to_lan(moves[i], move_str);
            printf("%s: %lld\n", move_str, res);
        }

        unmake_move(state, moves[i], depth);
    }

    hash_add_node(state->zobrist, nodes, depth, 0, 0);

    return nodes;
}
Exemple #30
0
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 );
}