diff --git a/README.md b/README.md index 6fdf6d198..a91242602 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,9 @@ change them via a chess GUI. This is a list of available UCI options in Pikafish * #### Rule60 Use 60 move rule in gameplay. + * #### Strict3Fold + Not only use 3 fold repetition at root nodes, but also use 3 fold at non-root nodes. Enable this will help get better analyses results but lose elo. + * #### Debug Log File Write all communication to and from the engine into a text file. diff --git a/src/position.cpp b/src/position.cpp index b0bd72a98..5df4c2d92 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -937,6 +937,7 @@ bool Position::rule_judge(Value& result, int ply) const { if (end >= 4 && filter[st->key]) { + int cnt = 1; StateInfo* stp = st->previous->previous; bool perpetualThem = st->checkersBB && stp->checkersBB; bool perpetualUs = st->previous->checkersBB && stp->previous->checkersBB; @@ -946,8 +947,9 @@ bool Position::rule_judge(Value& result, int ply) const { stp = stp->previous->previous; perpetualThem &= bool(stp->checkersBB); - // Return a score if a position repeats once earlier. - if (stp->key == st->key) + // Return a score if a position repeats once earlier but strictly + // after the root, or repeats twice before or at the root. + if (stp->key == st->key && ++cnt == (!Strict3Fold && ply > i ? 2 : 3)) { if (perpetualThem || perpetualUs) { @@ -963,6 +965,7 @@ bool Position::rule_judge(Value& result, int ply) const { rollback.set_chase_info(i); // Chasing detection + cnt = 1; stp = st->previous->previous; uint16_t chaseThem = st->chased & stp->chased; uint16_t chaseUs = st->previous->chased & stp->previous->chased; @@ -974,8 +977,9 @@ bool Position::rule_judge(Value& result, int ply) const { chaseThem &= stp->previous->previous->chased; stp = stp->previous->previous; - // Return a score if a position repeats once earlier. - if (stp->key == st->key) + // Return a score if a position repeats once earlier but strictly + // after the root, or repeats twice before or at the root. + if (stp->key == st->key && ++cnt == (!Strict3Fold && ply > i ? 2 : 3)) { result = (chaseThem || chaseUs) ? (!chaseUs ? mate_in(ply) : !chaseThem ? mated_in(ply) : VALUE_DRAW) : VALUE_DRAW; return true; diff --git a/src/uci.h b/src/uci.h index 254175d45..617db3a77 100644 --- a/src/uci.h +++ b/src/uci.h @@ -81,6 +81,7 @@ Move to_move(const Position& pos, std::string& str); extern UCI::OptionsMap Options; extern bool UseRule60; +extern bool Strict3Fold; } // namespace Stockfish diff --git a/src/ucioption.cpp b/src/ucioption.cpp index aefba5d34..06a825a36 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -34,6 +34,7 @@ namespace Stockfish { UCI::OptionsMap Options; // Global object bool UseRule60 = true; +bool Strict3Fold = false; namespace UCI { @@ -43,6 +44,7 @@ void on_hash_size(const Option& o) { TT.resize(size_t(o)); } void on_logger(const Option& o) { start_logger(o); } void on_threads(const Option& o) { Threads.set(size_t(o)); } void on_rule60(const Option& o) { UseRule60 = bool(o); } +void on_strict3fold(const Option& o) { Strict3Fold = bool(o); } void on_eval_file(const Option& ) { Eval::NNUE::init(); } /// Our case insensitive less() function as required by UCI protocol @@ -70,6 +72,7 @@ void init(OptionsMap& o) { o["Slow Mover"] << Option(100, 10, 1000); o["nodestime"] << Option(0, 0, 10000); o["Rule60"] << Option(true, on_rule60); + o["Strict3Fold"] << Option(false, on_strict3fold); o["UCI_LimitStrength"] << Option(false); o["UCI_Elo"] << Option(1350, 1350, 2850); o["UCI_WDLCentipawn"] << Option(true);