}
-// Marcel van Kervink's cuckoo algorithm for fast detection of "upcoming repetition"/
-// "no progress" situations. Description of the algorithm in the following paper:
+// Marcel van Kervinck's cuckoo algorithm for fast detection of "upcoming repetition"
+// situations. Description of the algorithm in the following paper:
// https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf
// First and second hash functions for indexing the cuckoo tables
-inline Key H1(Key h) { return h & 0x1fff; }
-inline Key H2(Key h) { return (h >> 16) & 0x1fff; }
+inline int H1(Key h) { return h & 0x1fff; }
+inline int H2(Key h) { return (h >> 16) & 0x1fff; }
// Cuckoo tables with Zobrist hashes of valid reversible moves, and the moves themselves
Key cuckoo[8192];
{
Move move = make_move(s1, s2);
Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
- unsigned int i = H1(key);
+ int i = H1(key);
while (true)
{
std::swap(cuckoo[i], key);
StateInfo* stc = st;
while (true)
{
- int i = 4, e = std::min(stc->rule50, stc->pliesFromNull);
+ int i = 4, end = std::min(stc->rule50, stc->pliesFromNull);
- if (e < i)
+ if (end < i)
return false;
StateInfo* stp = st->previous->previous;
return true;
i += 2;
- } while (i <= e);
+ } while (i <= end);
stc = stc->previous;
}
bool Position::has_game_cycle(int ply) const {
- unsigned int j;
+ int j;
int end = std::min(st->rule50, st->pliesFromNull);
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;
+ stp = stp->previous->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))
{
- 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()))
{
- Move m = Move(cuckooMove[j]);
- if (!(between_bb(from_sq(m), to_sq(m)) & pieces()))
- {
- if (ply > i)
- return true;
+ // 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);
- // 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;
- }
+ 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;
}