+// 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, end = std::min(stc->rule50, stc->pliesFromNull);
+
+ if (end < i)
+ return false;
+
+ StateInfo* stp = stc->previous->previous;
+
+ do {
+ stp = stp->previous->previous;
+
+ if (stp->key == stc->key)
+ return true;
+
+ i += 2;
+ } while (i <= end);
+
+ 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 {
+
+ int j;
+
+ int end = std::min(st->rule50, st->pliesFromNull);
+
+ if (end < 3)
+ return false;
+
+ Key originalKey = st->key;
+ StateInfo* stp = st->previous;
+
+ for (int i = 3; i <= end; i += 2)
+ {
+ stp = stp->previous->previous;
+
+ Key moveKey = originalKey ^ stp->key;
+ if ( (j = H1(moveKey), cuckoo[j] == moveKey)
+ || (j = H2(moveKey), cuckoo[j] == moveKey))
+ {
+ Move move = cuckooMove[j];
+ Square s1 = from_sq(move);
+ Square s2 = to_sq(move);
+
+ if (!(between_bb(s1, s2) & pieces()))
+ {
+ // In the cuckoo table, both moves Rc1c5 and Rc5c1 are stored in the same
+ // location. We select the legal one by reversing the move variable if necessary.
+ if (empty(s1))
+ move = make_move(s2, s1);
+
+ 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;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+