set_castling_right(c, rsq);
}
+ // counting limit
+ if (counting_rule() && isdigit(ss.peek()))
+ ss >> st->countingLimit;
+
// 4. En passant square. Ignore if no pawn capture is possible
- if ( ((ss >> col) && (col >= 'a' && col <= 'a' + max_file()))
- && ((ss >> row) && (row >= '1' && row <= '1' + max_rank())))
+ else if ( ((ss >> col) && (col >= 'a' && col <= 'a' + max_file()))
+ && ((ss >> row) && (row >= '1' && row <= '1' + max_rank())))
{
st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
}
+ // counting rules
+ if (st->countingLimit && st->rule50)
+ {
+ st->countingPly = st->rule50;
+ st->rule50 = 0;
+ }
+
chess960 = isChess960;
thisThread = th;
set_state(st);
if (max_check_count())
ss << " " << (max_check_count() - st->checksGiven[WHITE]) << "+" << (max_check_count() - st->checksGiven[BLACK]);
- ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(*this, ep_square()) + " ")
- << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
+ // Counting limit and counting ply, or ep-square and 50-move rule counter
+ if (st->countingLimit)
+ ss << " " << st->countingLimit << " " << st->countingPly;
+ else
+ ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(*this, ep_square()) + " ")
+ << st->rule50;
+
+ ss << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
return ss.str();
}
++gamePly;
++st->rule50;
++st->pliesFromNull;
+ if (st->countingLimit)
+ ++st->countingPly;
Color us = sideToMove;
Color them = ~us;
sideToMove = ~sideToMove;
+ if ( counting_rule()
+ && ( ((!st->countingLimit || captured) && count<ALL_PIECES>(sideToMove) == 1)
+ || (!st->countingLimit && !count<PAWN>())))
+ {
+ st->countingLimit = 2 * counting_limit();
+ st->countingPly = st->countingLimit && count<ALL_PIECES>(sideToMove) == 1 ? 2 * count<ALL_PIECES>() : 0;
+ }
+
// Update king attacks used for fast check detection
set_check_info(st);
}
}
+ // counting rules
+ if ( counting_rule()
+ && st->countingLimit
+ && st->countingPly >= st->countingLimit
+ && (!checkers() || MoveList<LEGAL>(*this).size()))
+ {
+ result = VALUE_DRAW;
+ return true;
+ }
+
return false;
}
}
+/// Position::counting_limit() returns the counting limit in full moves.
+
+int Position::counting_limit() const {
+
+ assert(counting_rule());
+
+ // No counting yet
+ if (count<PAWN>() && count<ALL_PIECES>(sideToMove) > 1)
+ return 0;
+
+ switch (counting_rule())
+ {
+ case MAKRUK_COUNTING:
+ // Board's honor rule
+ if (count<ALL_PIECES>(sideToMove) > 1)
+ return 64;
+
+ // Pieces' honor rule
+ if (count<ROOK>(~sideToMove) > 1)
+ return 8;
+ if (count<ROOK>(~sideToMove) == 1)
+ return 16;
+ if (count<KHON>(~sideToMove) > 1)
+ return 22;
+ if (count<KNIGHT>(~sideToMove) > 1)
+ return 32;
+ if (count<KHON>(~sideToMove) == 1)
+ return 44;
+
+ return 64;
+
+ case ASEAN_COUNTING:
+ if (count<ALL_PIECES>(sideToMove) > 1)
+ return 0;
+ if (count<ROOK>(~sideToMove))
+ return 16;
+ if (count<KHON>(~sideToMove) && count<MET>(~sideToMove))
+ return 44;
+ if (count<KNIGHT>(~sideToMove) && count<MET>(~sideToMove))
+ return 64;
+
+ return 0;
+
+ default:
+ assert(false);
+ return 0;
+ }
+
+}
+
+
/// Position::flip() flips position with the white and black sides reversed. This
/// is only useful for debugging e.g. for finding evaluation symmetry bugs.
int castlingRights;
int rule50;
int pliesFromNull;
+ int countingPly;
+ int countingLimit;
CheckCount checksGiven[COLOR_NB];
Score psq;
Square epSquare;
CheckCount max_check_count() const;
int connect_n() const;
CheckCount checks_given(Color c) const;
+ CountingRule counting_rule() const;
// Variant-specific properties
int count_in_hand(Color c, PieceType pt) const;
bool is_immediate_game_end(Value& result, int ply = 0) const;
bool has_game_cycle(int ply) const;
bool has_repeated() const;
+ int counting_limit() const;
int rule50_count() const;
Score psq_score() const;
Value non_pawn_material(Color c) const;
return st->checksGiven[c];
}
+inline CountingRule Position::counting_rule() const {
+ assert(var != nullptr);
+ return var->countingRule;
+}
+
inline bool Position::is_immediate_game_end() const {
Value result;
return is_immediate_game_end(result);
v->doubleStep = false;
v->castling = false;
v->nMoveRule = 0;
+ v->countingRule = MAKRUK_COUNTING;
return v;
}
Variant* asean_variant() {
v->promotionPieceTypes = {ROOK, KNIGHT, KHON, MET};
v->doubleStep = false;
v->castling = false;
+ v->countingRule = ASEAN_COUNTING;
return v;
}
Variant* aiwok_variant() {
v->promotionRank = RANK_1; // no regular promotions
v->sittuyinPromotion = true;
v->immobilityIllegal = false;
+ v->countingRule = ASEAN_COUNTING;
return v;
}
Variant* minishogi_variant_base() {