コード例 #1
0
ファイル: ace_str.c プロジェクト: idx0/ace
char char_from_piece(piece_t p)
{
	static const char sPIECES[6] = { 'P', 'N', 'B', 'R', 'Q', 'K' };

	if (piece_color(p) == BLACK) {
		return tolower(sPIECES[piece_type(p)]);
	}

	return sPIECES[piece_type(p)];
}
コード例 #2
0
/*
 * Generate all non-capturing, non-promoting, pseudo-legal checks. Used for
 * quiescent move generation.
 */
int generate_pseudo_checks(const position_t* pos, move_t* moves)
{
    move_t* moves_head = moves;
    color_t side = pos->side_to_move, other_side = side^1;
    square_t king_sq = pos->pieces[other_side][0];
    for (int i = 0; i < pos->num_pawns[side]; ++i) {
        square_t from = pos->pawns[side][i];
        square_t to = INVALID_SQUARE;
        piece_t piece = pos->board[from];
        // Figure out whether or not we can discover check by moving.
        direction_t discover_check_dir = 0;
        bool will_discover_check;
        const attack_data_t* king_atk = &get_attack_data(from, king_sq);
        if ((king_atk->possible_attackers & Q_FLAG) == 0) {
            discover_check_dir = 0;
        } else {
            direction_t king_dir = king_atk->relative_direction;
            square_t sq;
            for (sq = from+king_dir; pos->board[sq] == EMPTY; sq+=king_dir) {}
            if (sq == king_sq) {
                // Nothing between us and the king. Is there anything
                // behind us to do the check when we move?
                for (sq = from-king_dir; pos->board[sq] == EMPTY;
                        sq -= king_dir) {}
                if (side == piece_color(pos->board[sq]) &&
                        (king_atk->possible_attackers &
                         get_piece_flag(pos->board[sq]))) {
                    discover_check_dir = king_dir;
                }
            }
        }
        // Generate checking moves.
        will_discover_check = discover_check_dir && abs(discover_check_dir)!=N;
        to = from + pawn_push[side];
        if (pos->board[to] != EMPTY) continue;
        rank_t r_rank =
            relative_rank[side][square_rank(from)];
        if (r_rank == RANK_7) continue; // non-promotes only
        for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) {
            if (will_discover_check || to + *delta == king_sq) {
                moves = add_move(pos,
                        create_move(from, to, piece, EMPTY),
                        moves);
                break;
            }
        }
        to += pawn_push[side];
        if (r_rank == RANK_2 && pos->board[to] == EMPTY) {
            for (const direction_t* delta = piece_deltas[piece];
                    *delta; ++delta) {
                if (will_discover_check || to + *delta == king_sq) {
                    moves = add_move(pos,
                            create_move(from, to, piece, EMPTY),
                            moves);
                    break;
                }
            }
        }
    }

    for (int i = 0; i < pos->num_pieces[side]; ++i) {
        square_t from = pos->pieces[side][i];
        square_t to = INVALID_SQUARE;
        piece_t piece = pos->board[from];
        // Figure out whether or not we can discover check by moving.
        direction_t discover_check_dir = 0;
        bool will_discover_check;
        const attack_data_t* king_atk = &get_attack_data(from, king_sq);
        if ((king_atk->possible_attackers & Q_FLAG) == 0) {
            discover_check_dir = 0;
        } else {
            direction_t king_dir = king_atk->relative_direction;
            square_t sq;
            for (sq = from+king_dir; pos->board[sq] == EMPTY; sq+=king_dir) {}
            if (sq == king_sq) {
                // Nothing between us and the king. Is there anything
                // behind us to do the check when we move?
                for (sq = from - king_dir; pos->board[sq] == EMPTY;
                        sq -= king_dir) {}
                if (side == piece_color(pos->board[sq]) &&
                        (king_atk->possible_attackers &
                         get_piece_flag(pos->board[sq]))) {
                    discover_check_dir = king_dir;
                }
            }
        }
        // Generate checking moves.
        if (piece_is_type(piece, KNIGHT)) {
            for (const direction_t* delta = piece_deltas[piece];
                    *delta; ++delta) {
                to = from + *delta;
                if (pos->board[to] != EMPTY) continue;
                if (discover_check_dir ||
                        possible_attack(to, king_sq, WN)) {
                    moves = add_move(pos,
                            create_move(from, to, piece, EMPTY),
                            moves);
                }
            }
        } else {
            for (const direction_t* delta = piece_deltas[piece];
                    *delta; ++delta) {
                for (to = from+*delta; pos->board[to] == EMPTY; to+=*delta) {
                    will_discover_check = discover_check_dir &&
                        abs(discover_check_dir) != abs(*delta);
                    if (will_discover_check) {
                        moves = add_move(pos,
                                create_move(from, to, piece, NONE),
                                moves);
                        continue;
                    }
                    if (possible_attack(to, king_sq, piece)) {
                        const direction_t to_king = direction(to, king_sq);
                        square_t x = to + to_king;
                        for (; pos->board[x] == EMPTY; x+=to_king) {}
                        if (x == king_sq) {
                            moves = add_move(pos,
                                    create_move(from, to, piece, NONE),
                                    moves);
                        }
                    }
                }
            }
        }
    }
    *moves = 0;
    return moves-moves_head;
}
コード例 #3
0
ファイル: ace_search.c プロジェクト: idx0/ace
int alpha_beta(app_t *app, cnodeptr_t parent, int alpha, int beta, int depth)
{
	int palpha = alpha;
	int i, score = -MATE, highest = -MATE;
	node_t node;
	move_t cutoff = 0;
	piece_t p;

	init_node(&node);

	assert(app);

	app->search.nodes++;
	node.depth = depth;

	/* max depth */
	if (app->game.board->ply > (SEARCH_MAXDEPTH - 1)) {
		/* return evaluate(app->board); */
		return quiescent(app, parent, alpha, beta);
	}

	/* recursive base */
	if (depth == 0) {
		return evaluate(app->game.board);
	}

	/* draws */
	if (repetitions(app) || (app->game.board->half >= 100)) {
		return 0;
	}

	/* if we are checked, set the nodes checked flag */
	if (check(app->game.board, app->game.board->side)) {
		node.flags |= NODE_CHECK;
		/* extend our search by 1 depth if we are in check */
		/* NOTES: we may want to NOT extend our search here if the parent
		   is in check, because the means we already extended once */
		depth++;
	}

	/* TODO:
	     - NULL moves
	     - Late-move reduction
	     - Tactical extensions (pins & forks -> depth++)
	 */

	/* probe our table */
	if (probe_hash(&app->hash, app->game.board, &cutoff, &score, depth, alpha, beta) == TRUE) {
		app->hash.cut++;
		return score;
	}

	/* generate moves */
	generate_moves(app->game.board, &node.ml, &node.ml);

	/* reset score */
	score = -MATE;

	/* try to match our hash hit move */
	if (cutoff != 0) {
		for (i = 0; i < node.ml.count; i++) {
			if (node.ml.moves[i] == cutoff) {
				node.ml.scores[i] = 20000;
				break;
			}
		}
	}

	/* search negamax */
	for (i = 0; i < node.ml.count; i++) {
		/* get the next move ordered */
		next_move(i, &node.ml);

		if (!(do_move(app->game.board, &app->game.undo, node.ml.moves[i])))
			continue;

		score = -alpha_beta(app, &node, -beta, -alpha, depth - 1);

		node.made++;
		undo_move(app->game.board, &app->game.undo);

		/* score whatever is best so far */
		if (score > highest) {
			node.best = node.ml.moves[i];
			highest = score;

			/* update alpha */
			if (score > alpha) {
				if (score >= beta) {

					/* non-captures causing beta cutoffs (killers) */
					if (!is_capture(node.ml.moves[i])) {
						app->game.board->killers[1][app->game.board->ply] =
							app->game.board->killers[0][app->game.board->ply];
						app->game.board->killers[0][app->game.board->ply] = node.ml.moves[i];
					}

					/* store this beta in our transposition table */
					store_hash(&app->hash, app->game.board, node.best, beta, HASH_BETA, depth);

					return beta;
				}

				/* update alpha */
				alpha = score;

				/* update our history */
				if (!is_capture(node.best)) {
					p = app->game.board->pos.squares[move_from(node.best)];
					app->game.board->history[piece_color(p)][piece_type(p)][move_to(node.best)] += depth;
				}
			}
		}
	}

	/* check for checkmate or stalemate */
	if (!node.made) {
		if (node.flags & NODE_CHECK) {
			return -MATE + app->game.board->ply;
		} else {
			return 0;
		}
	}

	if (alpha != palpha) {
		/* store this as an exact, since we beat alpha */
		store_hash(&app->hash, app->game.board, node.best, highest, HASH_EXACT, depth);
	} else {
		/* store the current alpha */
		store_hash(&app->hash, app->game.board, node.best, alpha, HASH_ALPHA, depth);
	}

	return alpha;
}
コード例 #4
0
/*
 * Generate pseudo-legal moves which are neither captures nor promotions.
 */
