X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmovegen.cpp;h=866f4d0705a880e80cf15803dae671809c1328d2;hb=b36900ef44044e9ab96637c9da7a4d7ea5b055d9;hp=4b36360c56ae7a13c67178e14d495b320897b531;hpb=7a68916ff992115d8013e7ce31850aec558d8ac5;p=stockfish diff --git a/src/movegen.cpp b/src/movegen.cpp index 4b36360c..866f4d07 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2009 Marco Costalba + Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -140,6 +140,32 @@ MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) { } +/// generate_non_evasions() generates all pseudo-legal captures and +/// non-captures. Returns a pointer to the end of the move list. + +MoveStack* generate_non_evasions(const Position& pos, MoveStack* mlist) { + + assert(pos.is_ok()); + assert(!pos.is_check()); + + Color us = pos.side_to_move(); + Bitboard target = pos.pieces_of_color(opposite_color(us)); + + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, pos.empty_squares()); + + target |= pos.empty_squares(); + + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_castle_moves(pos, mlist); + return generate_castle_moves(pos, mlist); +} + + /// generate_non_capture_checks() generates all pseudo-legal non-captures and knight /// underpromotions that give check. Returns a pointer to the end of the move list. @@ -260,11 +286,8 @@ MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLega Bitboard pinned = pos.pinned_pieces(pos.side_to_move()); // Generate pseudo-legal moves - if (pos.is_check()) - last = generate_evasions(pos, mlist); - else - last = generate_noncaptures(pos, generate_captures(pos, mlist)); - + last = pos.is_check() ? generate_evasions(pos, mlist) + : generate_non_evasions(pos, mlist); if (pseudoLegal) return last; @@ -285,7 +308,7 @@ MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLega bool move_is_legal(const Position& pos, const Move m) { - MoveStack mlist[256]; + MoveStack mlist[MOVES_MAX]; MoveStack *cur, *last = generate_moves(pos, mlist, true); for (cur = mlist; cur != last; cur++) @@ -312,7 +335,7 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { Piece pc = pos.piece_on(from); // Use a slower but simpler function for uncommon cases - if (move_is_ep(m) || move_is_castle(m)) + if (move_is_special(m)) return move_is_legal(pos, m); // If the from square is not occupied by a piece belonging to the side to @@ -332,10 +355,9 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { if ((us == WHITE) != (direction > 0)) return false; - // A pawn move is a promotion iff the destination square is - // on the 8/1th rank. - if (( (square_rank(to) == RANK_8 && us == WHITE) - ||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m))) + // We have already handled promotion moves, so destination + // cannot be on the 8/1th rank. + if (square_rank(to) == RANK_8 || square_rank(to) == RANK_1) return false; // Proceed according to the square delta between the origin and @@ -382,14 +404,12 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { default: return false; } - // The move is pseudo-legal, check if it is also legal - return pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned); } + else if (!bit_is_set(pos.attacks_from(pc, from), to)) + return false; - // Luckly we can handle all the other pieces in one go - return bit_is_set(pos.attacks_from(pc, from), to) - && (pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned)) - && !move_is_promotion(m); + // The move is pseudo-legal, check if it is also legal + return pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned); } @@ -402,10 +422,13 @@ namespace { Square from; const Square* ptr = pos.piece_list_begin(us, Piece); - while ((from = *ptr++) != SQ_NONE) + if (*ptr != SQ_NONE) { - b = pos.attacks_from(from) & target; - SERIALIZE_MOVES(b); + do { + from = *ptr; + b = pos.attacks_from(from) & target; + SERIALIZE_MOVES(b); + } while (*++ptr != SQ_NONE); } return mlist; } @@ -421,34 +444,26 @@ namespace { return mlist; } - template + template inline Bitboard move_pawns(Bitboard p) { - if (Direction == DELTA_N) - return Us == WHITE ? p << 8 : p >> 8; - else if (Direction == DELTA_NE) - return Us == WHITE ? p << 9 : p >> 7; - else if (Direction == DELTA_NW) - return Us == WHITE ? p << 7 : p >> 9; - else - return p; + return Delta == DELTA_N ? p << 8 : Delta == DELTA_S ? p >> 8 : + Delta == DELTA_NE ? p << 9 : Delta == DELTA_SE ? p >> 7 : + Delta == DELTA_NW ? p << 7 : Delta == DELTA_SW ? p >> 9 : p; } - template - inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces) { + template + inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) { // Calculate our parametrized parameters at compile time const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); - const Bitboard TFileABB = (Diagonal == DELTA_NE ? FileABB : FileHBB); - const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE); - const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW); - const SquareDelta TTDELTA_NE = (Diagonal == DELTA_NE ? TDELTA_NE : TDELTA_NW); + const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB); Bitboard b1, b2; Square to; // Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black) - b1 = move_pawns(pawns) & ~TFileABB & enemyPieces; + b1 = move_pawns(pawns) & ~TFileABB & target; // Capturing promotions and under-promotions if (b1 & TRank8BB) @@ -460,26 +475,26 @@ namespace { to = pop_1st_bit(&b2); if (Type == CAPTURE || Type == EVASION) - (*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, QUEEN); + (*mlist++).move = make_promotion_move(to - Delta, to, QUEEN); if (Type == NON_CAPTURE || Type == EVASION) { - (*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, ROOK); - (*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, BISHOP); - (*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, KNIGHT); + (*mlist++).move = make_promotion_move(to - Delta, to, ROOK); + (*mlist++).move = make_promotion_move(to - Delta, to, BISHOP); + (*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); } // This is the only possible under promotion that can give a check // not already included in the queen-promotion. It is not sure that // the promoted knight will give check, but it doesn't worth to verify. if (Type == CHECK) - (*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, KNIGHT); + (*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); } } // Serialize standard captures if (Type == CAPTURE || Type == EVASION) - SERIALIZE_MOVES_D(b1, -TTDELTA_NE); + SERIALIZE_MOVES_D(b1, -Delta); return mlist; } @@ -492,7 +507,9 @@ namespace { const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); - const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S); + const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S); + const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE); + const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW); Square to; Bitboard b1, b2, enemyPieces, emptySquares; @@ -506,14 +523,14 @@ namespace { if (Type == EVASION) enemyPieces &= target; // Capture only the checker piece - mlist = generate_pawn_captures(mlist, pawns, enemyPieces); - mlist = generate_pawn_captures(mlist, pawns, enemyPieces); + mlist = generate_pawn_captures(mlist, pawns, enemyPieces); + mlist = generate_pawn_captures(mlist, pawns, enemyPieces); } // Non-capturing promotions and underpromotions if (pawns & TRank7BB) { - b1 = move_pawns(pawns) & TRank8BB & pos.empty_squares(); + b1 = move_pawns(pawns) & TRank8BB & pos.empty_squares(); if (Type == EVASION) b1 &= target; // Only blocking promotion pushes @@ -545,8 +562,8 @@ namespace { emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares()); // Single and double pawn pushes - b1 = move_pawns(pawns) & emptySquares & ~TRank8BB; - b2 = move_pawns(b1 & TRank3BB) & emptySquares; + b1 = move_pawns(pawns) & emptySquares & ~TRank8BB; + b2 = move_pawns(b1 & TRank3BB) & emptySquares; // Filter out unwanted pushes according to the move type if (Type == EVASION) @@ -565,8 +582,8 @@ namespace { // don't generate captures. if (pawns & target) // For CHECK type target is dc bitboard { - Bitboard dc1 = move_pawns(pawns & target & ~file_bb(ksq)) & emptySquares & ~TRank8BB; - Bitboard dc2 = move_pawns(dc1 & TRank3BB) & emptySquares; + Bitboard dc1 = move_pawns(pawns & target & ~file_bb(ksq)) & emptySquares & ~TRank8BB; + Bitboard dc2 = move_pawns(dc1 & TRank3BB) & emptySquares; b1 |= dc1; b2 |= dc2;