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