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