int generate_pseudo_quiet_moves(const position_t* pos, move_t* moves)
{
    move_t* moves_head = moves;
    color_t side = pos->side_to_move;
    piece_t piece;
    square_t from;

    // Castling. Castles are considered pseudo-legal if we have appropriate
    // castling rights, the squares between king and rook are unoccupied,
    // and the intermediate square is unattacked. Therefore checking for
    // legality just requires seeing if we're in check afterwards.
    // This is messy for Chess960, so it's separated into separate cases.
    square_t my_king_home = king_home + side*A8;
    if (!options.chess960) {
        if (has_oo_rights(pos, side) &&
                pos->board[my_king_home+1] == EMPTY &&
                pos->board[my_king_home+2] == EMPTY &&
                !is_square_attacked((position_t*)pos,my_king_home+1,side^1)) {
            assert(pos->board[my_king_home] ==
                    create_piece(pos->side_to_move, KING));
            moves = add_move(pos,
                    create_move_castle(my_king_home, my_king_home+2,
                        create_piece(side, KING)),
                    moves);
        }
        if (has_ooo_rights(pos, side) &&
                pos->board[my_king_home-1] == EMPTY &&
                pos->board[my_king_home-2] == EMPTY &&
                pos->board[my_king_home-3] == EMPTY &&
                !is_square_attacked((position_t*)pos,my_king_home-1,side^1)) {
            assert(pos->board[my_king_home] ==
                    create_piece(pos->side_to_move, KING));
            moves = add_move(pos,
                    create_move_castle(my_king_home, my_king_home-2,
                        create_piece(side, KING)),
                    moves);
        }
    } else {
        if (has_oo_rights(pos, side)) {
            square_t my_f1 = F1 + side*A8;
            square_t my_g1 = G1 + side*A8;
            square_t my_kr = king_rook_home + side*A8;
            bool castle_ok = true;
            // Check that rook is unimpeded.
            for (square_t sq = MIN(my_kr, my_f1);
                    sq <= MAX(my_kr, my_f1); ++sq) {
                if (sq != my_kr  && sq != my_king_home &&
                        pos->board[sq] != EMPTY) {
                    castle_ok = false;
                    break;
                }
            }
            // Check that the king is unimpeded and unattacked
            if (castle_ok) {
                for (square_t sq = MIN(my_king_home, my_g1);
                        sq <= my_g1; ++sq) {
                    if (sq != my_king_home && sq != my_kr &&
                            pos->board[sq] != EMPTY) {
                        castle_ok = false;
                        break;
                    }
                    if (sq != my_g1 &&
                            is_square_attacked((position_t*)pos, sq, side^1)) {
                        castle_ok = false;
                        break;
                    }
                }
            }
            if (castle_ok) moves = add_move(pos,
                    create_move_castle(my_king_home, my_g1,
                        create_piece(side, KING)), moves);
        }
        if (has_ooo_rights(pos, side)) {
            square_t my_d1 = D1 + side*A8;
            square_t my_c1 = C1 + side*A8;
            square_t my_qr = queen_rook_home + side*A8;
            bool castle_ok = true;
            // Check that rook is unimpeded.
            for (square_t sq = MIN(my_qr, my_d1);
                    sq <= MAX(my_qr, my_d1); ++sq) {
                if (sq != my_qr && sq != my_king_home &&
                        pos->board[sq] != EMPTY) {
                    castle_ok = false;
                    break;
                }
            }
            // Check that the king is unimpeded and unattacked
            if (castle_ok) {
                for (square_t sq = MIN(my_king_home, my_c1);
                        sq <= MAX(my_king_home, my_c1); ++sq) {
                    if (sq != my_king_home && sq != my_qr &&
                            pos->board[sq] != EMPTY) {
                        castle_ok = false;
                        break;
                    }
                    if (sq != my_c1 &&
                            is_square_attacked((position_t*)pos, sq, side^1)) {
                        castle_ok = false;
                        break;
                    }
                }
            }
            if (castle_ok) moves = add_move(pos,
                    create_move_castle(my_king_home, my_c1,
                        create_piece(side, KING)),
                    moves);
        }
    }

    for (int i = 0; i < pos->num_pieces[side]; ++i) {
        from = pos->pieces[side][i];
        piece = pos->board[from];
        assert(piece_color(piece) == side && piece_type(piece) != PAWN);
        generate_piece_noncaptures(pos, from, piece, &moves);
    }
    piece = create_piece(side, PAWN);
    for (int i=0; i<pos->num_pawns[side]; ++i) {
        from = pos->pawns[side][i];
        assert(pos->board[from] == piece);
        generate_pawn_quiet_moves(pos, from, piece, &moves);
    }

    *moves = 0;
    return (moves-moves_head);
}