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