1 /* GNU Chess 6 - main.cc - entry point
2 
3    Copyright (c) 2001-2021 Free Software Foundation, Inc.
4 
5    GNU Chess is based on the two research programs
6    Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.
7 
8    This program is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 
21    Contact Info:
22      bug-gnu-chess@gnu.org
23      cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
24 */
25 
26 #include "components.h"
27 
28 #include <time.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <getopt.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <locale.h>
36 #include <signal.h>
37 
38 #include "frontend/common.h"
39 #include "gettext.h"
40 
41 #define _(str) gettext (str)
42 
43 unsigned char lzArray[65536];
44 BitBoard BitPosArray[64];
45 BitBoard NotBitPosArray[64];
46 BitBoard MoveArray[8][64];
47 BitBoard Ray[64][8];
48 BitBoard FromToRay[64][64];
49 BitBoard RankBit[8];
50 BitBoard FileBit[8];
51 BitBoard Ataks[2][7];
52 BitBoard Rook00Atak[64][256];
53 BitBoard Rook90Atak[64][256];
54 BitBoard Bishop45Atak[64][256];
55 BitBoard Bishop315Atak[64][256];
56 short directions[64][64];
57 unsigned char BitCount[65536];
58 leaf Tree[MAXTREEDEPTH];
59 leaf *TreePtr[MAXPLYDEPTH];
60 GameRec Game[MAXGAMEDEPTH];
61 int GameCnt;
62 int RealGameCnt;
63 short RealSide;
64 int computer;
65 unsigned int flags;
66 unsigned int preanalyze_flags;
67 int cboard[64];
68 int Mvboard[64];
69 Board board;
70 HashType hashcode[2][7][64];
71 HashType ephash[64];
72 HashType WKCastlehash;
73 HashType WQCastlehash;
74 HashType BKCastlehash;
75 HashType BQCastlehash;
76 HashType Sidehash;
77 HashType HashKey;
78 HashType PawnHashKey;
79 int Game50;
80 unsigned long GenCnt;
81 char SANmv[SANSZ];
82 char id[32];
83 char solution[64];
84 float SearchTime;
85 int MoveLimit[2];
86 float TimeLimit[2];
87 int TCMove;
88 int TCinc;
89 float TCTime;
90 int phase;
91 short bookfirstlast;
92 short graphicmodeoutput;
93 short coords;
94 short pgnloaded = 0;
95 int pgncnt = 0;
96 
97 char *progname;
98 FILE *ofp;
99 int myrating, opprating;
100 char name[50];
101 int computerplays;		/* Side computer is playing */
102 int n;		/* Last mobility returned by CTL */
103 int ExchCnt[2];	/* How many exchanges? */
104 
105 int slider[8] = { 0, 0, 0, 1, 1, 1, 0, 0 };
106 int Value[7] = { 0, ValueP, ValueN, ValueB, ValueR, ValueQ, ValueK};
107 int range[8] = { 0, 0, 0, 1, 1, 1, 0, 0 };
108 int ptype[2] = { pawn, bpawn };
109 char algbr[64][3] =
110 { "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
111   "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
112   "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
113   "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
114   "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
115   "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
116   "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
117   "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8"
118 };
119 char algbrfile[9] = "abcdefgh";
120 char algbrrank[9] = "12345678";
121 
122 char notation[8] = { " PNBRQK" };
123 char lnotation[8] = { " pnbrqk" };
124 
125 short Shift00[64] =
126 { 56, 56, 56, 56, 56, 56, 56, 56,
127   48, 48, 48, 48, 48, 48, 48, 48,
128   40, 40, 40, 40, 40, 40, 40, 40,
129   32, 32, 32, 32, 32, 32, 32, 32,
130   24, 24, 24, 24, 24, 24, 24, 24,
131   16, 16, 16, 16, 16, 16, 16, 16,
132    8,  8,  8,  8,  8,  8,  8,  8,
133    0,  0,  0,  0,  0,  0,  0,  0
134 };
135 
136 int r90[64] =
137 { A8, A7, A6, A5, A4, A3, A2, A1,
138   B8, B7, B6, B5, B4, B3, B2, B1,
139   C8, C7, C6, C5, C4, C3, C2, C1,
140   D8, D7, D6, D5, D4, D3, D2, D1,
141   E8, E7, E6, E5, E4, E3, E2, E1,
142   F8, F7, F6, F5, F4, F3, F2, F1,
143   G8, G7, G6, G5, G4, G3, G2, G1,
144   H8, H7, H6, H5, H4, H3, H2, H1 };
145 
146 short Shift90[64] =
147 { 0, 8, 16, 24, 32, 40, 48, 56,
148   0, 8, 16, 24, 32, 40, 48, 56,
149   0, 8, 16, 24, 32, 40, 48, 56,
150   0, 8, 16, 24, 32, 40, 48, 56,
151   0, 8, 16, 24, 32, 40, 48, 56,
152   0, 8, 16, 24, 32, 40, 48, 56,
153   0, 8, 16, 24, 32, 40, 48, 56,
154   0, 8, 16, 24, 32, 40, 48, 56
155 };
156 
157 int r45[64] =
158 { E4, F3, H2, C2, G1, D1, B1, A1,
159   E5, F4, G3, A3, D2, H1, E1, C1,
160   D6, F5, G4, H3, B3, E2, A2, F1,
161   B7, E6, G5, H4, A4, C3, F2, B2,
162   G7, C7, F6, H5, A5, B4, D3, G2,
163   C8, H7, D7, G6, A6, B5, C4, E3,
164   F8, D8, A8, E7, H6, B6, C5, D4,
165   H8, G8, E8, B8, F7, A7, C6, D5 };
166 
167 short Shift45[64] =
168 { 28, 36, 43, 49, 54, 58, 61, 63,
169   21, 28, 36, 43, 49, 54, 58, 61,
170   15, 21, 28, 36, 43, 49, 54, 58,
171   10, 15, 21, 28, 36, 43, 49, 54,
172    6, 10, 15, 21, 28, 36, 43, 49,
173    3,  6, 10, 15, 21, 28, 36, 43,
174    1,  3,  6, 10, 15, 21, 28, 36,
175    0,  1,  3,  6, 10, 15, 21, 28 };
176 
177 int Mask45[64] =
178 { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01,
179   0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03,
180   0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07,
181   0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
182   0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F,
183   0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F,
184   0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F,
185   0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
186 
187 int r315[64] =
188 { A1, C1, F1, B2, G2, E3, D4, D5,
189   B1, E1, A2, F2, D3, C4, C5, C6,
190   D1, H1, E2, C3, B4, B5, B6, A7,
191   G1, D2, B3, A4, A5, A6, H6, F7,
192   C2, A3, H3, H4, H5, G6, E7, B8,
193   H2, G3, G4, G5, F6, D7, A8, E8,
194   F3, F4, F5, E6, C7, H7, D8, G8,
195   E4, E5, D6, B7, G7, C8, F8, H8 };
196 
197 short Shift315[64] =
198 { 63, 61, 58, 54, 49, 43, 36, 28,
199   61, 58, 54, 49, 43, 36, 28, 21,
200   58, 54, 49, 43, 36, 28, 21, 15,
201   54, 49, 43, 36, 28, 21, 15, 10,
202   49, 43, 36, 28, 21, 15, 10,  6,
203   43, 36, 28, 21, 15, 10,  6,  3,
204   36, 28, 21, 15, 10,  6,  3,  1,
205   28, 21, 15, 10,  6,  3,  1,  0 };
206 
207 int Mask315[64] =
208 { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF,
209   0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F,
210   0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F,
211   0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F,
212   0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
213   0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07,
214   0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03,
215   0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 };
216 
217 extern char userinputbuf[];
218 
EndProg(int sig)219 void EndProg( int sig __attribute__ ((unused)) )
220 {
221     int r = system( "stty sane" );
222     exit(r);
223 }
224 
main(int argc,char * argv[])225 int main (int argc, char *argv[])
226 {
227   int i;
228 
229   /* Set locale via LC_ALL.  */
230   setlocale (LC_ALL, "");
231 
232 #if ENABLE_NLS
233   /* Set the text message domain.  */
234   bindtextdomain (PACKAGE, LOCALEDIR);
235   textdomain (PACKAGE);
236 #endif
237 
238   /*
239    * Parse command line arguments conforming with getopt_long syntax
240    * Note: we have to support "xboard" and "post" as bare strings
241    * for backward compatibility.
242    */
243 
244   int c;
245   int opt_help = 0, opt_version = 0, opt_post = 0, opt_xboard = 0, opt_memory = 0,
246       opt_easy = 0, opt_manual = 0, opt_quiet = 0, opt_uci = 0, opt_graphic = 0;
247   char opt_addbook[MAXSTR+1] = "";
248   char *endptr;
249 
250   /*disable graphic output by default */
251   graphicmodeoutput = 0;
252 
253 
254   progname = argv[0]; /* Save in global for cmd_usage */
255 
256   while (1)
257   {
258     static struct option long_options[] =
259     {
260         {"memory", 1, 0, 'M'},
261         {"version", 0, 0, 'v'},
262         {"quiet", 0, 0, 'q'},
263         {"silent", 0, 0, 'q'},
264         {"help", 0, 0, 'h'},
265         {"xboard", 0, 0, 'x'},
266         {"post", 0, 0, 'p'},
267         {"easy", 0, 0, 'e'},
268         {"manual", 0, 0, 'm'},
269         {"uci", 0, 0, 'u'},
270         {"addbook", 1, 0, 'a'},
271         {"graphic", 0, 0, 'g'},
272         {0, 0, 0, 0}
273     };
274 
275     /* getopt_long stores the option index here. */
276 
277     int option_index = 0;
278 
279     c = getopt_long (argc, argv, "qehmpvxgM:ua:",
280              long_options, &option_index);
281 
282     /* Detect the end of the options. */
283    if (c == -1)
284      break;
285 
286    /*
287     * Options with a straight flag, could use getoopt_long
288     * flag setting but this is more "obvious" and easier to
289     * modify.
290     */
291    switch (c)
292      {
293      case 'v':
294        opt_version = 1;
295        break;
296      case 'h':
297        opt_help = 1;
298        break;
299      case 'q':
300        opt_quiet = 1;
301        break;
302      case 'x':
303        opt_xboard = 1;
304        break;
305      case 'p':
306        opt_post = 1;
307        break;
308      case 'e':
309        opt_easy = 1;
310        break;
311      case 'g':
312          opt_graphic = 1;
313        break;
314      case 'm':
315        opt_manual = 1;
316        break;
317      case 'M':
318        if  ( optarg == NULL ){ /* we have error such as two -M */
319          opt_help = 1;
320          break;
321        }
322        errno = 0; /* zero error indicator */
323        opt_memory = strtol (optarg, &endptr, 10);
324        if ( errno != 0 || *endptr != '\0' ){
325          printf(_("Memory out of range or invalid.\n"));
326          return(1);
327        }
328        break;
329      case '?': /* On error give help - getopt does a basic message. */
330        opt_help = 1;
331        break;
332      case 'u':
333        opt_uci = 1;
334        break;
335      case 'a':
336        if  ( optarg == NULL ){ /* we have error such as two -a */
337          opt_help = 1;
338          break;
339        }
340        errno = 0; /* zero error indicator */
341        if ( strlen( optarg ) > MAXSTR ) {
342          printf( _("File name is too long (max = %d).\n"), MAXSTR );
343          return(1);
344        }
345        strcpy( opt_addbook, optarg );
346        break;
347      default:
348        puts (_("Option processing failed.\n"));
349        abort();
350      }
351   } /* end of getopt_long style parsing */
352 
353   /* Initialize random number generator */
354   srand((unsigned int) time(NULL));
355 
356   /* initialize control flags */
357   flags = ULL(0);
358 
359   /* output for thinking */
360   ofp = stdout;
361 
362   /* Handle old style command line options */
363   if (argc > 1) {
364     for (i = 0; i < argc; i++) {
365       if (strcmp(argv[i],"xboard") == 0) {
366 	SET (flags, XBOARD);
367       } else if (strcmp(argv[i],"post") == 0) {
368 	SET (flags, POST);
369       }
370     }
371   }
372   if (opt_xboard == 1)
373     SET (flags, XBOARD);
374   if (opt_uci == 1)
375     SET (flags, UCI);
376   if (opt_post == 1) {
377     SET (flags, POST);
378   }
379   if (opt_manual ==1)
380     SET (flags, MANUAL);
381   cmd_version();
382 
383   /* If the version option was specified we can exit here */
384   if (opt_version == 1)
385 	return(0);
386 
387   /* Startup output */
388   if ( !( flags & XBOARD ) && ( !opt_quiet ) && ( !opt_uci) ) {
389     printf ( _("\
390 Copyright (C) %s Free Software Foundation, Inc.\n\
391 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
392 This is free software: you are free to change and redistribute it.\n\
393 There is NO WARRANTY, to the extent permitted by law.\n"),
394              "2021" );
395   }
396 
397   /* If a usage statement is required output it here */
398   if (opt_help == 1){
399     cmd_usage();
400     return (1); /* Maybe an error if due to bad arguments. */
401   }
402 
403   dbg_open(NULL);
404 
405   if ( opt_memory != 0 )
406     ; /* TODO: to be removed - this is handled by the adapter */
407 
408   /* Catch SIGINT to exit. */
409   struct sigaction action;
410   memset( &action, 0, sizeof(struct sigaction) );
411   action.sa_handler = EndProg;
412   sigaction( SIGINT, &action, NULL );
413 
414   Initialize ();
415   if ( ! (flags & UCI ) ) {
416     /* Initialize the frontend */
417     InitFrontend();
418     /* Initialize the adapter, which in turn initializes the engine */
419     InitAdapter();
420   } else {
421     /* Initialize the engine only; no adapter */
422     InitEngine();
423   }
424 
425   /* Compile book if the addbook option was specified. Ignore any other options. */
426   if ( strlen( opt_addbook ) > 0 ) {
427     char data[9+MAXSTR+1+4]="";
428     sprintf( data, "book add %s\nquit", opt_addbook );
429     SendToEngine( data );
430     SET (flags, QUIT);
431   }
432 
433   if ( opt_easy == 0 )
434     SET (flags, HARD);
435   else {
436     char data[9];
437     strcpy( data, "easy" );
438     SendToEngine( data );
439   }
440 
441   if ( opt_memory > 0 ) {
442     char data[20];
443     sprintf( data, "memory %d", opt_memory );
444     SendToEngine( data );
445   }
446 
447   if (opt_post == 1) {
448     SET (flags, POST);
449     char data[9];
450     strcpy( data, "post" );
451     SendToEngine( data );
452   }
453 
454   if (opt_manual == 1) {
455     SET (flags, MANUAL);
456     char data[9];
457     strcpy( data, "force" );
458     SendToEngine( data );
459   }
460 
461   if (argc > 1) {
462     for (i = 0; i < argc; i++) {
463       if (strcmp(argv[i],"xboard") == 0) {
464 	SET (flags, XBOARD);
465       } else if (strcmp(argv[i],"post") == 0) {
466 	SET (flags, POST);
467       }
468     }
469 
470   if ( opt_graphic == 1) {
471     graphicmodeoutput = 1;
472   }
473 
474   }
475 
476   bookfirstlast = 3;
477 
478 
479   /* While not quit
480    *     If user input buffer not empty
481    *         Read next line from user input buffer
482    *         Process user input at front-end level
483    *         If user input must be passed to engine
484    *             Send user input to engine
485    *     If engine input buffer not empty
486    *         Read next line from engine input buffer
487    *         Process engine input at front-end level
488    *             Send user input to user (print on term)
489    *         If engine input must be passed to user
490    *     If user input is ready for reading (select)
491    *         Add user input to user input buffer
492    *     If engine input is ready for reading (select)
493    *         Add engine input to engine input buffer
494    */
495 
496   //usleep(3000); /* So that Polyglot's and Fruit's banner has enough time to be displayed */
497   //strcpy( userinputbuf, "protover 2\n" );
498   while (!(flags & QUIT)) {
499     if ( flags & UCI ) {
500       /* In UCI mode, just forward input/output to/from engine - no adapter */
501       ForwardUserInputToEngine();
502       ForwardEngineOutputToUser();
503     } else { /* Classical GNU Chess mode */
504       /* Check if there is a new command from the user */
505       NextUserCmd();
506       /* Show thinking message */
507       if ((flags & THINK) && !(flags & MANUAL) && !(flags & ENDED)) {
508         if (!(flags & XBOARD)) printf(_("Thinking...\n"));
509         CLEAR (flags, THINK);
510       }
511       /* Check if there is a new command from the engine */
512       NextEngineCmd();
513       /* Check if user input ready for reading. If so, store it in a buffer. */
514       ReadFromUser();
515       /* Check if engine input ready for reading. If so, store it in a buffer. */
516       ReadFromEngine();
517     }
518     /* Avoid using 100% CPU */
519     usleep(100);
520   }
521 
522   dbg_close();
523 
524   /* Termintate adapter and engine threads and join them */
525   TerminateAdapterEngine();
526   TerminateInput();
527 
528   return (0);
529 }
530