Exemple #1
0
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)];
}
Exemple #2
0
 static sint piece_char(uint piece)
 {
     return type_char(piece_type(piece));
 }
/*
 * Add all pseudo-legal captures that the given piece (N/B/Q/K) can make.
 */
static void generate_piece_captures(const position_t* pos,
        square_t from,
        piece_t piece,
        move_t** moves_head)
{
    move_t* moves = *moves_head;
    square_t to;
    // Note: I unrolled all these loops to handle each direction explicitly.
    // The idea was to increase performance, but it's only about 1% faster
    // for much more code, so it's possible I'll change this back later.
    switch (piece_type(piece)) {
        case KING:
            to = from - 17;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from - 16;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from - 15;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from - 1;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 1;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 15;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 16;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 17;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            break;
        case KNIGHT:
            to = from - 33;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from - 31;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from - 18;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from - 14;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 14;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 18;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 31;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            to = from + 33;
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            break;
        case BISHOP:
            for (to=from-17; pos->board[to]==EMPTY; to-=17) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from-15; pos->board[to]==EMPTY; to-=15) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+15; pos->board[to]==EMPTY; to+=15) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+17; pos->board[to]==EMPTY; to+=17) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            break;
        case ROOK:
            for (to=from-16; pos->board[to]==EMPTY; to-=16) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from-1; pos->board[to]==EMPTY; to-=1) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+1; pos->board[to]==EMPTY; to+=1) {}
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+16; pos->board[to]==EMPTY; to+=16) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            break;
        case QUEEN:
            for (to=from-17; pos->board[to]==EMPTY; to-=17) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from-16; pos->board[to]==EMPTY; to-=16) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from-15; pos->board[to]==EMPTY; to-=15) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from-1; pos->board[to]==EMPTY; to-=1) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+1; pos->board[to]==EMPTY; to+=1) {}
            if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+15; pos->board[to]==EMPTY; to+=15) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+16; pos->board[to]==EMPTY; to+=16) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            for (to=from+17; pos->board[to]==EMPTY; to+=17) {}
            if (can_capture(piece, pos->board[to])) {
                moves = add_move(pos, create_move(from, to, piece,
                            pos->board[to]), moves);
            }
            break;
        default: assert(false);
    }
    *moves_head = moves;
}
Exemple #4
0
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;
}
/*
 * 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);
}