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