Value Evaluation<T>::value() {
assert(!pos.checkers());
+ assert(!pos.is_variant_end());
// Probe the material hash table
me = Material::probe(pos);
template<>
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
- Color us = pos.side_to_move();
- Bitboard pinned = pos.blockers_for_king(us) & pos.pieces(us);
- Square ksq = pos.square<KING>(us);
+ if (pos.is_variant_end())
+ return moveList;
+
ExtMove* cur = moveList;
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
: generate<NON_EVASIONS>(pos, moveList);
while (cur != moveList)
- if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT)
- && !pos.legal(*cur))
+ if (!pos.legal(*cur))
*cur = (--moveList)->move;
else
++cur;
assert(color_of(moved_piece(m)) == us);
assert(piece_on(square<KING>(us)) == make_piece(us, KING));
+ // illegal checks
+ if (!checking_permitted() && gives_check(m))
+ return false;
+
+ // illegal quiet moves
+ if (must_capture() && !capture(m))
+ {
+ if (checkers())
+ {
+ for (const auto& mevasion : MoveList<EVASIONS>(*this))
+ if (capture(mevasion) && legal(mevasion))
+ return false;
+ }
+ else
+ {
+ for (const auto& mcap : MoveList<CAPTURES>(*this))
+ if (capture(mcap) && legal(mcap))
+ return false;
+ }
+ }
+
+ // game end
+ if (is_variant_end())
+ return false;
+
// En passant captures are a tricky special case. Because they are rather
// uncommon, we do it simply by testing whether the king is attacked after
// the move is made.
std::vector<PieceType> promotion_piece_types() const;
bool double_step_enabled() const;
bool castling_enabled() const;
+ bool checking_permitted() const;
+ bool must_capture() const;
+ // winning conditions
+ Value stalemate_value(int ply = 0) const;
+ Value checkmate_value(int ply = 0) const;
+ Value bare_king_value(int ply = 0) const;
+ bool bare_king_move() const;
+ Bitboard capture_the_flag(Color c) const;
+ bool flag_move() const;
+ bool is_variant_end() const;
+ bool is_variant_end(Value& result, int ply = 0) const;
// Position representation
Bitboard pieces() const;
return var->castling;
}
+inline bool Position::checking_permitted() const {
+ assert(var != nullptr);
+ return var->checking;
+}
+
+inline bool Position::must_capture() const {
+ assert(var != nullptr);
+ return var->mustCapture;
+}
+
+inline Value Position::stalemate_value(int ply) const {
+ assert(var != nullptr);
+ Value v = var->stalemateValue;
+ return v == VALUE_MATE ? mate_in(ply)
+ : v == -VALUE_MATE ? mated_in(ply)
+ : v;
+}
+
+inline Value Position::checkmate_value(int ply) const {
+ assert(var != nullptr);
+ Value v = var->checkmateValue;
+ return v == VALUE_MATE ? mate_in(ply)
+ : v == -VALUE_MATE ? mated_in(ply)
+ : v;
+}
+
+inline Value Position::bare_king_value(int ply) const {
+ assert(var != nullptr);
+ Value v = var->bareKingValue;
+ return v == VALUE_MATE ? mate_in(ply)
+ : v == -VALUE_MATE ? mated_in(ply)
+ : v;
+}
+
+inline bool Position::bare_king_move() const {
+ assert(var != nullptr);
+ return var->bareKingMove;
+}
+
+inline Bitboard Position::capture_the_flag(Color c) const {
+ assert(var != nullptr);
+ return c == WHITE ? var->whiteFlag : var->blackFlag;
+}
+
+inline bool Position::flag_move() const {
+ assert(var != nullptr);
+ return var->flagMove;
+}
+
+inline bool Position::is_variant_end() const {
+ Value result;
+ return is_variant_end(result);
+}
+
+inline bool Position::is_variant_end(Value& result, int ply) const {
+ // bare king rule
+ if ( bare_king_value() != VALUE_NONE
+ && !bare_king_move()
+ && !(count<ALL_PIECES>(sideToMove) - count<KING>(sideToMove)))
+ {
+ result = bare_king_value(ply);
+ return true;
+ }
+ if ( bare_king_value() != VALUE_NONE
+ && bare_king_move()
+ && !(count<ALL_PIECES>(~sideToMove) - count<KING>(~sideToMove)))
+ {
+ result = -bare_king_value(ply);
+ return true;
+ }
+ // capture the flag
+ if (!flag_move() && (capture_the_flag(~sideToMove) & square<KING>(~sideToMove)))
+ {
+ result = mated_in(ply);
+ return true;
+ }
+ if (flag_move() && (capture_the_flag(sideToMove) & square<KING>(sideToMove)))
+ {
+ result = mate_in(ply);
+ return true;
+ }
+ return false;
+}
+
inline Color Position::side_to_move() const {
return sideToMove;
}
if (rootMoves.empty())
{
rootMoves.emplace_back(MOVE_NONE);
+ Value variantResult;
sync_cout << "info depth 0 score "
- << UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
+ << UCI::value( rootPos.is_variant_end(variantResult) ? variantResult
+ : rootPos.checkers() ? rootPos.checkmate_value() : rootPos.stalemate_value())
<< sync_endl;
}
else
if (!rootNode)
{
+ Value variantResult;
+ if (pos.is_variant_end(variantResult, ss->ply))
+ return variantResult;
+
// Step 2. Check for aborted search and immediate draw
if ( Threads.stop.load(std::memory_order_relaxed)
|| pos.is_draw(ss->ply)
if (!moveCount)
bestValue = excludedMove ? alpha
- : inCheck ? mated_in(ss->ply) : VALUE_DRAW;
+ : inCheck ? pos.checkmate_value(ss->ply) : pos.stalemate_value(ss->ply);
else if (bestMove)
{
// Quiet best move: update move sorting heuristics
inCheck = pos.checkers();
moveCount = 0;
+ Value variantResult;
+ if (pos.is_variant_end(variantResult, ss->ply))
+ return variantResult;
+
// Check for an immediate draw or maximum ply reached
if ( pos.is_draw(ss->ply)
|| ss->ply >= MAX_PLY)
if (abs(v) < VALUE_MATE - MAX_PLY)
ss << "cp " << v * 100 / PawnValueEg;
else
- ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
+ ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v - 1) / 2;
return ss.str();
}
v->promotionPieceTypes = {FERS};
v->doubleStep = false;
v->castling = false;
- // TODO: bare king, stalemate
+ v->bareKingValue = -VALUE_MATE;
+ v->bareKingMove = true;
+ v->stalemateValue = -VALUE_MATE;
return v;
} ();
const Variant* amazon = [&]{
v->promotionPieceTypes = {QUEEN, ROOK, BISKNI, KNIBIS};
return v;
} ();
+ const Variant* kingofthehill = [&]{
+ Variant* v = new Variant();
+ v->whiteFlag = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5);
+ v->whiteFlag = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5);
+ v->flagMove = false;
+ return v;
+ } ();
+ const Variant* racingkings = [&]{
+ Variant* v = new Variant();
+ v->startFen = "8/8/8/8/8/8/krbnNBRK/qrbnNBRQ w - - 0 1";
+ v->whiteFlag = Rank8BB;
+ v->whiteFlag = Rank8BB;
+ v->flagMove = true;
+ v->castling = false;
+ v->checking = false;
+ return v;
+ } ();
+ const Variant* losers = [&]{
+ Variant* v = new Variant();
+ v->checkmateValue = VALUE_MATE;
+ v->stalemateValue = VALUE_MATE;
+ v->bareKingValue = VALUE_MATE;
+ v->bareKingMove = false;
+ v->mustCapture = 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("shatranj"), shatranj));
insert(std::pair<std::string, const Variant*>(std::string("amazon"), amazon));
insert(std::pair<std::string, const Variant*>(std::string("hoppelpoppel"), hoppelpoppel));
+ 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));
}
void VariantMap::clear_all() {
#include <string>
#include "types.h"
+#include "bitboard.h"
/// Variant struct stores information needed to determine the rules of a variant.
std::vector<PieceType> promotionPieceTypes = {QUEEN, ROOK, BISHOP, KNIGHT};
bool doubleStep = true;
bool castling = true;
+ bool checking = true;
+ bool mustCapture = false;
+ // game end
+ Value stalemateValue = VALUE_DRAW;
+ Value checkmateValue = -VALUE_MATE;
+ Value bareKingValue = VALUE_NONE;
+ bool bareKingMove = false;
+ Bitboard whiteFlag = 0;
+ Bitboard blackFlag = 0;
+ bool flagMove = false;
void set_piece(PieceType pt, char c) {
pieceToChar[make_piece(WHITE, pt)] = toupper(c);