Allow setting up position from scratch
[bonanza.git] / time.c
1 #include <limits.h>
2 #include <assert.h>
3 #if ! defined(_WIN32)
4 #  include <sys/time.h>
5 #  include <time.h>
6 #endif
7 #include "shogi.h"
8
9
10 void CONV
11 set_search_limit_time( int turn )
12 /*
13   [inputs]
14   global variables:
15     sec_limit       time limit of a side for an entire game in seconds
16     sec_limit_up    time limit for a move when the ordinary time has run out.
17                     the time is known as 'byo-yomi'.
18     sec_b_total     seconds spent by black 
19     sec_w_total     seconds spent by white
20     time_response
21     ( game_status & flag_puzzling )        time-control for puzzling-search
22     ( game_status & flag_pondering )       time-control for pondering-search
23     ( game_status & flag_time_extendable ) bonanza isn't punctual to the time
24   
25   argument:
26     turn            a side to move
27   
28   [outputs]
29   global variables:
30     time_limit      tentative deadline for searching in millisecond
31     time_max_limit  maximum allowed time to search in millisecond
32   
33   [working area]
34   local variables:
35     sec_elapsed     second spent by the side to move
36     sec_left        time left for the side in seconds
37     u0              tentative deadline for searching in second
38     u1              maximum allowed time to search in second
39 */
40 {
41   unsigned int u0, u1;
42 #ifdef XBOARD
43   extern char xboard_mode;
44   if(xboard_mode) return;
45 #endif
46   /* no time-control */
47   if ( sec_limit_up == UINT_MAX || ( game_status & flag_pondering ) )
48     {
49       time_max_limit = time_limit = UINT_MAX;
50       return;
51     }
52
53 #if defined(USI)
54   if ( usi_mode != usi_off && usi_byoyomi )
55     {
56       time_max_limit = time_limit = usi_byoyomi;
57       Out( "- time ctrl: %u -- %u\n", time_limit, time_max_limit );
58       return;
59     }
60 #endif
61
62   /* not punctual to the time */
63   if ( ! sec_limit && ( game_status & flag_time_extendable ) )
64     {
65       u0 = sec_limit_up;
66       u1 = sec_limit_up * 5U;
67     }
68   /* have byo-yomi */
69   else if ( sec_limit_up )
70     {
71       unsigned int umax, umin, sec_elapsed, sec_left;
72
73       sec_elapsed = turn ? sec_w_total : sec_b_total;
74       sec_left    = ( sec_elapsed <= sec_limit ) ? sec_limit - sec_elapsed : 0;
75       u0          = ( sec_left + ( TC_NMOVE / 2U ) ) / TC_NMOVE;
76
77       /*
78         t = 2s is not beneficial since 2.8s are almost the same as 1.8s.
79         So that, we rather want to use up the ordinary time.
80       */
81       if ( u0 == 2U ) { u0 = 3U; }
82
83       /* 'byo-yomi' is so long that the ordinary time-limit is negligible. */
84       if ( u0 < sec_limit_up * 5U ) { u0 = sec_limit_up * 5U; }
85     
86       u1 = u0 * 5U;
87
88       umax = sec_left + sec_limit_up;
89       umin = 1;
90
91       if ( umax < u0 ) { u0 = umax; }
92       if ( umax < u1 ) { u1 = umax; }
93       if ( umin > u0 ) { u0 = umin; }
94       if ( umin > u1 ) { u1 = umin; }
95     }
96   /* no byo-yomi */
97   else {
98     unsigned int sec_elapsed, sec_left;
99     
100     sec_elapsed = turn ? sec_w_total : sec_b_total;
101
102     /* We have some seconds left to think. */
103     if ( sec_elapsed + SEC_MARGIN < sec_limit )
104       {
105         sec_left = sec_limit - sec_elapsed;
106         u0       = ( sec_left + ( TC_NMOVE / 2U ) ) / TC_NMOVE;
107         
108         /* t = 2s is not beneficial since 2.8s is almost the same as 1.8s. */
109         /* So that, we rather want to save the time.                       */
110         if ( u0 == 2U ) { u0 = 1U; }
111         u1 = u0 * 5U;
112       }
113     /* We are running out of time... */
114     else { u0 = u1 = 1U; }
115   }
116   
117   time_limit     = u0 * 1000U + 1000U - time_response;
118   time_max_limit = u1 * 1000U + 1000U - time_response;
119   
120   if ( game_status & flag_puzzling )
121     {
122       time_max_limit = time_max_limit / 5U;
123       time_limit     = time_max_limit / 5U;
124     }
125
126   Out( "- time ctrl: %u -- %u\n", time_limit, time_max_limit );
127 }
128
129
130 int CONV
131 update_time( int turn )
132 {
133   unsigned int te, time_elapsed;
134   int iret;
135
136   iret = get_elapsed( &te );
137   if ( iret < 0 ) { return iret; }
138
139   time_elapsed = te - time_turn_start;
140   sec_elapsed  = time_elapsed / 1000U;
141   if ( ! sec_elapsed ) { sec_elapsed = 1U; }
142
143   if ( turn ) { sec_w_total += sec_elapsed; }
144   else        { sec_b_total += sec_elapsed; }
145   
146   time_turn_start = te;
147
148   return 1;
149 }
150
151
152 void CONV
153 adjust_time( unsigned int elapsed_new, int turn )
154 {
155   const char *str = "TIME SKEW DETECTED";
156
157   if ( turn )
158     {
159       if ( sec_w_total + elapsed_new < sec_elapsed )
160         {
161           out_warning( str );
162           sec_w_total = 0;
163         }
164       else { sec_w_total = sec_w_total + elapsed_new - sec_elapsed; };
165     }
166   else {
167     if ( sec_b_total + elapsed_new < sec_elapsed )
168       {
169         out_warning( str );
170         sec_b_total = 0;
171       }
172     else { sec_b_total = sec_b_total + elapsed_new - sec_elapsed; };
173   }
174 }
175
176
177 int CONV
178 reset_time( unsigned int b_remain, unsigned int w_remain )
179 {
180   if ( sec_limit_up == UINT_MAX )
181     {
182       str_error = "no time limit is set";
183       return -2;
184     }
185
186   if ( b_remain > sec_limit || w_remain > sec_limit )
187     {
188       snprintf( str_message, SIZE_MESSAGE,
189                 "time remaining can't be larger than %u", sec_limit );
190       str_error = str_message;
191       return -2;
192     }
193
194   sec_b_total = sec_limit - b_remain;
195   sec_w_total = sec_limit - w_remain;
196   Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
197
198   return 1;
199 }
200
201
202 const char * CONV
203 str_time( unsigned int time )
204 {
205   static char str[32];
206   unsigned int time_min = time / 60000;
207   unsigned int time_sec = time / 1000;
208   unsigned int time_mil = time % 1000;
209
210   if ( time_min < 60 )
211     {
212       snprintf( str, 32, "%02u:%02u.%02u",
213                 time_min, time_sec%60, time_mil/10 );
214     }
215   else {
216     snprintf( str, 32, "%02u:%02u:%02u.%02u",
217               time_min / 60, time_min % 60, time_sec%60, time_mil/10 );
218   }
219   return str;
220 }
221
222
223 const char * CONV
224 str_time_symple( unsigned int time )
225 {
226   static char str[32];
227   unsigned int time_min = time / 60000;
228   unsigned int time_sec = time / 1000;
229   unsigned int time_mil = time % 1000;
230
231   if ( time_min == 0 )
232     {
233       snprintf( str, 32, "%5.2f", (float)(time_sec*1000+time_mil)/1000.0 );
234     }
235   else { snprintf( str, 32, "%2u:%02u", time_min, time_sec % 60 ); }
236
237   return str;
238 }
239
240
241 int CONV
242 get_cputime( unsigned int *ptime )
243 {
244 #if defined(_WIN32)
245   HANDLE         hProcess;
246   FILETIME       CreationTime, ExitTime, KernelTime, UserTime;
247   ULARGE_INTEGER uli_temp;
248
249   hProcess = GetCurrentProcess();
250   if ( GetProcessTimes( hProcess, &CreationTime, &ExitTime,
251                         &KernelTime, &UserTime ) )
252     {
253       uli_temp.LowPart  = UserTime.dwLowDateTime;
254       uli_temp.HighPart = UserTime.dwHighDateTime;
255       *ptime = (unsigned int)( uli_temp.QuadPart / 10000 );
256     }
257   else {
258 #  if 0 /* winnt */
259     str_error = "GetProcessTimes() failed.";
260     return -1;
261 #  else /* win95 */
262     *ptime = 0U;
263 #  endif
264   }
265 #else
266   clock_t clock_temp;
267   struct tms t;
268
269   if ( times( &t ) == -1 )
270     {
271       str_error = "times() faild.";
272       return -1;
273     }
274   clock_temp = t.tms_utime + t.tms_stime + t.tms_cutime + t.tms_cstime;
275   *ptime  = (unsigned int)( clock_temp / clk_tck ) * 1000;
276   clock_temp %= clk_tck;
277   *ptime += (unsigned int)( (clock_temp * 1000) / clk_tck );
278 #endif /* no _WIN32 */
279   
280   return 1;
281 }
282
283
284 int CONV
285 get_elapsed( unsigned int *ptime )
286 {
287 #if defined(_WIN32)
288   /*
289     try timeBeginPeriod() and timeGetTime(),
290     or QueryPerformanceFrequency and QueryPerformanceCounter()
291   */
292   FILETIME       FileTime;
293   ULARGE_INTEGER uli_temp;
294
295   GetSystemTimeAsFileTime( &FileTime );
296   uli_temp.LowPart  = FileTime.dwLowDateTime;
297   uli_temp.HighPart = FileTime.dwHighDateTime;
298   *ptime            = (unsigned int)( uli_temp.QuadPart / 10000U );
299 #else
300   struct timeval timeval;
301
302   if ( gettimeofday( &timeval, NULL ) == -1 )
303     {
304       str_error = "gettimeofday() faild.";
305       return -1;
306     }
307   *ptime  = (unsigned int)timeval.tv_sec * 1000;
308   *ptime += (unsigned int)timeval.tv_usec / 1000;
309 #endif /* no _WIN32 */
310
311   return 1;
312 }