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