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>
34fd_set read_fds;
35struct 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
55static uint32_t   state[N+1];
56static uint32_t   *next;
57int                    left = -1;
58
59int32_t 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 int32_t) */
64
65  float allocated_time = 0.0f, move_speed = 20.0f;
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.0f;
82      else if ((opp_time-time_left) > (opp_time/10.0) && xb_mode)
83	move_speed = 30.0f;
84      else if ((opp_time-time_left) > (opp_time/20.0) && xb_mode)
85	move_speed = 25.0f;
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.0f/3.0f;
114       }
115     }
116  }
117
118  /* conventional clock time allocation: */
119  else {
120    allocated_time = (((float)min_per_game * 6000.0f
121	    + (float)sec_per_game * 100.0f)/(float)moves_to_tc) - 100.0f;
122
123    /* if we've got extra time, use some of it: */
124    if (time_cushion) {
125      allocated_time += time_cushion*2.1f/3.0f;
126      time_cushion -= time_cushion*2.1f/3.0f;
127    }
128  }
129
130  if (Variant == Bughouse)
131  {
132	allocated_time *= 1.0f/4.0f;
133
134	if ((opp_time > time_left) || (opp_time < 1500))
135	{
136	  /* behind on time or blitzing out */
137	  allocated_time *= 1.0f/2.0f;
138	}
139  }
140
141  return ((int32_t) allocated_time);
142
143}
144
145void 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
309void 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
364void 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
403void 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  /* reset_piece_square fills these in */
436  piece_count = 0;
437
438  Material = 0;
439
440  memset(pieces, 0, sizeof(pieces));
441  memset(is_promoted, 0, sizeof(is_promoted));
442  memset(holding, 0, sizeof(holding));
443
444  white_hand_eval = 0;
445  black_hand_eval = 0;
446
447  reset_piece_square ();
448
449  bookidx = 0;
450  book_ply = 0;
451  fifty = 0;
452  ply = 0;
453
454  phase = Opening;
455}
456
457
458bool is_move (char str[]) {
459
460  /* check to see if the input string is a move or not.  Returns true if it
461     is in a move format supported by Sjeng. */
462
463  if (isalpha (str[0]) && isdigit (str[1]) && isalpha (str[2])
464      && isdigit (str[3])) {
465    return TRUE;
466  }
467  else if (isalpha(str[0]) && str[1] == '@' && isalpha(str[2]) && isdigit(str[3]))
468    {
469      return TRUE;
470    }
471  else {
472    return FALSE;
473  }
474
475}
476
477
478void perft_debug (void) {
479
480  /* A function to debug the move gen by doing perft's, showing the board, and
481     accepting move input */
482
483  char input[STR_BUFF], *p;
484  move_s move;
485  int depth;
486
487  init_game ();
488
489  /* go into a loop of doing a perft(), then making the moves the user inputs
490     until the user enters "exit" or "quit" */
491  while (TRUE) {
492    /* get the desired depth to generate to: */
493    printf ("\n\nPlease enter the desired depth for perft():\n");
494    rinput (input, STR_BUFF, stdin);
495    depth = atoi (input);
496
497    /* print out the number of raw nodes for this depth: */
498    raw_nodes = 0;
499    perft (depth);
500    printf ("\n\nRaw nodes for depth %d: %d\n\n", depth, raw_nodes);
501
502    /* print out the board: */
503    display_board (stdout, 1);
504
505    printf ("\nPlease input a move/command:\n");
506    rinput (input, STR_BUFF, stdin);
507
508    /* check to see if we have an exit/quit: */
509    for (p = input; *p; p++) *p = tolower (*p);
510    if (!strcmp (input, "exit") || !strcmp (input, "quit")) {
511      exit (EXIT_SUCCESS);
512    }
513
514    if (!verify_coord (input, &move)) {
515      /* loop until we get a legal move or an exit/quit: */
516      do {
517	printf ("\nIllegal move/command!  Please input a new move/command:\n");
518	rinput (input, STR_BUFF, stdin);
519
520	/* check to see if we have an exit/quit: */
521	for (p = input; *p; p++) *p = tolower (*p);
522	if (!strcmp (input, "exit") || !strcmp (input, "quit")) {
523	  exit (EXIT_SUCCESS);
524	}
525      } while (!verify_coord (input, &move));
526    }
527
528    make (&move, 0);
529  }
530}
531
532void hash_extract_pv(int level, char str[])
533{
534  int dummy, bm;
535  move_s moves[MOVE_BUFF];
536  int num_moves;
537  char output[STR_BUFF];
538
539  /* avoid loop on repetitions */
540  level--;
541  if (!level) return;
542
543  if(ProbeTT(&dummy, 0, 0, &bm, &dummy, &dummy, 0) != HMISS)
544    {
545      gen(&moves[0]);
546      num_moves = numb_moves;
547      if ((bm >= 0) && (bm < num_moves))
548	{
549	  comp_to_san(moves[bm], output);
550	  make(&moves[0], bm);
551	  if (check_legal(&moves[0], bm, 1))
552	    {
553	      /* only print move AFTER legal check is done */
554	      strcat(str, "<");
555	      strcat(str, output);
556	      strcat(str, "> ");
557	      hash_extract_pv(level, str);
558	    }
559	  unmake(&moves[0], bm);
560	}
561    }
562}
563
564void stringize_pv (char str[])
565{
566  char output[STR_BUFF];
567  int i;
568
569  memset(str, 0, STR_BUFF);
570
571   for (i = 1; i < pv_length[1]; i++)
572   {
573        	comp_to_san (pv[1][i], output);
574          	make(&pv[1][i], 0);
575          	strcat (str, output);
576	  	strcat (str, " ");
577   }
578
579   hash_extract_pv(7, str);
580
581   for (i = (pv_length[1]-1); i > 0; i--)
582   {
583   	unmake(&pv[1][i], 0);
584   }
585
586}
587
588void post_thinking (int32_t score) {
589
590  /* post our thinking output: */
591  char output[STR_BUFF];
592
593  /* if root move is already/still played, back it up */
594  /* 25-06-2000 our en passant info is unrecoverable here
595	 so we cannot gen.... */
596
597  if (pv_length[1]) {
598	  comp_to_coord (pv[1][1], output);
599	  printf ("ponder %s\n", output);
600  }
601}
602
603void post_fail_thinking(int32_t score, move_s *failmove)
604{
605  /* post our thinking output: */
606
607  char output[STR_BUFF];
608
609  /* in xboard mode, follow xboard conventions for thinking output, otherwise
610     output the iterative depth, human readable score, and the pv */
611  comp_to_coord (*failmove, output);
612  printf ("ponder %s\n", output);
613}
614
615void post_fh_thinking(int32_t score, move_s *failmove)
616{
617  /* post our thinking output: */
618
619  char output[STR_BUFF];
620
621  /* in xboard mode, follow xboard conventions for thinking output, otherwise
622     output the iterative depth, human readable score, and the pv */
623  comp_to_coord (*failmove, output);
624  printf ("ponder %s\n", output);
625}
626
627void post_fl_thinking(int32_t score, move_s *failmove)
628{
629}
630
631void post_stat_thinking(void)
632{
633  /* post our thinking output: */
634
635  int32_t elapsed;
636
637  elapsed = rdifftime (rtime (), start_time);
638
639  if (xb_mode == 1)
640  {
641    printf ("stat01: %d %d %d %d %d\n", elapsed, nodes, i_depth, moveleft, movetotal);
642  }
643  else if (xb_mode == 2)
644  {
645    printf ("stat01: %d %d %d %d %d %s\n", elapsed, nodes, i_depth, moveleft, movetotal, searching_move);
646  }
647}
648
649
650void print_move (move_s moves[], int m, FILE *stream) {
651
652  /* print out a move */
653
654  char move[STR_BUFF];
655
656  comp_to_san (moves[m], move);
657
658  fprintf (stream, "%s", move);
659
660}
661
662
663void rdelay (int time_in_s) {
664
665  /* My delay function to cause a delay of time_in_s seconds */
666
667  rtime_t time1, time2;
668  int32_t timer = 0;
669
670  time1 = rtime ();
671  while (timer/100 < time_in_s) {
672    time2 = rtime ();
673    timer = rdifftime (time2, time1);
674  }
675
676}
677
678
679int32_t rdifftime (rtime_t end, rtime_t start) {
680
681  /* determine the time taken between start and the current time in
682     centi-seconds */
683
684  /* using ftime(): */
685#if defined(HAVE_SYS_TIMEB_H) && (defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY))
686	return (int32_t)((end.time-start.time)*100 + (end.millitm-start.millitm)/10);
687
688  /* -------------------------------------------------- */
689
690  /* using time(): */
691#else
692  return (100*(int32_t) difftime (end, start));
693#endif
694
695}
696
697
698void check_piece_square (void)
699{
700  int i;
701
702  for (i = 1; i <= piece_count; i++)
703  {
704    if (squares[pieces[i]] != i && pieces[i] != 0)
705    {
706      printf("Piece->square->piece inconsistency\n");
707      display_board(stdout, 0);
708      DIE;
709    }
710      if (board[pieces[i]] == npiece && pieces[i] != 0)
711      {
712	printf("Board/Piece->square inconsistency\n");
713        display_board(stdout, 0);
714	DIE;
715      }
716	if (pieces[i] == 0 && squares[pieces[i]] != 0)
717    {
718      printf("Zero-ed piece inconsistency\n");
719      display_board(stdout, 0);
720      DIE;
721    }
722  }
723  for (i = 0; i < 144; i++)
724  {
725    if ((board[i] == npiece || board[i] == frame) && squares[i] != 0)
726    {
727      printf("Empty square has piece pointer\n");
728      display_board(stdout, 0);
729      DIE;
730    }
731    if (board[i] != npiece && board[i] != frame && squares[i] == 0)
732    {
733      printf("Filled square %d has no piece pointer\n", i);
734      display_board(stdout, 0);
735      DIE;
736    }
737    if (pieces[squares[i]] != i && squares[i] != 0)
738    {
739      printf("Square->piece->square inconsistency\n");
740      display_board(stdout, 0);
741      DIE;
742    }
743  }
744}
745
746void reset_piece_square (void) {
747
748  /* we use piece number 0 to show a piece taken off the board, so don't
749     use that piece number for other things: */
750
751   /* reset the piece / square tables: */
752
753   int i, j, promoted_board[144];
754
755   memset(promoted_board, 0, sizeof(promoted_board));
756
757   /* save our promoted info as we cant determine it from the board */
758   for (i = 1, j = 1; j <= piece_count && i<62; i++) {
759     if(is_promoted[i]) {
760       promoted_board[pieces[i]] = 1;
761     }
762     if (pieces[i] != 0) j++;
763   }
764
765   Material = 0;
766
767   piece_count = 0;
768
769   memset(pieces, 0, sizeof(pieces));
770   memset(is_promoted, 0, sizeof(is_promoted));
771
772   pieces[0] = 0;
773
774   for (i = 26; i < 118; i++)
775     if (board[i] && (board[i] < npiece)) {
776
777       AddMaterial(board[i]);
778
779       piece_count += 1;
780
781       pieces[piece_count] = i;
782       squares[i] = piece_count;
783
784       /* restored promoted info */
785       if (promoted_board[i])
786	 is_promoted[piece_count] = 1;
787     }
788     else
789	squares[i] = 0;
790}
791
792
793void rinput (char str[], int n, FILE *stream) {
794
795  /* My input function - reads in up to n-1 characters from stream, or until
796     we encounter a \n or an EOF.  Appends a null character at the end of the
797     string, and stores the string in str[] */
798
799  int ch, i = 0;
800
801  while ((ch = getc (stream)) != (int) '\n' && ch != EOF) {
802	/* Skip stray interrupt characters at beginning of line */
803	if (!i && ch=='?')
804	  continue;
805    if (i < n-1) {
806      str[i++] = ch;
807    }
808  }
809
810  str [i] = '\0';
811
812}
813
814rtime_t rtime (void) {
815
816  /* using ftime(): */
817#if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H)
818  rtime_t temp;
819  ftime(&temp);
820  return (temp);
821
822  /* -------------------------------------------------- */
823
824  /* gettimeofday replacement by Daniel Clausen */
825#else
826#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIMEB_H)
827  rtime_t temp;
828  struct timeval tmp;
829
830  gettimeofday(&tmp, NULL);
831  temp.time = tmp.tv_sec;
832  temp.millitm = tmp.tv_usec / 1000;
833  temp.timezone = 0;
834  temp.dstflag = 0;
835
836  return (temp);
837
838#else
839  return (time (0));
840#endif
841#endif
842
843}
844
845
846void start_up (void) {
847
848  /* things to do on start up of the program */
849
850  printf("\nSjeng version " VERSION ", Copyright (C) 2000-2001 Gian-Carlo Pascutto\n\n"
851         "Sjeng comes with ABSOLUTELY NO WARRANTY; for details type 'warranty'\n"
852         "This is free software, and you are welcome to redistribute it\n"
853         "under certain conditions; type 'distribution'\n\n");
854}
855
856
857void toggle_bool (bool *var) {
858
859  /* toggle FALSE -> TRUE, TRUE -> FALSE */
860
861  if (*var) {
862    *var = FALSE;
863  }
864  else {
865    *var = TRUE;
866  }
867
868}
869
870
871void tree_debug (void) {
872
873  /* A function to make a tree of output at a certain depth and print out
874     the number of nodes: */
875
876  char input[STR_BUFF];
877  FILE *stream;
878  int depth;
879
880  init_game ();
881
882  /* get the desired depth to generate to: */
883  printf ("\nPlease enter the desired depth:\n");
884  rinput (input, STR_BUFF, stdin);
885  depth = atoi (input);
886
887  /* does the user want to output tree () ? */
888  printf ("\nDo you want tree () output?  (y/n)\n");
889  rinput (input, STR_BUFF, stdin);
890  if (input[0] == 'y') {
891    /* get our output file: */
892    printf ("\nPlease enter the name of the output file for tree ():\n");
893    rinput (input, STR_BUFF, stdin);
894    if ((stream = fopen (input, "w")) == NULL) {
895      fprintf (stderr, "Couldn't open file %s\n", input);
896    }
897
898    /* does the user want to output diagrams? */
899    printf ("\nDo you want to output diagrams? (y/n)\n");
900    rinput (input, STR_BUFF, stdin);
901
902    tree (depth, 0, stream, input);
903  }
904
905  /* print out the number of raw nodes for this depth: */
906  raw_nodes = 0;
907  perft (depth);
908  printf ("\n\n%s\nRaw nodes for depth %d: %d\n%s\n\n", divider,
909	  depth, raw_nodes, divider);
910
911}
912
913
914bool verify_coord (char input[], move_s *move) {
915
916  /* checks to see if the move the user entered was legal or not, returns
917     true if the move was legal, and stores the legal move inside move */
918
919  move_s moves[MOVE_BUFF];
920  int num_moves, i;
921  char comp_move[6];
922  bool legal = FALSE;
923  bool mate;
924
925  if (Variant == Losers)
926    {
927      captures = TRUE;
928      num_moves = 0;
929      gen (&moves[0]);
930      num_moves = numb_moves;
931      captures = FALSE;
932
933      mate = TRUE;
934
935      for (i = 0; i < num_moves; i++)
936	{
937	  make (&moves[0], i);
938
939	  /* check to see if our move is legal: */
940	  if (check_legal (&moves[0], i, TRUE))
941	    {
942	      mate = FALSE;
943	      unmake(&moves[0], i);
944	      break;
945	    };
946
947	  unmake(&moves[0], i);
948	}
949
950      if (mate == TRUE)
951	{
952	  /* no legal capture..do non-captures */
953	  captures = FALSE;
954	  num_moves = 0;
955	  gen (&moves[0]);
956	  num_moves = numb_moves;
957	}
958    }
959  else
960    {
961      gen (&moves[0]);
962      num_moves = numb_moves;
963    }
964
965  /* compare user input to the generated moves: */
966  for (i = 0; i < num_moves; i++) {
967    comp_to_coord (moves[i], comp_move);
968    if (!strcasecmp (input, comp_move)) {
969      make (&moves[0], i);
970      if (check_legal (&moves[0], i, TRUE)) {
971	legal = TRUE;
972	*move = moves[i];
973      }
974      unmake (&moves[0], i);
975    }
976  }
977
978  return (legal);
979
980}
981
982int interrupt(void)
983{
984  int c;
985
986#ifdef HAVE_SELECT
987  FD_ZERO(&read_fds);
988  FD_SET(0,&read_fds);
989  timeout.tv_sec = timeout.tv_usec = 0;
990  select(1,&read_fds,NULL,NULL,&timeout);
991  if(FD_ISSET(0,&read_fds))
992    {
993      c = getc(stdin);
994
995      if (c == '?')   /*Move now*/
996	{
997	  return 1;
998	}
999      else if (c == '.')     /* Stat request */
1000	{
1001	  getc(stdin);
1002	  post_stat_thinking();
1003	  return 0;
1004	}
1005
1006      ungetc(c, stdin);
1007
1008      if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1009
1010      return 1;
1011    }
1012  else return 0;
1013#else
1014#ifdef _WIN32
1015  static int init = 0, pipe;
1016  static HANDLE inh;
1017  DWORD dw;
1018  if(xb_mode) {     /* winboard interrupt code taken from crafty */
1019    if (!init) {
1020      init = 1;
1021      inh = GetStdHandle(STD_INPUT_HANDLE);
1022      pipe = !GetConsoleMode(inh, &dw);
1023      if (!pipe) {
1024	SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT|ENABLE_WINDOW_INPUT));
1025	FlushConsoleInputBuffer(inh);
1026      }
1027    }
1028    if(pipe) {
1029      if(!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL))
1030	{
1031	  c = getc(stdin);
1032
1033	  if (c == '?')   /*Move now*/
1034	    {
1035	      return 1;
1036	    }
1037	  else if (c == '.')     /* Stat request */
1038	    {
1039	      getc(stdin);
1040	      post_stat_thinking();
1041	      return 0;
1042	    }
1043
1044	  ungetc(c, stdin);
1045
1046	  if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1047
1048	  return 1;
1049	}
1050      if (dw)
1051	{
1052	  c = getc(stdin);
1053
1054	  if (c == '?')   /*Move now*/
1055	    {
1056	      return 1;
1057	    }
1058	  else if (c == '.')     /* Stat request */
1059	    {
1060	      getc(stdin);
1061	      post_stat_thinking();
1062	      return 0;
1063	    }
1064
1065	  ungetc(c, stdin);
1066
1067	  if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1068
1069	  return 1;
1070	}
1071      else return 0;
1072    } else {
1073      GetNumberOfConsoleInputEvents(inh, &dw);
1074      if (dw <= 1)
1075	{
1076	  return 0;
1077	}
1078      else
1079	{
1080	  c = getc(stdin);
1081
1082	  if (c == '?')   /*Move now*/
1083	    {
1084	      return 1;
1085	    }
1086	  else if (c == '.')     /* Stat request */
1087	    {
1088	      getc(stdin);
1089	      post_stat_thinking();
1090	      return 0;
1091	    }
1092
1093	  ungetc(c, stdin);
1094
1095	  if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0;
1096
1097	  return 1;
1098	};
1099    }
1100  }
1101#else
1102#endif
1103#endif
1104
1105  return 0;
1106}
1107
1108void PutPiece(int color, char piece, char pfile, int prank)
1109{
1110  int converterf = (int) 'a';
1111  int converterr = (int) '1';
1112  int norm_file, norm_rank, norm_square;
1113
1114  norm_file = pfile - converterf;
1115  norm_rank = prank - converterr;
1116
1117  norm_square = ((norm_rank * 12) + 26) + (norm_file);
1118
1119  if (color == WHITE)
1120    {
1121      switch (piece)
1122	{
1123	case 'p':
1124	  board[norm_square] = wpawn;
1125	  break;
1126	case 'n':
1127	  board[norm_square] = wknight;
1128	  break;
1129	case 'b':
1130	  board[norm_square] = wbishop;
1131	  break;
1132	case 'r':
1133	  board[norm_square] = wrook;
1134	  break;
1135	case 'q':
1136	  board[norm_square] = wqueen;
1137	  break;
1138	case 'k':
1139	  board[norm_square] = wking;
1140	  break;
1141	case 'x':
1142	  board[norm_square] = npiece;
1143	  break;
1144	}
1145    }
1146  else if (color == BLACK)
1147    {
1148      switch (piece)
1149	{
1150	case 'p':
1151	  board[norm_square] = bpawn;
1152	  break;
1153	case 'n':
1154	  board[norm_square] = bknight;
1155	  break;
1156	case 'b':
1157	  board[norm_square] = bbishop;
1158	  break;
1159	case 'r':
1160	  board[norm_square] = brook;
1161	  break;
1162	case 'q':
1163	  board[norm_square] = bqueen;
1164	  break;
1165	case 'k':
1166	  board[norm_square] = bking;
1167	  break;
1168	case 'x':
1169	  board[norm_square] = npiece;
1170	  break;
1171	}
1172    }
1173
1174  return;
1175}
1176
1177void reset_board (void) {
1178
1179  /* set up an empty  game: */
1180
1181  int i;
1182
1183  int init_board[144] = {
1184    0,0,0,0,0,0,0,0,0,0,0,0,
1185    0,0,0,0,0,0,0,0,0,0,0,0,
1186    0,0,13,13,13,13,13,13,13,13,0,0,
1187    0,0,13,13,13,13,13,13,13,13,0,0,
1188    0,0,13,13,13,13,13,13,13,13,0,0,
1189    0,0,13,13,13,13,13,13,13,13,0,0,
1190    0,0,13,13,13,13,13,13,13,13,0,0,
1191    0,0,13,13,13,13,13,13,13,13,0,0,
1192    0,0,13,13,13,13,13,13,13,13,0,0,
1193    0,0,13,13,13,13,13,13,13,13,0,0,
1194    0,0,0,0,0,0,0,0,0,0,0,0,
1195    0,0,0,0,0,0,0,0,0,0,0,0
1196  };
1197
1198  memcpy (board, init_board, sizeof (init_board));
1199  for (i = 0; i <= 143; i++)
1200    moved[i] = 0;
1201
1202  ep_square = 0;
1203
1204  piece_count = 0;
1205
1206  Material = 0;
1207
1208  memset(pieces, 0, sizeof(pieces));
1209  memset(is_promoted, 0, sizeof(is_promoted));
1210  memset(holding, 0, sizeof(holding));
1211
1212  white_hand_eval = 0;
1213  black_hand_eval = 0;
1214
1215  bookidx = 0;
1216  fifty = 0;
1217
1218  reset_piece_square ();
1219
1220}
1221
1222void speed_test(void)
1223{
1224  move_s moves[MOVE_BUFF];
1225  int i, j;
1226  clock_t cpu_start, cpu_end;
1227  float et;
1228  int ic;
1229
1230  /* LCT2 Pos 1 */
1231  setup_epd_line("r3kb1r/3n1pp1/p6p/2pPp2q/Pp2N3/3B2PP/1PQ2P2/R3K2R w KQkq");
1232
1233  cpu_start = clock ();
1234
1235  for (i = 0; i < 5000000; i++)
1236    {
1237      gen (&moves[0]);
1238    }
1239
1240  cpu_end = clock ();
1241  et = (cpu_end-cpu_start)/(float) CLOCKS_PER_SEC;
1242
1243  printf("Movegen speed: %d/s\n", (int)(5000000.0/et));
1244  j = 0;
1245
1246  cpu_start = clock ();
1247
1248  for (i = 0; i < 50000000; i++)
1249    {
1250      make (&moves[0], j);
1251      unmake (&moves[0], j);
1252
1253      if ((j+1) < numb_moves) j++;
1254      else j = 0;
1255    }
1256
1257  cpu_end = clock ();
1258  et = (cpu_end-cpu_start)/(float) CLOCKS_PER_SEC;
1259
1260  printf("Make+unmake speed: %d/s\n", (int)(50000000.0/et));
1261
1262  j = 0;
1263
1264  ic = in_check();
1265
1266  cpu_start = clock ();
1267
1268  for (i = 0; i < 50000000; i++)
1269    {
1270      make (&moves[0], j);
1271
1272      check_legal(&moves[0], j, ic);
1273
1274      unmake (&moves[0], j);
1275
1276      if ((j+1) < numb_moves) j++;
1277      else j = 0;
1278    }
1279
1280  cpu_end = clock ();
1281  et = (cpu_end-cpu_start)/(float) CLOCKS_PER_SEC;
1282
1283  printf("Movecycle speed: %d/s\n", (int)(50000000.0/et));
1284
1285  reset_ecache();
1286
1287  cpu_start = clock ();
1288
1289  for (i = 0; i < 10000000; i++)
1290    {
1291      eval();
1292      /* invalidate the ecache */
1293      hash = (++hash) % UINT_MAX;
1294    }
1295
1296  cpu_end = clock ();
1297  et = (cpu_end-cpu_start)/(float) CLOCKS_PER_SEC;
1298
1299  printf("Eval speed: %d/s\n", (int)(10000000.0/et));
1300
1301  /* restore the hash */
1302  initialize_hash();
1303
1304}
1305
1306/* Mersenne Twister */
1307
1308void seedMT(uint32_t seed)
1309{
1310  register uint32_t x = (seed | 1U) & 0xFFFFFFFFU, *s = state;
1311  register int    j;
1312
1313  for(left=0, *s++=x, j=N; --j;
1314      *s++ = (x*=69069U) & 0xFFFFFFFFU);
1315}
1316
1317uint32_t reloadMT(void)
1318{
1319  register uint32_t *p0=state, *p2=state+2, *pM=state+M, s0, s1;
1320  register int    j;
1321
1322  if(left < -1)
1323    seedMT(4357U);
1324
1325  left=N-1, next=state+1;
1326
1327  for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
1328    *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
1329
1330  for(pM=state, j=M; --j; s0=s1, s1=*p2++)
1331    *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
1332
1333  s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
1334  s1 ^= (s1 >> 11);
1335  s1 ^= (s1 <<  7) & 0x9D2C5680U;
1336  s1 ^= (s1 << 15) & 0xEFC60000U;
1337  return(s1 ^ (s1 >> 18));
1338}
1339
1340uint32_t randomMT(void)
1341{
1342  uint32_t y;
1343
1344  if(--left < 0)
1345    return(reloadMT());
1346
1347  y  = *next++;
1348  y ^= (y >> 11);
1349  y ^= (y <<  7) & 0x9D2C5680U;
1350  y ^= (y << 15) & 0xEFC60000U;
1351  return(y ^ (y >> 18));
1352}
1353