using std::string;
namespace PSQT {
- extern Score psq[PIECE_NB][SQUARE_NB];
+ extern Score psq[PIECE_NB][SQUARE_NB + 1];
}
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 {
Zobrist::side = rng.rand<Key>();
Zobrist::noPawns = rng.rand<Key>();
+ for (Color c = WHITE; c <= BLACK; ++c)
+ for (int n = 0; n < CHECKS_NB; ++n)
+ Zobrist::checks[c][n] = rng.rand<Key>();
+
+ 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<Key>();
+
// Prepare the cuckoo tables
int count = 0;
for (Color c = WHITE; c <= BLACK; ++c)
}
}
+ // 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;
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)];
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]];
}
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))
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;
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));
int castlingRights;
int rule50;
int pliesFromNull;
+ CheckCount checksGiven[COLOR_NB];
Score psq;
Square epSquare;
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;
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;
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];
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;
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);
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;
}
#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
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];
}
}
: S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
};
+enum CheckCount : int {
+ CHECKS_0 = 0, CHECKS_NB = 11
+};
+
enum Phase {
PHASE_ENDGAME,
PHASE_MIDGAME = 128,
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)
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, const Variant*>(std::string("chess"), chess));
insert(std::pair<std::string, const Variant*>(std::string("makruk"), makruk));
insert(std::pair<std::string, const Variant*>(std::string("asean"), asean));
insert(std::pair<std::string, const Variant*>(std::string("kingofthehill"), kingofthehill));
insert(std::pair<std::string, const Variant*>(std::string("racingkings"), racingkings));
insert(std::pair<std::string, const Variant*>(std::string("losers"), losers));
+ insert(std::pair<std::string, const Variant*>(std::string("3check"), threecheck));
+ insert(std::pair<std::string, const Variant*>(std::string("5check"), fivecheck));
+ //insert(std::pair<std::string, const Variant*>(std::string("crazyhouse"), crazyhouse));
}
void VariantMap::clear_all() {
bool castling = true;
bool checking = true;
bool mustCapture = false;
+ bool pieceDrops = false;
// game end
Value stalemateValue = VALUE_DRAW;
Value checkmateValue = -VALUE_MATE;
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);