From 0af9d9f480d837515a5bb352fcb30661353f045d Mon Sep 17 00:00:00 2001 From: ianfab Date: Sun, 24 Jun 2018 21:18:39 +0200 Subject: [PATCH] Support 3check/5check/nCheck ; initial development for crazyhouse --- src/position.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/position.h | 21 ++++++++++++++++++ src/psqt.cpp | 5 +++- src/types.h | 5 ++++ src/variant.cpp | 21 ++++++++++++++++++ src/variant.h | 2 + 6 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 286a989..841b8b9 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -37,7 +37,7 @@ using std::string; namespace PSQT { - extern Score psq[PIECE_NB][SQUARE_NB]; + extern Score psq[PIECE_NB][SQUARE_NB + 1]; } namespace Zobrist { @@ -46,6 +46,8 @@ namespace Zobrist { Key enpassant[FILE_NB]; Key castling[CASTLING_RIGHT_NB]; Key side, noPawns; + Key inHand[PIECE_NB][17]; + Key checks[COLOR_NB][CHECKS_NB]; } namespace { @@ -167,6 +169,15 @@ void Position::init() { Zobrist::side = rng.rand(); Zobrist::noPawns = rng.rand(); + for (Color c = WHITE; c <= BLACK; ++c) + for (int n = 0; n < CHECKS_NB; ++n) + Zobrist::checks[c][n] = rng.rand(); + + for (Color c = WHITE; c <= BLACK; ++c) + for (PieceType pt = KNIGHT; pt <= KING; ++pt) + for (int n = 0; n < 17; ++n) + Zobrist::inHand[make_piece(c, pt)][n] = rng.rand(); + // Prepare the cuckoo tables int count = 0; for (Color c = WHITE; c <= BLACK; ++c) @@ -313,6 +324,18 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, } } + // Check counter for nCheck + ss >> std::skipws >> token; + + if (max_check_count() && ss.peek() == '+') + { + st->checksGiven[WHITE] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0)); + ss >> token >> token; + st->checksGiven[BLACK] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0)); + } + else + ss.putback(token); + // 5-6. Halfmove clock and fullmove number ss >> std::skipws >> st->rule50 >> gamePly; @@ -394,6 +417,16 @@ void Position::set_state(StateInfo* si) const { si->key ^= Zobrist::psq[pc][s]; si->psq += PSQT::psq[pc][s]; } + // pieces in hand + if (piece_drops()) + { + for (Color c = WHITE; c <= BLACK; ++c) + for (PieceType pt = PAWN; pt <= KING; ++pt) + { + Piece pc = make_piece(c, pt); + si->psq += PSQT::psq[pc][SQ_NONE] * pieceCountInHand[color_of(pc)][type_of(pc)]; + } + } if (si->epSquare != SQ_NONE) si->key ^= Zobrist::enpassant[file_of(si->epSquare)]; @@ -418,7 +451,18 @@ void Position::set_state(StateInfo* si) const { for (int cnt = 0; cnt < pieceCount[pc]; ++cnt) si->materialKey ^= Zobrist::psq[pc][cnt]; + + if (piece_drops()) + { + if (type_of(pc) != PAWN && type_of(pc) != KING) + si->nonPawnMaterial[color_of(pc)] += pieceCountInHand[color_of(pc)][type_of(pc)] * PieceValue[MG][pc]; + si->key ^= Zobrist::inHand[pc][pieceCountInHand[color_of(pc)][type_of(pc)]]; + } } + + if (max_check_count()) + for (Color c = WHITE; c <= BLACK; ++c) + si->key ^= Zobrist::checks[c][si->checksGiven[c]]; } @@ -469,6 +513,16 @@ const string Position::fen() const { ss << '/'; } + // pieces in hand + if (piece_drops()) + { + ss << '['; + for (Color c = WHITE; c <= BLACK; ++c) + for (PieceType pt = PieceType(KING - 1); pt >= PAWN; --pt) + ss << std::string(pieceCountInHand[c][pt], piece_to_char()[make_piece(c, pt)]); + ss << ']'; + } + ss << (sideToMove == WHITE ? " w " : " b "); if (can_castle(WHITE_OO)) @@ -486,6 +540,10 @@ const string Position::fen() const { if (!can_castle(WHITE) && !can_castle(BLACK)) ss << '-'; + // check count + if (max_check_count()) + ss << " " << (max_check_count() - st->checksGiven[WHITE]) << "+" << (max_check_count() - st->checksGiven[BLACK]); + ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(ep_square()) + " ") << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2; @@ -771,6 +829,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us)); assert(type_of(captured) != KING); + if (max_check_count() && givesCheck) + k ^= Zobrist::checks[us][st->checksGiven[us]] ^ Zobrist::checks[us][++(st->checksGiven[us])]; + if (type_of(m) == CASTLING) { assert(pc == make_piece(us, KING)); diff --git a/src/position.h b/src/position.h index d978a97..1b8cbfe 100644 --- a/src/position.h +++ b/src/position.h @@ -44,6 +44,7 @@ struct StateInfo { int castlingRights; int rule50; int pliesFromNull; + CheckCount checksGiven[COLOR_NB]; Score psq; Square epSquare; @@ -92,6 +93,7 @@ public: bool castling_enabled() const; bool checking_permitted() const; bool must_capture() const; + bool piece_drops() const; // winning conditions Value stalemate_value(int ply = 0) const; Value checkmate_value(int ply = 0) const; @@ -99,6 +101,7 @@ public: bool bare_king_move() const; Bitboard capture_the_flag(Color c) const; bool flag_move() const; + CheckCount max_check_count() const; bool is_variant_end() const; bool is_variant_end(Value& result, int ply = 0) const; @@ -203,6 +206,8 @@ private: Bitboard byColorBB[COLOR_NB]; int pieceCount[PIECE_NB]; Square pieceList[PIECE_NB][16]; + int pieceCountInHand[COLOR_NB][PIECE_TYPE_NB]; + Bitboard promotedPieces; int index[SQUARE_NB]; int castlingRightsMask[SQUARE_NB]; Square castlingRookSquare[CASTLING_RIGHT_NB]; @@ -257,6 +262,11 @@ inline bool Position::must_capture() const { return var->mustCapture; } +inline bool Position::piece_drops() const { + assert(var != nullptr); + return var->pieceDrops; +} + inline Value Position::stalemate_value(int ply) const { assert(var != nullptr); Value v = var->stalemateValue; @@ -296,6 +306,11 @@ inline bool Position::flag_move() const { return var->flagMove; } +inline CheckCount Position::max_check_count() const { + assert(var != nullptr); + return var->maxCheckCount; +} + inline bool Position::is_variant_end() const { Value result; return is_variant_end(result); @@ -328,6 +343,12 @@ inline bool Position::is_variant_end(Value& result, int ply) const { result = mate_in(ply); return true; } + // nCheck + if (max_check_count() && st->checksGiven[~sideToMove] == max_check_count()) + { + result = mated_in(ply); + return true; + } return false; } diff --git a/src/psqt.cpp b/src/psqt.cpp index 86593c1..c921636 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -102,7 +102,7 @@ constexpr Score Bonus[PIECE_TYPE_NB][RANK_NB][int(FILE_NB) / 2] = { #undef S -Score psq[PIECE_NB][SQUARE_NB]; +Score psq[PIECE_NB][SQUARE_NB + 1]; // init() initializes piece-square tables: the white halves of the tables are // copied from Bonus[] adding the piece value, then the black halves of the @@ -124,6 +124,9 @@ void init() { psq[ pc][ s] = score + Bonus[pc][rank_of(s)][f]; psq[~pc][~s] = -psq[pc][s]; } + // pieces in pocket + psq[ pc][SQ_NONE] = score; + psq[~pc][SQ_NONE] = -psq[pc][SQ_NONE]; } } diff --git a/src/types.h b/src/types.h index 0003e17..dd9914b 100644 --- a/src/types.h +++ b/src/types.h @@ -154,6 +154,10 @@ template struct MakeCastling { : S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO; }; +enum CheckCount : int { + CHECKS_0 = 0, CHECKS_NB = 11 +}; + enum Phase { PHASE_ENDGAME, PHASE_MIDGAME = 128, @@ -316,6 +320,7 @@ inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \ inline T& operator/=(T& d, int i) { return d = T(int(d) / i); } ENABLE_FULL_OPERATORS_ON(Value) +ENABLE_FULL_OPERATORS_ON(CheckCount) ENABLE_FULL_OPERATORS_ON(Depth) ENABLE_FULL_OPERATORS_ON(Direction) diff --git a/src/variant.cpp b/src/variant.cpp index ca6aa68..f04201f 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -139,6 +139,24 @@ void VariantMap::init() { v->mustCapture = true; return v; } (); + const Variant* threecheck = [&]{ + Variant* v = new Variant(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+3 0 1"; + v->maxCheckCount = CheckCount(3); + return v; + } (); + const Variant* fivecheck = [&]{ + Variant* v = new Variant(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 5+5 0 1"; + v->maxCheckCount = CheckCount(5); + return v; + } (); + const Variant* crazyhouse = [&]{ + Variant* v = new Variant(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[] w KQkq - 0 1"; + v->pieceDrops = true; + return v; + } (); insert(std::pair(std::string("chess"), chess)); insert(std::pair(std::string("makruk"), makruk)); insert(std::pair(std::string("asean"), asean)); @@ -149,6 +167,9 @@ void VariantMap::init() { insert(std::pair(std::string("kingofthehill"), kingofthehill)); insert(std::pair(std::string("racingkings"), racingkings)); insert(std::pair(std::string("losers"), losers)); + insert(std::pair(std::string("3check"), threecheck)); + insert(std::pair(std::string("5check"), fivecheck)); + //insert(std::pair(std::string("crazyhouse"), crazyhouse)); } void VariantMap::clear_all() { diff --git a/src/variant.h b/src/variant.h index 0ed3cb5..160398d 100644 --- a/src/variant.h +++ b/src/variant.h @@ -41,6 +41,7 @@ struct Variant { bool castling = true; bool checking = true; bool mustCapture = false; + bool pieceDrops = false; // game end Value stalemateValue = VALUE_DRAW; Value checkmateValue = -VALUE_MATE; @@ -49,6 +50,7 @@ struct Variant { Bitboard whiteFlag = 0; Bitboard blackFlag = 0; bool flagMove = false; + CheckCount maxCheckCount = CheckCount(0); void set_piece(PieceType pt, char c) { pieceToChar[make_piece(WHITE, pt)] = toupper(c); -- 1.7.0.4