+// Position::has_repeated() tests whether there has been at least one repetition
+// of positions since the last capture or pawn move.
+
+bool Position::has_repeated() const {
+
+ StateInfo* stc = st;
+ while (true)
+ {
+ int i = 4, e = std::min(stc->rule50, stc->pliesFromNull);
+
+ if (e < i)
+ return false;
+
+ StateInfo* stp = st->previous->previous;
+
+ do {
+ stp = stp->previous->previous;
+
+ if (stp->key == stc->key)
+ return true;
+
+ i += 2;
+ } while (i <= e);
+
+ stc = stc->previous;
+ }
+}
+
+
+/// Position::has_game_cycle() tests if the position has a move which draws by repetition,
+/// or an earlier position has a move that directly reaches the current position.
+
+bool Position::has_game_cycle(int ply) const {
+
+ unsigned int j;
+
+ int end = std::min(st->rule50, st->pliesFromNull);
+
+ if (end < 3)
+ return false;
+
+ Key originalKey = st->key;
+ StateInfo* stp = st->previous;
+ Key progressKey = stp->key ^ Zobrist::side;
+
+ for (int i = 3; i <= end; i += 2)
+ {
+ stp = stp->previous;
+ progressKey ^= stp->key ^ Zobrist::side;
+ stp = stp->previous;
+
+ // "originalKey == " detects upcoming repetition, "progressKey == " detects no-progress
+ if ( originalKey == (progressKey ^ stp->key)
+ || progressKey == Zobrist::side)
+ {
+ Key moveKey = originalKey ^ stp->key;
+ if ( (j = H1(moveKey), cuckoo[j] == moveKey)
+ || (j = H2(moveKey), cuckoo[j] == moveKey))
+ {
+ Move m = Move(cuckooMove[j]);
+ if (!(between_bb(from_sq(m), to_sq(m)) & pieces()))
+ {
+ if (ply > i)
+ return true;
+
+ // For repetitions before or at the root, require one more
+ StateInfo* next_stp = stp;
+ for (int k = i + 2; k <= end; k += 2)
+ {
+ next_stp = next_stp->previous->previous;
+ if (next_stp->key == stp->key)
+ return true;
+ }
+ }
+ }
+ }
+ progressKey ^= stp->key;
+ }
+ return false;
+}
+
+