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