1 /*
2     Sjeng - a chess variants playing program
3     Copyright (C) 2000-2001 Gian-Carlo Pascutto
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19     File: utils.c
20     Purpose: misc. functions used throughout the program
21 
22 */
23 
24 #include "config.h"
25 #include "sjeng.h"
26 #include "extvars.h"
27 #include "protos.h"
28 
29 #include "limits.h"
30 #ifdef HAVE_SELECT
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 fd_set read_fds;
35 struct timeval timeout = { 0, 0 };
36 #else
37 #ifdef _WIN32
38 #undef frame
39 #include <windows.h>
40 #include <time.h>
41 #define frame 0
42 #endif
43 #endif
44 
45 /* Random number generator stuff */
46 
47 #define N              (624)
48 #define M              (397)
49 #define K              (0x9908B0DFU)
50 #define hiBit(u)       ((u) & 0x80000000U)
51 #define loBit(u)       ((u) & 0x00000001U)
52 #define loBits(u)      ((u) & 0x7FFFFFFFU)
53 #define mixBits(u, v)  (hiBit(u)|loBits(v))
54 
55 static unsigned long   state[N+1];
56 static unsigned long   *next;
57 int                    left = -1;
58 
allocate_time(void)59 long int allocate_time (void) {
60 
61   /* calculate the ammount of time the program can use in its search, measured
62      in centi-seconds (calculate everything in float for more accuracy as
63      we go, and return the result as a long int) */
64 
65   float allocated_time = 0.0, move_speed = 20.0;
66 
67   /* sudden death time allocation: */
68   if (!moves_to_tc) {
69     /* calculate move speed.  The idea is that if we are behind, we move
70        faster, and if we have < 1 min left and a small increment, we REALLY
71        need to start moving fast.  Also, if we aren't in a super fast
72        game, don't worry about being behind on the clock at the beginning,
73        because some players will make instant moves in the opening, and Sjeng
74        will play poorly if it tries to do the same. */
75 
76     /* check to see if we're behind on time and need to speed up: */
77     if ((min_per_game < 6 && !inc)
78 	|| time_left < (((min_per_game*6000) + (sec_per_game*100))*4.0/5.0))
79     {
80       if ((opp_time-time_left) > (opp_time/5.0) && xb_mode)
81 	move_speed = 40.0;
82       else if ((opp_time-time_left) > (opp_time/10.0) && xb_mode)
83 	move_speed = 30.0;
84       else if ((opp_time-time_left) > (opp_time/20.0) && xb_mode)
85 	move_speed = 25.0;
86     }
87 
88     if ((Variant != Suicide) && (Variant != Losers))
89     {
90     	if ((time_left-opp_time) > (time_left/5.0) && xb_mode)
91         	move_speed -= 10;
92     	else if ((time_left-opp_time) > (time_left/10.0) && xb_mode)
93         	move_speed -= 5;
94     }
95     else if (Variant == Suicide)
96     {
97 	move_speed -= 10;
98     }
99     else if (Variant == Losers)
100     {
101 	move_speed -= 5;
102     }
103 
104     /* allocate our base time: */
105     allocated_time = time_left/move_speed;
106 
107     /* add our increment if applicable: */
108     if (inc) {
109       if (time_left-allocated_time-inc > 500) {
110         allocated_time += inc;
111       }
112       else if (time_left-allocated_time-(inc*2.0/3.0) > 100) {
113         allocated_time += inc*2.0/3.0;
114        }
115      }
116   }
117 
118   /* conventional clock time allocation: */
119   else {
120     allocated_time = (((float)min_per_game * 6000.
121 	    + (float)sec_per_game * 100.)/(float)moves_to_tc) - 100.;
122 
123     /* if we've got extra time, use some of it: */
124     if (time_cushion) {
125       allocated_time += time_cushion*2.1/3.0;
126       time_cushion -= time_cushion*2.1/3.0;
127     }
128   }
129 
130   if (Variant == Bughouse)
131   {
132 	allocated_time *= 1./4.;
133 
134 	if ((opp_time > time_left) || (opp_time < 1500))
135 	{
136 	  /* behind on time or blitzing out */
137 	  allocated_time *= 1./2.;
138 	}
139   }
140 
141   return ((long int) allocated_time);
142 
143 }
144 
comp_to_san(move_s move,char str[])145 void comp_to_san (move_s move, char str[])
146 {
147   move_s moves[MOVE_BUFF];
148   move_s evade_moves[MOVE_BUFF];
149   char type_to_char[] = { 'F', 'P', 'P', 'N', 'N', 'K', 'K', 'R', 'R', 'Q', 'Q', 'B', 'B', 'E' };
150   int i, num_moves, evasions, ambig, mate;
151   int f_rank, t_rank, converter;
152   char f_file, t_file;
153   int ic;
154 
155   //eps = ep_square;
156 
157   f_rank = rank (move.from);
158   t_rank = rank (move.target);
159   converter = (int) 'a';
160   f_file = file (move.from)+converter-1;
161   t_file = file (move.target)+converter-1;
162 
163   if (move.from == 0)
164     {
165       sprintf (str, "%c@%c%d", type_to_char[move.promoted], t_file, t_rank);
166     }
167   else if ((board[move.from] == wpawn) || (board[move.from] == bpawn))
168     {
169       if (board[move.target] == npiece && !move.ep)
170 	{
171 	  if(!move.promoted)
172 	    {
173 	      sprintf (str, "%c%d", t_file, t_rank);
174 	    }
175 	  else
176 	    {
177 	      sprintf (str, "%c%d=%c", t_file, t_rank, type_to_char[move.promoted]);
178 	    }
179 	}
180       else
181 	{
182 	  if (!move.promoted)
183 	    {
184 	      sprintf (str, "%cx%c%d", f_file, t_file, t_rank);
185 	    }
186 	  else
187 	    {
188 	      sprintf (str, "%cx%c%d=%c", f_file, t_file, t_rank,
189 		       type_to_char[move.promoted]);
190 	    }
191 	}
192     }
193   else if (move.castled != no_castle)
194     {
195       if (move.castled == wck || move.castled == bck)
196 	{
197 	  sprintf (str, "O-O");
198 	}
199       else
200 	{
201 	  sprintf(str, "O-O-O");
202 	}
203     }
204   else
205     {
206       ambig = -1;
207       num_moves = 0;
208 
209       gen(&moves[0]);
210       num_moves = numb_moves;
211 
212       ic = in_check();
213 
214       /* check whether there is another, identical piece that
215 	 could also move to this square */
216       for(i = 0; i < num_moves; i++)
217 	{
218 	  if ((moves[i].target == move.target) &&
219 	      (board[moves[i].from] == board[move.from]) &&
220 	      (moves[i].from != move.from))
221 	    {
222 	      /* would it be a legal move ? */
223 	      make(&moves[0], i);
224 	      if (check_legal(&moves[0], i, ic))
225 		{
226 		  unmake(&moves[0], i);
227 		  ambig = i;
228 		  break;
229 		}
230 	      unmake(&moves[0], i);
231 	    }
232 	}
233 
234       if (ambig != -1)
235 	{
236 
237 	  if (board[move.target] == npiece)
238 	    {
239 	      if (file(moves[ambig].from) != file(move.from))
240 		sprintf(str, "%c%c%c%d", type_to_char[board[move.from]],
241 			f_file, t_file, t_rank);
242 	      else
243 		sprintf(str, "%c%d%c%d", type_to_char[board[move.from]],
244 			f_rank, t_file, t_rank);
245 	    }
246 	  else
247 	    {
248 	      if (file(moves[ambig].from) != file(move.from))
249 		sprintf(str, "%c%cx%c%d", type_to_char[board[move.from]],
250 			f_file, t_file, t_rank);
251 	      else
252 		sprintf(str, "%c%dx%c%d", type_to_char[board[move.from]],
253 			f_rank, t_file, t_rank);
254 	    }
255 	}
256       else
257 	{
258 	  if (board[move.target] == npiece)
259 	    {
260 	      sprintf(str, "%c%c%d", type_to_char[board[move.from]],
261 		      t_file, t_rank);
262 	    }
263 	  else
264 	    {
265 	      sprintf(str, "%cx%c%d", type_to_char[board[move.from]],
266 		      t_file, t_rank);
267 	    }
268 	}
269     }
270 
271   //ep_square = eps;
272 
273   make(&move, 0);
274 
275   if (!check_legal(&move, 0, 1))
276   {
277     strcpy(str, "illg");
278     unmake(&move, 0);
279     return;
280   }
281 
282   if (in_check())
283     {
284       mate = TRUE;
285       evasions = 0;
286       gen(&evade_moves[0]);
287       evasions = numb_moves;
288 
289       for (i = 0; i < evasions; i++)
290 	{
291 	  make(&evade_moves[0], i);
292 	  if (check_legal(&evade_moves[0], i, TRUE))
293 	    {
294 	      mate = FALSE;
295 	      unmake(&evade_moves[0], i);
296 	      break;
297 	    }
298 	  unmake(&evade_moves[0], i);
299 	}
300       if (mate == TRUE)
301 	strcat(str, "#");
302       else
303 	strcat(str, "+");
304     }
305   unmake(&move, 0);
306 
307 }
308 
comp_to_coord(move_s move,char str[])309 void comp_to_coord (move_s move, char str[]) {
310 
311   /* convert a move_s internal format move to coordinate notation: */
312 
313   int prom, from, target, f_rank, t_rank, converter;
314   char f_file, t_file;
315 
316   char type_to_char[] = { 'F', 'P', 'p', 'N', 'n', 'K', 'k', 'R', 'r', 'Q', 'q', 'B', 'b', 'E' };
317 
318   prom = move.promoted;
319   from = move.from;
320   target = move.target;
321 
322   f_rank = rank (from);
323   t_rank = rank (target);
324   converter = (int) 'a';
325   f_file = file (from)+converter-1;
326   t_file = file (target)+converter-1;
327 
328 
329   if (from == 0)
330     {
331       sprintf (str, "%c@%c%d", type_to_char[prom], t_file, t_rank);
332     }
333   else
334     {
335       /* "normal" move: */
336       if (!prom) {
337 	sprintf (str, "%c%d%c%d", f_file, f_rank, t_file, t_rank);
338       }
339 
340       /* promotion move: */
341       else {
342 	if (prom == wknight || prom == bknight) {
343 	  sprintf (str, "%c%d%c%dn", f_file, f_rank, t_file, t_rank);
344 	}
345 	else if (prom == wrook || prom == brook) {
346 	  sprintf (str, "%c%d%c%dr", f_file, f_rank, t_file, t_rank);
347 	}
348 	else if (prom == wbishop || prom == bbishop) {
349 	  sprintf (str, "%c%d%c%db", f_file, f_rank, t_file, t_rank);
350 	}
351 	else if (prom == wking || prom == bking)
352 	{
353 	  sprintf (str, "%c%d%c%dk", f_file, f_rank, t_file, t_rank);
354 	}
355 	else
356 	{
357 	  sprintf (str, "%c%d%c%dq", f_file, f_rank, t_file, t_rank);
358 	}
359       }
360     }
361 }
362 
363 
display_board(FILE * stream,int color)364 void display_board (FILE *stream, int color) {
365 
366   /* prints a text-based representation of the board: */
367 
368   char *line_sep = "+----+----+----+----+----+----+----+----+";
369   char *piece_rep[14] = {"!!", " P", "*P", " N", "*N", " K", "*K", " R",
370 			  "*R", " Q", "*Q", " B", "*B", "  "};
371   int a,b,c;
372 
373   if (color % 2) {
374     fprintf (stream, "  %s\n", line_sep);
375     for (a = 1; a <= 8; a++) {
376       fprintf (stream, "%d |", 9 - a);
377       for (b = 0; b <= 11; b++) {
378 	c = 120 - a*12 + b;
379 	if (board[c] != 0)
380 	  fprintf (stream, " %s |", piece_rep[board[c]]);
381       }
382       fprintf (stream, "\n  %s\n", line_sep);
383     }
384     fprintf (stream, "\n     a    b    c    d    e    f    g    h\n\n");
385   }
386 
387   else {
388     fprintf (stream, "  %s\n", line_sep);
389     for (a = 1; a <= 8; a++) {
390       fprintf (stream, "%d |", a);
391       for (b = 0; b <= 11; b++) {
392 	c = 24 + a*12 -b;
393 	if (board[c] != 0)
394 	  fprintf (stream, " %s |", piece_rep[board[c]]);
395       }
396       fprintf (stream, "\n  %s\n", line_sep);
397     }
398     fprintf (stream, "\n     h    g    f    e    d    c    b    a\n\n");
399   }
400 
401 }
402 
init_game(void)403 void init_game (void) {
404 
405   /* set up a new game: */
406 
407   int init_board[144] = {
408   0,0,0,0,0,0,0,0,0,0,0,0,
409   0,0,0,0,0,0,0,0,0,0,0,0,
410   0,0,7,3,11,9,5,11,3,7,0,0,
411   0,0,1,1,1,1,1,1,1,1,0,0,
412   0,0,13,13,13,13,13,13,13,13,0,0,
413   0,0,13,13,13,13,13,13,13,13,0,0,
414   0,0,13,13,13,13,13,13,13,13,0,0,
415   0,0,13,13,13,13,13,13,13,13,0,0,
416   0,0,2,2,2,2,2,2,2,2,0,0,
417   0,0,8,4,12,10,6,12,4,8,0,0,
418   0,0,0,0,0,0,0,0,0,0,0,0,
419   0,0,0,0,0,0,0,0,0,0,0,0
420   };
421 
422   memcpy (board, init_board, sizeof (init_board));
423   memset (moved, 0, sizeof(moved));
424 
425   white_to_move = 1;
426   ep_square = 0;
427   wking_loc = 30;
428   bking_loc = 114;
429   white_castled = no_castle;
430   black_castled = no_castle;
431 
432   result = no_result;
433   captures = FALSE;
434 
435   piece_count = 32;
436 
437   Material = 0;
438 
439   memset(is_promoted, 0, sizeof(is_promoted));
440   memset(holding, 0, sizeof(holding));
441 
442   white_hand_eval = 0;
443   black_hand_eval = 0;
444 
445   reset_piece_square ();
446 
447   bookidx = 0;
448   book_ply = 0;
449   fifty = 0;
450   ply = 0;
451 
452   phase = Opening;
453 }
454 
455 
is_move(char str[])456 bool is_move (char str[]) {
457 
458   /* check to see if the input string is a move or not.  Returns true if it
459      is in a move format supported by Sjeng. */
460 
461   if (isalpha (str[0]) && isdigit (str[1]) && isalpha (str[2])
462       && isdigit (str[3])) {
463     return TRUE;
464   }
465   else if (isalpha(str[0]) && str[1] == '@' && isalpha(str[2]) && isdigit(str[3]))
466     {
467       return TRUE;
468     }
469   else {
470     return FALSE;
471   }
472 
473 }
474 
475 
perft_debug(void)476 void perft_debug (void) {
477 
478   /* A function to debug the move gen by doing perft's, showing the board, and
479      accepting move input */
480 
481   char input[STR_BUFF], *p;
482   move_s move;
483   int depth;
484 
485   init_game ();
486 
487   /* go into a loop of doing a perft(), then making the moves the user inputs
488      until the user enters "exit" or "quit" */
489   while (TRUE) {
490     /* get the desired depth to generate to: */
491     printf ("\n\nPlease enter the desired depth for perft():\n");
492     rinput (input, STR_BUFF, stdin);
493     depth = atoi (input);
494 
495     /* print out the number of raw nodes for this depth: */
496     raw_nodes = 0;
497     perft (depth);
498     printf ("\n\nRaw nodes for depth %d: %ld\n\n", depth, raw_nodes);
499 
500     /* print out the board: */
501     display_board (stdout, 1);
502 
503     printf ("\nPlease input a move/command:\n");
504     rinput (input, STR_BUFF, stdin);
505 
506     /* check to see if we have an exit/quit: */
507     for (p = input; *p; p++) *p = tolower (*p);
508     if (!strcmp (input, "exit") || !strcmp (input, "quit")) {
509       exit (EXIT_SUCCESS);
510     }
511 
512     if (!verify_coord (input, &move)) {
513       /* loop until we get a legal move or an exit/quit: */
514       do {
515 	printf ("\nIllegal move/command!  Please input a new move/command:\n");
516 	rinput (input, STR_BUFF, stdin);
517 
518 	/* check to see if we have an exit/quit: */
519 	for (p = input; *p; p++) *p = tolower (*p);
520 	if (!strcmp (input, "exit") || !strcmp (input, "quit")) {
521 	  exit (EXIT_SUCCESS);
522 	}
523       } while (!verify_coord (input, &move));
524     }
525 
526     make (&move, 0);
527   }
528 }
529 
hash_extract_pv(int level,char str[])530 void hash_extract_pv(int level, char str[])
531 {
532   int dummy, bm;
533   move_s moves[MOVE_BUFF];
534   int num_moves;
535   char output[STR_BUFF];
536 
537   /* avoid loop on repetitions */
538   level--;
539   if (!level) return;
540 
541   if(ProbeTT(&dummy, 0, 0, &bm, &dummy, &dummy, 0) != HMISS)
542     {
543       gen(&moves[0]);
544       num_moves = numb_moves;
545       if ((bm >= 0) && (bm < num_moves))
546 	{
547 	  comp_to_san(moves[bm], output);
548 	  make(&moves[0], bm);
549 	  if (check_legal(&moves[0], bm, 1))
550 	    {
551 	      /* only print move AFTER legal check is done */
552 	      strcat(str, "<");
553 	      strcat(str, output);
554 	      strcat(str, "> ");
555 	      hash_extract_pv(level, str);
556 	    }
557 	  unmake(&moves[0], bm);
558 	}
559     }
560 }
561 
stringize_pv(char str[])562 void stringize_pv (char str[])
563 {
564   char output[STR_BUFF];
565   int i;
566 
567   memset(str, 0, STR_BUFF);
568 
569    for (i = 1; i < pv_length[1]; i++)
570    {
571         	comp_to_san (pv[1][i], output);
572           	make(&pv[1][i], 0);
573           	strcat (str, output);
574 	  	strcat (str, " ");
575    }
576 
577    hash_extract_pv(7, str);
578 
579    for (i = (pv_length[1]-1); i > 0; i--)
580    {
581    	unmake(&pv[1][i], 0);
582    }
583 
584 }
585 
post_thinking(long int score)586 void post_thinking (long int score) {
587 
588   /* post our thinking output: */
589 
590   int i, remake = 0;
591   long int elapsed;
592   char output[STR_BUFF];
593   char hashpv[STR_BUFF];
594 
595   /* in xboard mode, follow xboard conventions for thinking output, otherwise
596      output the iterative depth, human readable score, and the pv */
597 /*  if (xb_mode) {*/
598     elapsed = rdifftime (rtime (), start_time);
599     printf ("%2d %7ld %5ld %8ld  ", i_depth, score, elapsed, nodes);
600 
601     /* if root move is already/still played, back it up */
602     /* 25-06-2000 our en passant info is unrecoverable here
603        so we cannot gen.... */
604 
605     if (((pv[1][1].from != 0) && (board[pv[1][1].from] == npiece))
606 	|| ((pv[1][1].from == 0) && (board[pv[1][1].target] != npiece)))
607       {
608 	unmake(&pv[1][1], 0);
609 	remake = 1;
610       }
611 
612    for (i = 1; i < pv_length[1]; i++) {
613      comp_to_san (pv[1][i], output);
614      make(&pv[1][i], 0);
615      printf ("%s ", output);
616    }
617 
618    memset(hashpv, 0, sizeof(hashpv));
619 
620    hash_extract_pv(7, hashpv);
621 
622    printf("%s", hashpv);
623 
624    for (i = (pv_length[1]-1); i > 0; i--)
625      {
626            unmake(&pv[1][i], 0);
627      }
628    if (remake)
629      make(&pv[1][1], 0);
630 
631   printf ("\n");
632 }
633 
post_fail_thinking(long int score,move_s * failmove)634 void post_fail_thinking(long int score, move_s *failmove)
635 {
636 
637   /* post our thinking output: */
638 
639   long int elapsed;
640   char output[STR_BUFF];
641 
642   /* in xboard mode, follow xboard conventions for thinking output, otherwise
643      output the iterative depth, human readable score, and the pv */
644     elapsed = rdifftime (rtime (), start_time);
645     printf ("%2d %7ld %5ld %8ld  ", i_depth, score, elapsed, nodes);
646     unmake(failmove, 0);
647     comp_to_san (*failmove, output);
648     make(failmove, 0);
649     printf ("%s !", output);
650     printf ("\n");
651 }
652 
post_fh_thinking(long int score,move_s * failmove)653 void post_fh_thinking(long int score, move_s *failmove)
654 {
655   /* post our thinking output: */
656 
657   long int elapsed;
658   char output[STR_BUFF];
659 
660   /* in xboard mode, follow xboard conventions for thinking output, otherwise
661      output the iterative depth, human readable score, and the pv */
662     elapsed = rdifftime (rtime (), start_time);
663     printf ("%2d %7ld %5ld %8ld  ", i_depth, score, elapsed, nodes);
664     unmake(failmove, 0);
665     comp_to_san (*failmove, output);
666     make(failmove, 0);
667     printf ("%s !!", output);
668     printf ("\n");
669 }
670 
post_fl_thinking(long int score,move_s * failmove)671 void post_fl_thinking(long int score, move_s *failmove)
672 {
673   /* post our thinking output: */
674 
675   long int elapsed;
676   char output[STR_BUFF];
677 
678   /* in xboard mode, follow xboard conventions for thinking output, otherwise
679      output the iterative depth, human readable score, and the pv */
680     elapsed = rdifftime (rtime (), start_time);
681     printf ("%2d %7ld %5ld %8ld  ", i_depth, score, elapsed, nodes);
682     unmake(failmove, 0);
683     comp_to_san (*failmove, output);
684     make(failmove, 0);
685     printf ("%s ??", output);
686     printf ("\n");
687 }
688 
post_stat_thinking(void)689 void post_stat_thinking(void)
690 {
691   /* post our thinking output: */
692 
693   long int elapsed;
694 
695   elapsed = rdifftime (rtime (), start_time);
696 
697   if (xb_mode == 1)
698   {
699     printf ("stat01: %ld %ld %d %d %d\n", elapsed, nodes, i_depth, moveleft, movetotal);
700   }
701   else if (xb_mode == 2)
702   {
703     printf ("stat01: %ld %ld %d %d %d %s\n", elapsed, nodes, i_depth, moveleft, movetotal, searching_move);
704   }
705 }
706 
707 
print_move(move_s moves[],int m,FILE * stream)708 void print_move (move_s moves[], int m, FILE *stream) {
709 
710   /* print out a move */
711 
712   char move[STR_BUFF];
713 
714   comp_to_san (moves[m], move);
715 
716   fprintf (stream, "%s", move);
717 
718 }
719 
720 
rdelay(int time_in_s)721 void rdelay (int time_in_s) {
722 
723   /* My delay function to cause a delay of time_in_s seconds */
724 
725   rtime_t time1, time2;
726   long int timer = 0;
727 
728   time1 = rtime ();
729   while (timer/100 < time_in_s) {
730     time2 = rtime ();
731     timer = rdifftime (time2, time1);
732   }
733 
734 }
735 
736 
rdifftime(rtime_t end,rtime_t start)737 long int rdifftime (rtime_t end, rtime_t start) {
738 
739   /* determine the time taken between start and the current time in
740      centi-seconds */
741 
742   /* using ftime(): */
743 #if defined(HAVE_SYS_TIMEB_H) && (defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY))
744   return ((end.time-start.time)*100 + (end.millitm-start.millitm)/10);
745 
746   /* -------------------------------------------------- */
747 
748   /* using time(): */
749 #else
750   return (100*(long int) difftime (end, start));
751 #endif
752 
753 }
754 
755 
check_piece_square(void)756 void check_piece_square (void)
757 {
758   int i;
759 
760   for (i = 1; i <= piece_count; i++)
761   {
762     if (squares[pieces[i]] != i && pieces[i] != 0)
763     {
764       printf("Piece->square->piece inconsistency\n");
765       display_board(stdout, 0);
766       DIE;
767     }
768       if (board[pieces[i]] == npiece && pieces[i] != 0)
769       {
770 	printf("Board/Piece->square inconsistency\n");
771         display_board(stdout, 0);
772 	DIE;
773       }
774 	if (pieces[i] == 0 && squares[pieces[i]] != 0)
775     {
776       printf("Zero-ed piece inconsistency\n");
777       display_board(stdout, 0);
778       DIE;
779     }
780   }
781   for (i = 0; i < 144; i++)
782   {
783     if ((board[i] == npiece || board[i] == frame) && squares[i] != 0)
784     {
785       printf("Empty square has piece pointer\n");
786       display_board(stdout, 0);
787       DIE;
788     }
789     if (board[i] != npiece && board[i] != frame && squares[i] == 0)
790     {
791       printf("Filled square %d has no piece pointer\n", i);
792       display_board(stdout, 0);
793       DIE;
794     }
795     if (pieces[squares[i]] != i && squares[i] != 0)
796     {
797       printf("Square->piece->square inconsistency\n");
798       display_board(stdout, 0);
799       DIE;
800     }
801   }
802 }
803 
reset_piece_square(void)804 void reset_piece_square (void) {
805 
806   /* we use piece number 0 to show a piece taken off the board, so don't
807      use that piece number for other things: */
808 
809    /* reset the piece / square tables: */
810 
811    int i, promoted_board[144];
812 
813    memset(promoted_board, 0, sizeof(promoted_board));
814 
815    /* save our promoted info as we cant determine it from the board */
816 
817    for (i = 1; i <= piece_count; i++)
818      if(is_promoted[i])
819 	 promoted_board[pieces[i]] = 1;
820 
821    Material = 0;
822 
823    piece_count = 0;
824 
825    memset(pieces, 0, sizeof(pieces));
826    memset(is_promoted, 0, sizeof(is_promoted));
827 
828    pieces[0] = 0;
829 
830    for (i = 26; i < 118; i++)
831      if (board[i] && (board[i] < npiece)) {
832 
833        AddMaterial(board[i]);
834 
835        piece_count += 1;
836 
837        pieces[piece_count] = i;
838        squares[i] = piece_count;
839 
840        /* restored promoted info */
841        if (promoted_board[i])
842 	 is_promoted[piece_count] = 1;
843      }
844      else
845 	squares[i] = 0;
846 }
847 
848 
rinput(char str[],int n,FILE * stream)849 void rinput (char str[], int n, FILE *stream) {
850 
851   /* My input function - reads in up to n-1 characters from stream, or until
852      we encounter a \n or an EOF.  Appends a null character at the end of the
853      string, and stores the string in str[] */
854 
855   int ch, i = 0;
856 
857   while ((ch = getc (stream)) != (int) '\n' && ch != EOF) {
858     if (i < n-1) {
859       str[i++] = ch;
860     }
861   }
862 
863   str [i] = '\0';
864 
865 }
866 
rtime(void)867 rtime_t rtime (void) {
868 
869   /* using ftime(): */
870 #if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H)
871   rtime_t temp;
872   ftime(&temp);
873   return (temp);
874 
875   /* -------------------------------------------------- */
876 
877   /* gettimeofday replacement by Daniel Clausen */
878 #else
879 #if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIMEB_H)
880   rtime_t temp;
881   struct timeval tmp;
882 
883   gettimeofday(&tmp, NULL);
884   temp.time = tmp.tv_sec;
885   temp.millitm = tmp.tv_usec / 1000;
886   temp.timezone = 0;
887   temp.dstflag = 0;
888 
889   return (temp);
890 
891 #else
892   return (time (0));
893 #endif
894 #endif
895 
896 }
897 
898 
start_up(void)899 void start_up (void) {
900 
901   /* things to do on start up of the program */
902 
903   printf("\nSjeng version " VERSION ", Copyright (C) 2000-2001 Gian-Carlo Pascutto\n\n"
904          "Sjeng comes with ABSOLUTELY NO WARRANTY; for details type 'warranty'\n"
905          "This is free software, and you are welcome to redistribute it\n"
906          "under certain conditions; type 'distribution'\n\n");
907 }
908 
909 
toggle_bool(bool * var)910 void toggle_bool (bool *var) {
911 
912   /* toggle FALSE -> TRUE, TRUE -> FALSE */
913 
914   if (*var) {
915     *var = FALSE;
916   }
917   else {
918     *var = TRUE;
919   }
920 
921 }
922 
923 
tree_debug(void)924 void tree_debug (void) {
925 
926   /* A function to make a tree of output at a certain depth and print out
927      the number of nodes: */
928 
929   char input[STR_BUFF];
930   FILE *stream;
931   int depth;
932 
933   init_game ();
934 
935   /* get the desired depth to generate to: */
936   printf ("\nPlease enter the desired depth:\n");
937   rinput (input, STR_BUFF, stdin);
938   depth = atoi (input);
939 
940   /* does the user want to output tree () ? */
941   printf ("\nDo you want tree () output?  (y/n)\n");
942   rinput (input, STR_BUFF, stdin);
943   if (input[0] == 'y') {
944     /* get our output file: */
945     printf ("\nPlease enter the name of the output file for tree ():\n");
946     rinput (input, STR_BUFF, stdin);
947     if ((stream = fopen (input, "w")) == NULL) {
948       fprintf (stderr, "Couldn't open file %s\n", input);
949     }
950 
951     /* does the user want to output diagrams? */
952     printf ("\nDo you want to output diagrams? (y/n)\n");
953     rinput (input, STR_BUFF, stdin);
954 
955     tree (depth, 0, stream, input);
956   }
957 
958   /* print out the number of raw nodes for this depth: */
959   raw_nodes = 0;
960   perft (depth);
961   printf ("\n\n%s\nRaw nodes for depth %d: %ld\n%s\n\n", divider,
962 	  depth, raw_nodes, divider);
963 
964 }
965 
966 
verify_coord(char input[],move_s * move)967 bool verify_coord (char input[], move_s *move) {
968 
969   /* checks to see if the move the user entered was legal or not, returns
970      true if the move was legal, and stores the legal move inside move */
971 
972   move_s moves[MOVE_BUFF];
973   int num_moves, i;
974   char comp_move[6];
975   bool legal = FALSE;
976   bool mate;
977 
978   if (Variant == Losers)
979     {
980       captures = TRUE;
981       num_moves = 0;
982       gen (&moves[0]);
983       num_moves = numb_moves;
984       captures = FALSE;
985 
986       mate = TRUE;
987 
988       for (i = 0; i < num_moves; i++)
989 	{
990 	  make (&moves[0], i);
991 
992 	  /* check to see if our move is legal: */
993 	  if (check_legal (&moves[0], i, TRUE))
994 	    {
995 	      mate = FALSE;
996 	      unmake(&moves[0], i);
997 	      break;
998 	    };
999 
1000 	  unmake(&moves[0], i);
1001 	}
1002 
1003       if (mate == TRUE)
1004 	{
1005 	  /* no legal capture..do non-captures */
1006 	  captures = FALSE;
1007 	  num_moves = 0;
1008 	  gen (&moves[0]);
1009 	  num_moves = numb_moves;
1010 	}
1011     }
1012   else
1013     {
1014       gen (&moves[0]);
1015       num_moves = numb_moves;
1016     }
1017 
1018   /* compare user input to the generated moves: */
1019   for (i = 0; i < num_moves; i++) {
1020     comp_to_coord (moves[i], comp_move);
1021     if (!strcasecmp (input, comp_move)) {
1022       make (&moves[0], i);
1023       if (check_legal (&moves[0], i, TRUE)) {
1024 	legal = TRUE;
1025 	*move = moves[i];
1026       }
1027       unmake (&moves[0], i);
1028     }
1029   }
1030 
1031   return (legal);
1032 
1033 }
1034 
interrupt(void)1035 int interrupt(void)
1036 {
1037   int c;
1038 
1039 #ifdef HAVE_SELECT
1040   FD_ZERO(&read_fds);
1041   FD_SET(0,&read_fds);
1042   timeout.tv_sec = timeout.tv_usec = 0;
1043   select(1,&read_fds,NULL,NULL,&timeout);
1044   if(FD_ISSET(0,&read_fds))
1045     {
1046       c = getc(stdin);
1047 
1048       if (c == '?')   /*Move now*/
1049 	{
1050 	  return 1;
1051 	}
1052       else if (c == '.')     /* Stat request */
1053 	{
1054 	  getc(stdin);
1055 	  post_stat_thinking();
1056 	  return 0;
1057 	}
1058 
1059       ungetc(c, stdin);
1060 
1061       if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1062 
1063       return 1;
1064     }
1065   else return 0;
1066 #else
1067 #ifdef _WIN32
1068   static int init = 0, pipe;
1069   static HANDLE inh;
1070   DWORD dw;
1071   if(xb_mode) {     /* winboard interrupt code taken from crafty */
1072     if (!init) {
1073       init = 1;
1074       inh = GetStdHandle(STD_INPUT_HANDLE);
1075       pipe = !GetConsoleMode(inh, &dw);
1076       if (!pipe) {
1077 	SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT|ENABLE_WINDOW_INPUT));
1078 	FlushConsoleInputBuffer(inh);
1079       }
1080     }
1081     if(pipe) {
1082       if(!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL))
1083 	{
1084 	  c = getc(stdin);
1085 
1086 	  if (c == '?')   /*Move now*/
1087 	    {
1088 	      return 1;
1089 	    }
1090 	  else if (c == '.')     /* Stat request */
1091 	    {
1092 	      getc(stdin);
1093 	      post_stat_thinking();
1094 	      return 0;
1095 	    }
1096 
1097 	  ungetc(c, stdin);
1098 
1099 	  if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1100 
1101 	  return 1;
1102 	}
1103       if (dw)
1104 	{
1105 	  c = getc(stdin);
1106 
1107 	  if (c == '?')   /*Move now*/
1108 	    {
1109 	      return 1;
1110 	    }
1111 	  else if (c == '.')     /* Stat request */
1112 	    {
1113 	      getc(stdin);
1114 	      post_stat_thinking();
1115 	      return 0;
1116 	    }
1117 
1118 	  ungetc(c, stdin);
1119 
1120 	  if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1121 
1122 	  return 1;
1123 	}
1124       else return 0;
1125     } else {
1126       GetNumberOfConsoleInputEvents(inh, &dw);
1127       if (dw <= 1)
1128 	{
1129 	  return 0;
1130 	}
1131       else
1132 	{
1133 	  c = getc(stdin);
1134 
1135 	  if (c == '?')   /*Move now*/
1136 	    {
1137 	      return 1;
1138 	    }
1139 	  else if (c == '.')     /* Stat request */
1140 	    {
1141 	      getc(stdin);
1142 	      post_stat_thinking();
1143 	      return 0;
1144 	    }
1145 
1146 	  ungetc(c, stdin);
1147 
1148 	  if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1149 
1150 	  return 1;
1151 	};
1152     }
1153   }
1154 #else
1155 #endif
1156 #endif
1157 
1158   return 0;
1159 }
1160 
PutPiece(int color,char piece,char pfile,int prank)1161 void PutPiece(int color, char piece, char pfile, int prank)
1162 {
1163   int converterf = (int) 'a';
1164   int converterr = (int) '1';
1165   int norm_file, norm_rank, norm_square;
1166 
1167   norm_file = pfile - converterf;
1168   norm_rank = prank - converterr;
1169 
1170   norm_square = ((norm_rank * 12) + 26) + (norm_file);
1171 
1172   if (color == WHITE)
1173     {
1174       switch (piece)
1175 	{
1176 	case 'p':
1177 	  board[norm_square] = wpawn;
1178 	  break;
1179 	case 'n':
1180 	  board[norm_square] = wknight;
1181 	  break;
1182 	case 'b':
1183 	  board[norm_square] = wbishop;
1184 	  break;
1185 	case 'r':
1186 	  board[norm_square] = wrook;
1187 	  break;
1188 	case 'q':
1189 	  board[norm_square] = wqueen;
1190 	  break;
1191 	case 'k':
1192 	  board[norm_square] = wking;
1193 	  break;
1194 	case 'x':
1195 	  board[norm_square] = npiece;
1196 	  break;
1197 	}
1198     }
1199   else if (color == BLACK)
1200     {
1201       switch (piece)
1202 	{
1203 	case 'p':
1204 	  board[norm_square] = bpawn;
1205 	  break;
1206 	case 'n':
1207 	  board[norm_square] = bknight;
1208 	  break;
1209 	case 'b':
1210 	  board[norm_square] = bbishop;
1211 	  break;
1212 	case 'r':
1213 	  board[norm_square] = brook;
1214 	  break;
1215 	case 'q':
1216 	  board[norm_square] = bqueen;
1217 	  break;
1218 	case 'k':
1219 	  board[norm_square] = bking;
1220 	  break;
1221 	case 'x':
1222 	  board[norm_square] = npiece;
1223 	  break;
1224 	}
1225     }
1226 
1227   return;
1228 }
1229 
reset_board(void)1230 void reset_board (void) {
1231 
1232   /* set up an empty  game: */
1233 
1234   int i;
1235 
1236   int init_board[144] = {
1237     0,0,0,0,0,0,0,0,0,0,0,0,
1238     0,0,0,0,0,0,0,0,0,0,0,0,
1239     0,0,13,13,13,13,13,13,13,13,0,0,
1240     0,0,13,13,13,13,13,13,13,13,0,0,
1241     0,0,13,13,13,13,13,13,13,13,0,0,
1242     0,0,13,13,13,13,13,13,13,13,0,0,
1243     0,0,13,13,13,13,13,13,13,13,0,0,
1244     0,0,13,13,13,13,13,13,13,13,0,0,
1245     0,0,13,13,13,13,13,13,13,13,0,0,
1246     0,0,13,13,13,13,13,13,13,13,0,0,
1247     0,0,0,0,0,0,0,0,0,0,0,0,
1248     0,0,0,0,0,0,0,0,0,0,0,0
1249   };
1250 
1251   memcpy (board, init_board, sizeof (init_board));
1252   for (i = 0; i <= 143; i++)
1253     moved[i] = 0;
1254 
1255   ep_square = 0;
1256 
1257   piece_count = 0;
1258 
1259   Material = 0;
1260 
1261   memset(is_promoted, 0, sizeof(is_promoted));
1262   memset(holding, 0, sizeof(holding));
1263 
1264   white_hand_eval = 0;
1265   black_hand_eval = 0;
1266 
1267   bookidx = 0;
1268   fifty = 0;
1269 
1270   reset_piece_square ();
1271 
1272 }
1273 
speed_test(void)1274 void speed_test(void)
1275 {
1276   move_s moves[MOVE_BUFF];
1277   int i, j;
1278   clock_t cpu_start, cpu_end;
1279   float et;
1280   int ic;
1281 
1282   /* LCT2 Pos 1 */
1283   setup_epd_line("r3kb1r/3n1pp1/p6p/2pPp2q/Pp2N3/3B2PP/1PQ2P2/R3K2R w KQkq");
1284 
1285   cpu_start = clock ();
1286 
1287   for (i = 0; i < 5000000; i++)
1288     {
1289       gen (&moves[0]);
1290     }
1291 
1292   cpu_end = clock ();
1293   et = (cpu_end-cpu_start)/(double) CLOCKS_PER_SEC;
1294 
1295   printf("Movegen speed: %d/s\n", (int)(5000000.0/et));
1296   j = 0;
1297 
1298   cpu_start = clock ();
1299 
1300   for (i = 0; i < 50000000; i++)
1301     {
1302       make (&moves[0], j);
1303       unmake (&moves[0], j);
1304 
1305       if ((j+1) < numb_moves) j++;
1306       else j = 0;
1307     }
1308 
1309   cpu_end = clock ();
1310   et = (cpu_end-cpu_start)/(double) CLOCKS_PER_SEC;
1311 
1312   printf("Make+unmake speed: %d/s\n", (int)(50000000.0/et));
1313 
1314   j = 0;
1315 
1316   ic = in_check();
1317 
1318   cpu_start = clock ();
1319 
1320   for (i = 0; i < 50000000; i++)
1321     {
1322       make (&moves[0], j);
1323 
1324       check_legal(&moves[0], j, ic);
1325 
1326       unmake (&moves[0], j);
1327 
1328       if ((j+1) < numb_moves) j++;
1329       else j = 0;
1330     }
1331 
1332   cpu_end = clock ();
1333   et = (cpu_end-cpu_start)/(double) CLOCKS_PER_SEC;
1334 
1335   printf("Movecycle speed: %d/s\n", (int)(50000000.0/et));
1336 
1337   reset_ecache();
1338 
1339   cpu_start = clock ();
1340 
1341   for (i = 0; i < 10000000; i++)
1342     {
1343       eval();
1344       /* invalidate the ecache */
1345       hash = (++hash) % ULONG_MAX;
1346     }
1347 
1348   cpu_end = clock ();
1349   et = (cpu_end-cpu_start)/(double) CLOCKS_PER_SEC;
1350 
1351   printf("Eval speed: %d/s\n", (int)(10000000.0/et));
1352 
1353   /* restore the hash */
1354   initialize_hash();
1355 
1356 }
1357 
1358 /* Mersenne Twister */
1359 
seedMT(unsigned long seed)1360 void seedMT(unsigned long seed)
1361 {
1362   register unsigned long x = (seed | 1U) & 0xFFFFFFFFU, *s = state;
1363   register int    j;
1364 
1365   for(left=0, *s++=x, j=N; --j;
1366       *s++ = (x*=69069U) & 0xFFFFFFFFU);
1367 }
1368 
reloadMT(void)1369 unsigned long reloadMT(void)
1370 {
1371   register unsigned long *p0=state, *p2=state+2, *pM=state+M, s0, s1;
1372   register int    j;
1373 
1374   if(left < -1)
1375     seedMT(4357U);
1376 
1377   left=N-1, next=state+1;
1378 
1379   for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
1380     *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
1381 
1382   for(pM=state, j=M; --j; s0=s1, s1=*p2++)
1383     *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
1384 
1385   s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
1386   s1 ^= (s1 >> 11);
1387   s1 ^= (s1 <<  7) & 0x9D2C5680U;
1388   s1 ^= (s1 << 15) & 0xEFC60000U;
1389   return(s1 ^ (s1 >> 18));
1390 }
1391 
randomMT(void)1392 unsigned long randomMT(void)
1393 {
1394   unsigned long y;
1395 
1396   if(--left < 0)
1397     return(reloadMT());
1398 
1399   y  = *next++;
1400   y ^= (y >> 11);
1401   y ^= (y <<  7) & 0x9D2C5680U;
1402   y ^= (y << 15) & 0xEFC60000U;
1403   return(y ^ (y >> 18));
1404 }
1405