{ 15, 17 }, // shogi knight
{ -1, 1, 15, 17 }, // euroshogi knight
{ -8, -1, 1, 7, 8, 9 }, // gold
+ { -8, -1, 1, 8 }, // horse
{ -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner
{ -9, -8, -7, -1, 1, 7, 8, 9 } // king
};
{ 15, 17 }, // shogi knight
{ -1, 1, 15, 17 }, // euroshogi knight
{ -8, -1, 1, 7, 8, 9 }, // gold
+ { -8, -1, 1, 8 }, // horse
{ -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner
{ -9, -8, -7, -1, 1, 7, 8, 9 } // king
};
{}, // shogi knight
{}, // euroshogi knight
{}, // gold
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse
{}, // commoner
{} // king
};
{}, // shogi knight
{}, // euroshogi knight
{}, // gold
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse
{}, // commoner
{} // king
};
0, // shogi knight
0, // euroshogi knight
0, // gold
+ 7, // horse
0, // commoner
0 // king
};
0, // shogi knight
0, // euroshogi knight
0, // gold
+ 7, // horse
0, // commoner
0 // king
};
/// in front of and on the given relative rank, from the point of view of the given color.
/// For instance, promotion_zone_bb(BLACK, RANK_7) will return the 16 squares on ranks 1 and 2.
-inline Bitboard promotion_zone_bb(Color c, Rank r) {
- return ForwardRanksBB[c][relative_rank(c, r)] | rank_bb(relative_rank(c, r));
+inline Bitboard promotion_zone_bb(Color c, Rank r, Rank maxRank) {
+ return ForwardRanksBB[c][relative_rank(c, r, maxRank)] | rank_bb(relative_rank(c, r, maxRank));
}
{
if (pt == PAWN)
{
- b &= ~promotion_zone_bb(Us, pos.promotion_rank());
+ b &= ~promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank());
if (!pos.first_rank_drops())
b &= ~rank_bb(relative_rank(Us, RANK_1, pos.max_rank()));
}
+ if (pt == SHOGI_PAWN)
+ for (File f = FILE_A; f <= pos.max_file(); ++f)
+ if (file_bb(f) & pos.pieces(Us, pt))
+ b &= ~file_bb(f);
if (Checks)
b &= pos.check_squares(pt);
while (b)
b &= pos.check_squares(pt);
while (b)
- *moveList++ = make_move(from, pop_lsb(&b));
+ {
+ Square s = pop_lsb(&b);
+ bool piece_promotion = pos.promoted_piece_type(pt) != NO_PIECE_TYPE
+ && (promotion_zone_bb(us, pos.promotion_rank(), pos.max_rank()) & (SquareBB[from] | s));
+ if (!piece_promotion || !pos.mandatory_piece_promotion())
+ *moveList++ = make_move(from, s);
+ // Shogi-style piece promotions
+ if (piece_promotion)
+ *moveList++ = make<PIECE_PROMOTION>(from, s);
+ }
}
return moveList;
// illegal drops
if (piece_drops() && type_of(m) == DROP)
- return pieceCountInHand[us][type_of(moved_piece(m))] && empty(to_sq(m));
+ return pieceCountInHand[us][type_of(moved_piece(m))] && empty(to_sq(m)) && moves_bb(us, type_of(moved_piece(m)), to, 0);
// game end
if (is_variant_end())
return false;
// Is there a direct check?
- if (st->checkSquares[type_of(moved_piece(m))] & to)
+ if (type_of(m) != PROMOTION && type_of(m) != PIECE_PROMOTION && (st->checkSquares[type_of(moved_piece(m))] & to))
return true;
// Is there a discovered check?
case PROMOTION:
return attacks_bb(sideToMove, promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
+ case PIECE_PROMOTION:
+ return attacks_bb(sideToMove, promoted_piece_type(type_of(moved_piece(m))), to, pieces() ^ from) & square<KING>(~sideToMove);
+
// En passant capture with check? We have already handled the case
// of direct checks and ordinary discovered check, so the only case we
// need to handle is the unusual case of a discovered check through
Square to = to_sq(m);
Piece pc = moved_piece(m);
Piece captured = type_of(m) == ENPASSANT ? make_piece(them, PAWN) : piece_on(to);
+ Piece unpromotedCaptured = unpromoted_piece_on(to);
assert(color_of(pc) == us);
assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
if (captures_to_hand())
{
st->capturedpromoted = is_promoted(to);
- Piece pieceToHand = is_promoted(to) ? make_piece(~color_of(captured), PAWN) : ~captured;
+ Piece pieceToHand = !is_promoted(to) ? ~captured
+ : unpromotedCaptured ? ~unpromotedCaptured
+ : make_piece(~color_of(captured), PAWN);
add_to_hand(color_of(pieceToHand), type_of(pieceToHand));
st->psq += PSQT::psq[pieceToHand][SQ_NONE];
k ^= Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)] - 1]
^ Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)]];
promotedPieces -= to;
}
+ unpromotedBoard[to] = NO_PIECE;
// Update material hash key and prefetch access to materialTable
k ^= Zobrist::psq[captured][capsq];
// Reset rule 50 draw counter
st->rule50 = 0;
}
+ else if (type_of(m) == PIECE_PROMOTION)
+ {
+ Piece promotion = make_piece(us, promoted_piece_type(type_of(pc)));
+
+ remove_piece(pc, to);
+ put_piece(promotion, to);
+ promotedPieces |= to;
+ unpromotedBoard[to] = pc;
+
+ // Update hash keys
+ k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
+ st->materialKey ^= Zobrist::psq[promotion][pieceCount[promotion]-1]
+ ^ Zobrist::psq[pc][pieceCount[pc]];
+
+ // Update incremental score
+ st->psq += PSQT::psq[promotion][to] - PSQT::psq[pc][to];
+
+ // Update material
+ st->nonPawnMaterial[us] += PieceValue[MG][promotion] - PieceValue[MG][pc];
+ }
// Update incremental scores
st->psq += PSQT::psq[pc][to] - PSQT::psq[pc][from];
// Set capture piece
st->capturedPiece = captured;
+ st->unpromotedCapturedPiece = captured ? unpromotedCaptured : NO_PIECE;
if (captures_to_hand() && !captured)
st->capturedpromoted = false;
// Calculate checkers bitboard (if move gives check)
st->checkersBB = givesCheck ? attackers_to(square<KING>(them)) & pieces(us) : 0;
+ // Update information about promoted pieces
if (type_of(m) != DROP && is_promoted(from))
promotedPieces = (promotedPieces - from) | to;
+ if (type_of(m) != DROP && unpromoted_piece_on(from))
+ {
+ unpromotedBoard[to] = unpromotedBoard[from];
+ unpromotedBoard[from] = NO_PIECE;
+ }
+
sideToMove = ~sideToMove;
// Update king attacks used for fast check detection
if (captures_to_hand() && !drop_loop())
promotedPieces -= to;
}
+ else if (type_of(m) == PIECE_PROMOTION)
+ {
+ remove_piece(pc, to);
+ pc = unpromoted_piece_on(to);
+ put_piece(pc, to);
+ unpromotedBoard[to] = NO_PIECE;
+ promotedPieces -= to;
+ }
if (type_of(m) == CASTLING)
{
move_piece(pc, to, from); // Put the piece back at the source square
if (captures_to_hand() && !drop_loop() && is_promoted(to))
promotedPieces = (promotedPieces - to) | from;
+ if (unpromoted_piece_on(to))
+ {
+ unpromotedBoard[from] = unpromotedBoard[to];
+ unpromotedBoard[to] = NO_PIECE;
+ }
if (st->capturedPiece)
{
if (captures_to_hand())
{
remove_from_hand(~color_of(st->capturedPiece),
- !drop_loop() && st->capturedpromoted ? PAWN : type_of(st->capturedPiece));
+ !drop_loop() && st->capturedpromoted ? (st->unpromotedCapturedPiece ? type_of(st->unpromotedCapturedPiece)
+ : PAWN)
+ : type_of(st->capturedPiece));
if (!drop_loop() && st->capturedpromoted)
promotedPieces |= to;
}
+ if (st->unpromotedCapturedPiece)
+ unpromotedBoard[to] = st->unpromotedCapturedPiece;
}
}
Key key;
Bitboard checkersBB;
Piece capturedPiece;
+ Piece unpromotedCapturedPiece;
StateInfo* previous;
Bitboard blockersForKing[COLOR_NB];
Bitboard pinners[COLOR_NB];
const std::string piece_to_char() const;
Rank promotion_rank() const;
const std::set<PieceType, std::greater<PieceType> >& promotion_piece_types() const;
+ PieceType promoted_piece_type(PieceType pt) const;
+ bool mandatory_piece_promotion() const;
bool endgame_eval() const;
bool double_step_enabled() const;
bool castling_enabled() const;
Bitboard pieces(Color c, PieceType pt) const;
Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
Piece piece_on(Square s) const;
+ Piece unpromoted_piece_on(Square s) const;
Square ep_square() const;
bool empty(Square s) const;
int count(Color c, PieceType pt) const;
// Data members
Piece board[SQUARE_NB];
+ Piece unpromotedBoard[SQUARE_NB];
Bitboard byTypeBB[PIECE_TYPE_NB];
Bitboard byColorBB[COLOR_NB];
int pieceCount[PIECE_NB];
return var->promotionPieceTypes;
}
+inline PieceType Position::promoted_piece_type(PieceType pt) const {
+ assert(var != nullptr);
+ return var->promotedPieceType[pt];
+}
+
+inline bool Position::mandatory_piece_promotion() const {
+ assert(var != nullptr);
+ return var->mandatoryPiecePromotion;
+}
+
inline bool Position::endgame_eval() const {
assert(var != nullptr);
return var->endgameEval;
return board[s];
}
+inline Piece Position::unpromoted_piece_on(Square s) const {
+ return unpromotedBoard[s];
+}
+
inline Piece Position::moved_piece(Move m) const {
if (type_of(m) == DROP)
return make_piece(sideToMove, dropped_piece_type(m));
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg,
FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg, ChancellorValueMg,
AmazonValueMg, KnibisValueMg, BiskniValueMg,
- ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg,
+ ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, HorseValueMg,
CommonerValueMg },
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg, ChancellorValueEg,
AmazonValueEg, KnibisValueMg, BiskniValueMg,
- ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg,
+ ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, HorseValueEg,
CommonerValueEg }
};
PROMOTION_LEFT = 4 << 12,
PROMOTION_RIGHT = 5 << 12,
DROP = 6 << 12,
+ PIECE_PROMOTION = 7 << 12,
};
enum Color {
AlfilValueMg = 300, AlfilValueEg = 300,
SilverValueMg = 600, SilverValueEg = 600,
AiwokValueMg = 2500, AiwokValueEg = 2500,
- BersValueMg = 2500, BersValueEg = 2500,
+ BersValueMg = 2000, BersValueEg = 2000,
ChancellorValueMg = 2500, ChancellorValueEg = 2500,
AmazonValueMg = 3000, AmazonValueEg = 3000,
KnibisValueMg = 800, KnibisValueEg = 800,
ShogiKnightValueMg = 300, ShogiKnightValueEg = 300,
EuroShogiKnightValueMg = 400, EuroShogiKnightValueEg = 400,
GoldValueMg = 600, GoldValueEg = 600,
+ HorseValueMg = 1500, HorseValueEg = 1500,
CommonerValueMg = 600, CommonerValueEg = 600,
MidgameLimit = 15258, EndgameLimit = 3915
enum PieceType {
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK,
QUEEN, FERS, MET = FERS, ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS, CHANCELLOR,
- AMAZON, KNIBIS, BISKNI, SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, COMMONER, KING,
+ AMAZON, KNIBIS, BISKNI, SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, HORSE, COMMONER, KING,
ALL_PIECES = 0,
PIECE_TYPE_NB = 1 << PIECE_TYPE_BITS
if (type_of(m) == PROMOTION)
move += pos.piece_to_char()[make_piece(BLACK, promotion_type(m))];
+ if (type_of(m) == PIECE_PROMOTION)
+ move += '+';
+
return move;
}
v->add_piece(EUROSHOGI_KNIGHT, 'n');
v->add_piece(GOLD, 'g');
v->add_piece(BISHOP, 'b');
+ v->add_piece(HORSE, 'h');
v->add_piece(ROOK, 'r');
v->add_piece(KING, 'k');
+ v->add_piece(DRAGON, 'd');
v->startFen = "1nbgkgn1/1r4b1/pppppppp/8/8/PPPPPPPP/1B4R1/1NGKGBN1[-] w 0 1";
v->pieceDrops = true;
v->capturesToHand = true;
v->promotionPieceTypes = {};
v->doubleStep = false;
v->castling = false;
- // TODO: piece promotions, illegal pawn drops
+ v->promotedPieceType[SHOGI_PAWN] = GOLD;
+ v->promotedPieceType[EUROSHOGI_KNIGHT] = GOLD;
+ v->promotedPieceType[SILVER] = GOLD;
+ v->promotedPieceType[BISHOP] = HORSE;
+ v->promotedPieceType[ROOK] = DRAGON;
+ v->mandatoryPiecePromotion = true;
return v;
} ();
const Variant* minishogi = [&]{
v->add_piece(SILVER, 's');
v->add_piece(GOLD, 'g');
v->add_piece(BISHOP, 'b');
+ v->add_piece(HORSE, 'h');
v->add_piece(ROOK, 'r');
+ v->add_piece(DRAGON, 'd');
v->add_piece(KING, 'k');
v->startFen = "rbsgk/4p/5/P4/KGSBR[-] w 0 1";
v->pieceDrops = true;
v->promotionPieceTypes = {};
v->doubleStep = false;
v->castling = false;
- // TODO: piece promotions, illegal pawn drops
+ v->promotedPieceType[SHOGI_PAWN] = GOLD;
+ v->promotedPieceType[SILVER] = GOLD;
+ v->promotedPieceType[BISHOP] = HORSE;
+ v->promotedPieceType[ROOK] = DRAGON;
return v;
} ();
const Variant* losalamos = [&]{
std::string startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
Rank promotionRank = RANK_8;
std::set<PieceType, std::greater<PieceType> > promotionPieceTypes = { QUEEN, ROOK, BISHOP, KNIGHT };
+ PieceType promotedPieceType[PIECE_TYPE_NB] = {};
+ bool mandatoryPiecePromotion = false;
bool endgameEval = false;
bool doubleStep = true;
bool castling = true;