Changing license to GPL3 (and bumping version to 1.4.0).
[gnushogi.git] / gnushogi / tcontrl.c
1 /*
2  * FILE: tcontrl.c
3  *
4  * ----------------------------------------------------------------------
5  *
6  * Copyright (c) 2012 Free Software Foundation
7  *
8  * GNU SHOGI is based on GNU CHESS
9  *
10  * This file is part of GNU SHOGI.
11  *
12  * GNU Shogi is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation; either version 3 of the License,
15  * or (at your option) any later version.
16  *
17  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with GNU Shogi; see the file COPYING. If not, see
24  * <http://www.gnu.org/licenses/>.
25  * ----------------------------------------------------------------------
26  *
27  */
28
29
30 #include "gnushogi.h"
31 #include <math.h>
32
33 #define ALTERNATIVE_TC
34
35
36 /*
37  * In a networked enviroment gnushogi might be compiled on different hosts
38  * with different random number generators; that is not acceptable if they
39  * are going to share the same transposition table.
40  */
41
42 static unsigned long next = 1;
43
44 unsigned int
45 urand(void)
46 {
47     next *= 1103515245;
48     next += 12345;
49     return ((unsigned int) (next >> 16) & 0xFFFF);
50 }
51
52
53
54 void
55 gsrand(unsigned int seed)
56 {
57     next = seed;
58 }
59
60
61
62 void
63 TimeCalc()
64 {
65     /* adjust number of moves remaining in gamein games */
66     int increment = 0;
67     int topsum = 0;
68     int tcompsum = 0;
69     int me, him;
70     int i;
71
72     /* Don't do anything until you have enough numbers. */
73     if (GameCnt < (MINGAMEIN * 2))
74         return;
75
76     /* Calculate average time in sec for last MINGAMEIN moves. */
77     for (i = 0; i < MINGAMEIN; i++)
78     {
79         tcompsum += timecomp[i];
80         topsum += timeopp[i];
81     }
82
83     topsum   /= (100 * MINGAMEIN);
84     tcompsum /= (100 * MINGAMEIN);
85
86     /* If I have less time than opponent add another move. */
87     me  = TimeControl.clock[computer] / 100;
88     him = TimeControl.clock[opponent] / 100;
89
90     if (me < him)
91         increment += 2;
92
93     if (((him - me) > 60) || ((me < him) && (me < 120)))
94         increment++;
95
96     /* If I am losing more time with each move add another. */
97     /* If (!((me - him) > 60) && tcompsum > topsum) increment++; */
98
99     if (tcompsum > topsum)
100     {
101         increment += 2;
102     }
103     else if ((TimeControl.moves[computer] < MINMOVES) && !increment)
104     {
105         /* ... but don't let moves go below MINMOVES. */
106         increment++;
107     }
108     else if ((me > him) && (tcompsum < topsum))
109     {
110         /* If I am doing really well use more time per move. */
111         increment = -1;
112     }
113
114     /* If not fischer clock be careful about time. */
115     /* CHECKME: what's a fischer clock? */
116
117     if ((TCadd == 0) && (increment > 0))
118         increment += 2;
119
120     if ((me == 0) && (increment > 0))
121         increment += 2;
122
123     TimeControl.moves[computer] += increment;
124 }
125
126
127
128 /*
129  * Set ResponseTime, TCcount, and TCleft.
130  */
131
132 void SetResponseTime(short side)
133 {
134 #ifdef ALTERNATIVE_TC
135     int DetermineTCcount = true;
136
137     if (TCflag)
138     {
139         TCcount = 0;
140
141         if (TimeControl.moves[side] < 1)
142             TimeControl.moves[side] = 1;
143
144         /* special case time per move specified */
145         if (flag.onemove)
146         {
147             ResponseTime = TimeControl.clock[side] - 100;
148             TCleft = 0;
149         }
150         else
151         {
152             /* calculate avg time per move remaining */
153             if (TimeControl.clock[side] <= 0)
154             {
155                 ResponseTime = 0;
156                 TCleft = (long)MINRESPONSETIME / MAXTCCOUNTX;
157             }
158             else
159             {
160                 short rtf = in_opening_stage ? 8 : 2;
161                 short tcq = in_opening_stage ? 2 : 4;
162
163                 TimeControl.clock[side] += TCadd;
164                 ResponseTime = (TimeControl.clock[side])
165                     / (((TimeControl.moves[side]) * rtf) + 1);
166                 TCleft = (long)ResponseTime / tcq;
167                 ResponseTime += TCadd / 2;
168             }
169
170             if (TimeControl.moves[side] < 5)
171             {
172                 TCcount = MAXTCCOUNTX - 10;
173
174                 if (TCcount < 0)
175                     TCcount = 0;
176
177                 DetermineTCcount = false;
178             }
179         }
180
181         if (ResponseTime < MINRESPONSETIME)
182         {
183             ResponseTime = MINRESPONSETIME;
184             TCcount = MAXTCCOUNTX - 10;
185
186             if (TCcount < 0)
187                 TCcount = 0;
188
189             DetermineTCcount = false;
190         }
191
192         if (!hard_time_limit && (ResponseTime < 2 * MINRESPONSETIME))
193         {
194             TCcount = MAXTCCOUNTX - 10;
195
196             if (TCcount < 0)
197                 TCcount = 0;
198
199             DetermineTCcount = false;
200         }
201     }
202     else
203     {
204         TCleft = 0;
205         ResponseTime = MaxResponseTime;
206         ElapsedTime(COMPUTE_AND_INIT_MODE);
207     }
208
209     if (DetermineTCcount)
210     {
211         if (TCleft )
212         {
213             int AllowedCounts
214                 = ((int)((TimeControl.clock[side] - ResponseTime)) / 2)
215                 / TCleft;
216
217             if (AllowedCounts <= 0)
218                 TCcount = MAXTCCOUNTX;
219             else if (AllowedCounts > MAXTCCOUNTX)
220                 TCcount = 0;
221             else
222                 TCcount = MAXTCCOUNTX - AllowedCounts;
223         }
224         else
225         {
226             TCcount = MAXTCCOUNTX;
227         }
228     }
229
230     if (ResponseTime < MINRESPONSETIME)
231         ResponseTime = MINRESPONSETIME;
232
233 #else
234
235     if (TCflag)
236     {
237         TCcount = 0;
238
239         if (TimeControl.moves[side] < 1)
240             TimeControl.moves[side] = 1;
241
242         /* special case time per move specified */
243         if (flag.onemove)
244         {
245             ResponseTime = TimeControl.clock[side] - 100;
246             TCleft = 0;
247         }
248         else
249         {
250             /* calculate avg time per move remaining */
251             TimeControl.clock[side] += TCadd;
252
253             ResponseTime = (TimeControl.clock[side])
254                 / (((TimeControl.moves[side]) * 2) + 1);
255             TCleft = (int) ResponseTime / 3;
256             ResponseTime += TCadd / 2;
257
258             if (TimeControl.moves[side] < 5)
259                 TCcount = MAXTCCOUNTX - 10;
260         }
261
262         if (ResponseTime < 101)
263         {
264             ResponseTime = 100;
265             TCcount = MAXTCCOUNTX - 10;
266         }
267         else if (ResponseTime < 200)
268         {
269             TCcount = MAXTCCOUNTX - 10;
270         }
271     }
272     else
273     {
274         ResponseTime = MaxResponseTime;
275         TCleft = 0;
276         ElapsedTime(COMPUTE_AND_INIT_MODE);
277     }
278
279     if (TCleft)
280     {
281         TCcount = ((int)((TimeControl.clock[side] - ResponseTime)) / 2)
282             / TCleft;
283
284         if (TCcount > MAXTCCOUNTX)
285             TCcount = 0;
286         else
287             TCcount = MAXTCCOUNTX - TCcount;
288     }
289     else
290     {
291         TCcount = MAXTCCOUNTX;
292     }
293 #endif
294
295     assert(TCcount <= MAXTCCOUNTX);
296 }
297
298
299
300 void
301 CheckForTimeout(int score, int globalscore, int Jscore, int zwndw)
302 {
303     if (flag.musttimeout || (Sdepth >= MaxSearchDepth))
304         flag.timeout = true;
305
306     else if (TCflag && (Sdepth > (MINDEPTH - 1)) && (TCcount < MAXTCCOUNTR))
307     {
308         if (killr0[1] != PrVar[1] /* || Killr0[2] != PrVar[2] */)
309         {
310             TCcount++;
311             ExtraTime += TCleft;
312         }
313
314         if ((TCcount < MAXTCCOUNTR)
315             && (abs(score - globalscore) / Sdepth) > ZDELTA)
316         {
317             TCcount++;
318             ExtraTime += TCleft;
319         }
320     }
321
322     if ((score > (Jscore - zwndw)) && (score > (Tree[1].score + 250)))
323         ExtraTime = 0;
324
325     ElapsedTime(COMPUTE_MODE);
326
327     if (root->flags & exact)
328         flag.timeout = true;
329     /*else if (Tree[1].score < -SCORE_LIMIT) flag.timeout = true;
330      */
331 #if defined OLDTIME || !defined HAVE_GETTIMEOFDAY
332     else if (!(Sdepth < MINDEPTH)
333              && TCflag
334              && ((4 * et) > (2*ResponseTime + ExtraTime)))
335         flag.timeout = true;
336 #else
337     else if (!(Sdepth < MINDEPTH)
338              && TCflag
339              && ((int)(1.93913099l * (pow((double)et, 1.12446928l)))
340                  > (ResponseTime + ExtraTime)))
341         flag.timeout = true;
342 #endif
343
344     if (flag.timeout)
345         ShowMessage("timeout");
346 }