1 #include "chess.h"
2 #include "data.h"
3 /* last modified 08/03/16 */
4 /*
5 *******************************************************************************
6 * *
7 * Repeat() is used to detect a draw by repetition. The repetition list is *
8 * a simple 1d array that contains the Zobrist signatures for each position *
9 * reached in the game since the last irreversable moves at the root. New *
10 * positions are only added to this list here in Repeat(). *
11 * *
12 * Repeat() scans the list to determine if this position has occurred at *
13 * once previously (two-fold repetition.) If so, this will be treated as a *
14 * draw by Search()/Quiesce(). *
15 * *
16 * Repeat() also handles 50-move draws. The position[] structure contains *
17 * the count of moves since the last capture or pawn push. When this value *
18 * reaches 100 (plies, which is 50 moves) the score is set to DRAW. *
19 * *
20 * Repeat() has one tricky issue. MakeMoveRoot() has to insert moves into *
21 * the repetition list so that things will work well. We end up with the *
22 * list having entries from 0 through "rep_index" where the last entry is *
23 * the entry stored after the last actual move in the game. Search() will *
24 * call Repeat() at ply=1, which stores the SAME position at position *
25 * rep_index + 1. That gets the list out of sync. To solve this, Iterate() *
26 * decrements rep_index immediately prior to calling Search(), and it then *
27 * increments it immediately after Search() returns. This causes Search() *
28 * to overwrite the entry with the same value for ply=1, but now the list is *
29 * in a sane state for the rest of the search. Do NOT remove those to lines *
30 * in Iterate() or repetition detection will be broken. *
31 * *
32 *******************************************************************************
33 */
Repeat(TREE * RESTRICT tree,int ply)34 int Repeat(TREE * RESTRICT tree, int ply) {
35 int where, count;
36
37 /*
38 ************************************************************
39 * *
40 * If the 50-move rule has been reached, then adjust the *
41 * score to reflect the impending draw. If we have not *
42 * made 2 moves for each side (or more) since the last *
43 * irreversible move, there is no way to repeat a prior *
44 * position. *
45 * *
46 ************************************************************
47 */
48 tree->rep_list[rep_index + ply] = HashKey;
49 if (Reversible(ply) < 4)
50 return 0;
51 if (Reversible(ply) > 99)
52 return 3;
53 /*
54 ************************************************************
55 * *
56 * Now we scan the right part of the repetition list, *
57 * which is to search backward from the entry for 2 plies *
58 * back (no point in checking current position, we KNOW *
59 * that is a match but it is not a repetition, it is just *
60 * the current position's entry which we don't want to *
61 * check). We can use the reversible move counter as a *
62 * limit since there is no point in scanning the list back *
63 * beyond the last capture/pawn move since there can not *
64 * possibly be a repeat beyond that point. *
65 * *
66 ************************************************************
67 */
68 count = Reversible(ply) / 2 - 1;
69 for (where = rep_index + ply - 4; count; where -= 2, count--) {
70 if (HashKey == tree->rep_list[where])
71 return 2;
72 }
73 return 0;
74 }
75
76 /* last modified 08/03/16 */
77 /*
78 *******************************************************************************
79 * *
80 * Repeat3x() is used to detect a real draw by repetition. This routine is *
81 * only called from Main() and simply scans the complete list searching for *
82 * exactly three repetitions (two additional repetitions of the current *
83 * position.) This is used to actually claim a draw by repetition or by the *
84 * 50 move rule. *
85 * *
86 *******************************************************************************
87 */
Repeat3x(TREE * RESTRICT tree)88 int Repeat3x(TREE * RESTRICT tree) {
89 int reps = 0, where;
90
91 /*
92 ************************************************************
93 * *
94 * If the 50-move rule has been reached, then return an *
95 * indicator that a draw can be claimed if wanted. *
96 * *
97 ************************************************************
98 */
99 if (Reversible(0) > 99)
100 return 2;
101 /*
102 ************************************************************
103 * *
104 * Scan the repetition list to determine if this position *
105 * has occurred two times previously, making this an *
106 * actual 3-fold repetition. Note we only check every *
107 * other entry since the position has to be repeated 3x *
108 * with the SAME side on move. *
109 * *
110 ************************************************************
111 */
112 for (where = rep_index % 2; where < rep_index; where += 2)
113 if (HashKey == tree->rep_list[where])
114 reps++;
115 return reps == 2;
116 }
117