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