From cbd2b1fc4fbfd07932b4a511be0d520986b14d8a Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Sat, 29 Sep 2018 23:27:55 +0200 Subject: [PATCH] Support capablanca chess (#6) Generalize castling and add archbishop to support capablanca chess. bench: 4636755 --- src/bitboard.cpp | 8 ++++++++ src/movegen.cpp | 5 +++-- src/position.cpp | 13 +++++++------ src/position.h | 12 ++++++++++++ src/psqt.cpp | 8 ++++---- src/types.h | 10 ++++++---- src/uci.cpp | 2 +- src/variant.cpp | 13 +++++++++++++ src/variant.h | 2 ++ 9 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 7ba1783..94cf477 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -431,6 +431,8 @@ void Bitboards::init() { NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon @@ -464,6 +466,8 @@ void Bitboards::init() { NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon @@ -494,6 +498,7 @@ void Bitboards::init() { {}, // silver/khon { NORTH, EAST, SOUTH, WEST }, // aiwok { NORTH, EAST, SOUTH, WEST }, // bers/dragon + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop { NORTH, EAST, SOUTH, WEST }, // chancellor { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // knibis @@ -522,6 +527,7 @@ void Bitboards::init() { {}, // silver/khon { NORTH, EAST, SOUTH, WEST }, // aiwok { NORTH, EAST, SOUTH, WEST }, // bers/dragon + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop { NORTH, EAST, SOUTH, WEST }, // chancellor { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon {}, // knibis @@ -550,6 +556,7 @@ void Bitboards::init() { 0, // silver/khon FILE_MAX, // aiwok FILE_MAX, // bers/dragon + FILE_MAX, // archbishop FILE_MAX, // chancellor FILE_MAX, // amazon FILE_MAX, // knibis @@ -578,6 +585,7 @@ void Bitboards::init() { 0, // silver/khon FILE_MAX, // aiwok FILE_MAX, // bers/dragon + FILE_MAX, // archbishop FILE_MAX, // chancellor FILE_MAX, // amazon 0, // knibis diff --git a/src/movegen.cpp b/src/movegen.cpp index f9ccf24..6bbdb66 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -35,9 +35,10 @@ namespace { // After castling, the rook and king final positions are the same in Chess960 // as they would be in standard chess. - Square kfrom = pos.count(us) ? pos.square(us) : make_square(FILE_E, us == WHITE ? RANK_1 : RANK_8); + Square kfrom = pos.count(us) ? pos.square(us) : make_square(FILE_E, relative_rank(us, RANK_1, pos.max_rank())); Square rfrom = pos.castling_rook_square(Cr); - Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1); + Square kto = make_square(KingSide ? pos.castling_kingside_file() : pos.castling_queenside_file(), + relative_rank(us, RANK_1, pos.max_rank())); Bitboard enemies = pos.pieces(~us); assert(!pos.checkers()); diff --git a/src/position.cpp b/src/position.cpp index eef10b2..00b878e 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -358,13 +358,13 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, token = char(toupper(token)); if (token == 'K') - for (rsq = relative_square(c, SQ_H1); piece_on(rsq) != rook; --rsq) {} + for (rsq = make_square(FILE_MAX, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; --rsq) {} else if (token == 'Q') - for (rsq = relative_square(c, SQ_A1); piece_on(rsq) != rook; ++rsq) {} + for (rsq = make_square(FILE_A, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; ++rsq) {} - else if (token >= 'A' && token <= 'H') - rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1)); + else if (token >= 'A' && token <= 'A' + max_file()) + rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1, max_rank())); else continue; @@ -1258,8 +1258,9 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ bool kingSide = to > from; rfrom = to; // Castling is encoded as "king captures friendly rook" - rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1); - to = relative_square(us, kingSide ? SQ_G1 : SQ_C1); + to = make_square(kingSide ? castling_kingside_file() : castling_queenside_file(), + us == WHITE ? RANK_1 : max_rank()); + rto = to + (kingSide ? WEST : EAST); // Remove both pieces first since squares could overlap in Chess960 Piece castling_piece = piece_on(Do ? from : to); diff --git a/src/position.h b/src/position.h index 04f5bb9..ea06a38 100644 --- a/src/position.h +++ b/src/position.h @@ -103,6 +103,8 @@ public: bool double_step_enabled() const; bool first_rank_double_steps() const; bool castling_enabled() const; + File castling_kingside_file() const; + File castling_queenside_file() const; bool checking_permitted() const; bool must_capture() const; bool piece_drops() const; @@ -327,6 +329,16 @@ inline bool Position::castling_enabled() const { return var->castling; } +inline File Position::castling_kingside_file() const { + assert(var != nullptr); + return var->castlingKingsideFile; +} + +inline File Position::castling_queenside_file() const { + assert(var != nullptr); + return var->castlingQueensideFile; +} + inline bool Position::checking_permitted() const { assert(var != nullptr); return var->checking; diff --git a/src/psqt.cpp b/src/psqt.cpp index 3fef593..13a0796 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -24,13 +24,13 @@ Value PieceValue[PHASE_NB][PIECE_NB] = { { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, - FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg, ChancellorValueMg, - AmazonValueMg, KnibisValueMg, BiskniValueMg, + FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg, + ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg, ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, HorseValueMg, ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg, CommonerValueMg }, { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, - FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg, ChancellorValueEg, - AmazonValueEg, KnibisValueMg, BiskniValueMg, + FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg, + ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg, ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, HorseValueEg, ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg, CommonerValueEg } }; diff --git a/src/types.h b/src/types.h index d9818a5..634553b 100644 --- a/src/types.h +++ b/src/types.h @@ -208,7 +208,8 @@ enum Value : int { SilverValueMg = 600, SilverValueEg = 600, AiwokValueMg = 2500, AiwokValueEg = 2500, BersValueMg = 2000, BersValueEg = 2000, - ChancellorValueMg = 2500, ChancellorValueEg = 2500, + ArchbishopValueMg = 2000, ArchbishopValueEg = 2000, + ChancellorValueMg = 2300, ChancellorValueEg = 2300, AmazonValueMg = 3000, AmazonValueEg = 3000, KnibisValueMg = 800, KnibisValueEg = 800, BiskniValueMg = 800, BiskniValueEg = 800, @@ -229,9 +230,10 @@ enum Value : int { const int PIECE_TYPE_BITS = 5; // PIECE_TYPE_NB = pow(2, PIECE_TYPE_BITS) 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, HORSE, + NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, + FERS, MET = FERS, ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS, + ARCHBISHOP, CHANCELLOR, AMAZON, KNIBIS, BISKNI, + SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, HORSE, CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, COMMONER, KING, ALL_PIECES = 0, diff --git a/src/uci.cpp b/src/uci.cpp index 6ae8105..e1a9238 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -307,7 +307,7 @@ string UCI::move(const Position& pos, Move m) { return "0000"; if (type_of(m) == CASTLING && !pos.is_chess960()) - to = make_square(to > from ? FILE_G : FILE_C, rank_of(from)); + to = make_square(to > from ? pos.castling_kingside_file() : pos.castling_queenside_file(), rank_of(from)); string move = (type_of(m) == DROP ? std::string{pos.piece_to_char()[type_of(pos.moved_piece(m))], Options["Protocol"] == "usi" ? '*' : '@'} diff --git a/src/variant.cpp b/src/variant.cpp index 90f3c49..0d2325b 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -465,6 +465,18 @@ void VariantMap::init() { v->shogiPawnDropMateIllegal = true; return v; } (); + const Variant* capablanca = [&]{ + Variant* v = new Variant(); + v->maxRank = RANK_8; + v->maxFile = FILE_J; + v->castlingKingsideFile = FILE_I; + v->castlingQueensideFile = FILE_C; + v->add_piece(ARCHBISHOP, 'a'); + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR w KQkq - 0 1"; + v->promotionPieceTypes = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } (); #endif // Add to UCI_Variant option @@ -504,6 +516,7 @@ void VariantMap::init() { add("tictactoe", tictactoe); #ifdef LARGEBOARDS add("shogi", shogi); + add("capablanca", capablanca); #endif } diff --git a/src/variant.h b/src/variant.h index baf9d66..eda559c 100644 --- a/src/variant.h +++ b/src/variant.h @@ -46,6 +46,8 @@ struct Variant { bool doubleStep = true; bool firstRankDoubleSteps = false; bool castling = true; + File castlingKingsideFile = FILE_G; + File castlingQueensideFile = FILE_C; bool checking = true; bool mustCapture = false; bool pieceDrops = false; -- 1.7.0.4