Merge branch 'maint'
[gnushogi.git] / gnushogi / main.c
1 /*
2  * FILE: main.c
3  *
4  * ----------------------------------------------------------------------
5  * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6  * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
7  * Copyright (c) 2008, 2013, 2014 Yann Dirson and the Free Software Foundation
8  *
9  * GNU SHOGI is based on GNU CHESS
10  *
11  * Copyright (c) 1988, 1989, 1990 John Stanback
12  * Copyright (c) 1992 Free Software Foundation
13  *
14  * This file is part of GNU SHOGI.
15  *
16  * GNU Shogi is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU General Public License as published by the
18  * Free Software Foundation; either version 3 of the License,
19  * or (at your option) any later version.
20  *
21  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
22  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with GNU Shogi; see the file COPYING. If not, see
28  * <http://www.gnu.org/licenses/>.
29  * ----------------------------------------------------------------------
30  *
31  */
32
33 #include "gnushogi.h"
34
35 #include <signal.h>
36
37
38 void print_arglist(int argc, char **argv)
39 {
40     int i;
41
42     for (i = 0; i < argc; i++)
43         printf("argv[%d] = %s\n", i, argv[i]);
44
45     printf("\n");
46 }
47
48
49 int
50 main (int argc, char **argv)
51 {
52     /*
53      * Process command-line arguments.
54      */
55
56     /* Get rid of the program name. */
57
58     argc--;
59     argv++;
60
61     /* CHECKME: get rid of the '+' syntax? */
62
63     while ((argc > 0) && ((argv[0][0] == '-') || (argv[0][0] == '+')))
64     {
65         switch (argv[0][1])
66         {
67         case 'a':
68             /* Need the "+" syntax here... */
69             ahead = ((argv[0][0] == '-') ? false : true);
70             break;
71
72
73         case 'b':
74             argc--;
75             argv++;
76
77             if (argc > 0)
78             {
79                 bookfile = argv[0];
80 #ifdef BINBOOK
81                 binbookfile = NULL;
82 #endif
83             }
84             break;
85
86 #ifdef BINBOOK
87         case 'B':
88             argc--;
89             argv++;
90             if (argc > 0)
91                 binbookfile = argv[0];
92             break;
93 #endif
94
95 #ifdef HAVE_LIBCURSES
96         case 'C':
97             /* Curses interface. */
98             display_type = DISPLAY_CURSES;
99             dsp = &curses_display;
100             break;
101 #endif
102
103         case 'h':
104             /* Need the "+" syntax here... */
105             hash = ((argv[0][0] == '-') ? false : true);
106             break;
107
108         case 'l':
109             argc--;
110             argv++;
111
112             if (argc > 0)
113                 Lang = argv[0];
114             break;
115
116         case 'L':
117             argc--;
118             argv++;
119
120             if (argc > 0)
121                 strcpy(listfile, argv[0]);
122             break;
123
124         case 's':
125             argc--;
126             argv++;
127
128             if (argc > 0)
129                 strcpy(savefile, argv[0]);
130             break;
131
132         case 'P':
133             argc--;
134             argv++;
135
136             if (argc > 0)
137                 bookmaxply = atoi(argv[0]);
138             break;
139
140         case 'R':
141             /* Raw text interface. */
142             display_type = DISPLAY_RAW;
143             dsp = &raw_display;
144             break;
145
146         case 'S':
147             argc--;
148             argv++;
149
150             if (argc > 0)
151                 booksize = atoi(argv[0]);
152             break;
153
154 #if ttblsz
155         case 'r':
156             argc--;
157             argv++;
158
159             if (argc > 0)
160                 rehash = atoi(argv[0]);
161             if (rehash > MAXrehash)
162                 rehash = MAXrehash;
163             break;
164
165         case 'T':
166             argc--;
167             argv++;
168
169             if (argc > 0)
170                 ttblsize = atoi(argv[0]);
171             if (ttblsize <= MINTTABLE)
172                 ttblsize = (MINTTABLE) + 1;
173             break;
174
175 #ifdef HASHFILE
176         case 'c':   /* Create or test persistent transposition table. */
177             argc--;
178             argv++;
179
180             if (argc > 0)
181                 filesz = atoi(argv[0]);
182             else
183                 filesz = vfilesz;
184
185             if ((filesz > 0) && (filesz < 24))
186                 filesz = (1 << filesz) - 1 + MAXrehash;
187             else
188                 filesz = filesz + MAXrehash;
189
190             if ((hashfile = fopen(HASHFILE, RWA_ACC)) == NULL)
191                 hashfile = fopen(HASHFILE, WA_ACC);
192
193             if (hashfile != NULL)
194             {
195                 long j;
196                 struct fileentry n;
197
198                 fputs("Filling transposition file, wait!\n", stdout);
199                 n.f = n.t = 0;
200                 n.flags = 0;
201                 n.depth = 0;
202                 n.sh = n.sl = 0;
203
204                 for (j = 0; j < filesz + 1; j++)
205                     fwrite(&n, sizeof(struct fileentry), 1, hashfile);
206
207                 fclose(hashfile);
208             }
209             else
210             {
211                 printf("Create failed for %s\n", HASHFILE);
212             }
213
214             return 0;
215
216         case 't':   /* Create or test persistent transposition table. */
217             hashfile = fopen(HASHFILE, RWA_ACC);
218
219             if (hashfile)
220             {
221                 fseek(hashfile, 0L, SEEK_END);
222                 filesz = (ftell(hashfile) / (sizeof(struct fileentry))) - 1;
223             }
224
225             if (hashfile != NULL)
226             {
227                 long i, j;
228                 int nr[MAXDEPTH];
229                 struct fileentry n;
230
231                 fputs("Counting transposition file entries, wait!\n", stdout);
232
233                 for (i = 0; i < MAXDEPTH; i++)
234                     nr[i] = 0;
235
236                 fseek(hashfile, 0L, SEEK_END);
237                 i = ftell(hashfile) / (sizeof(struct fileentry));
238                 fseek(hashfile, 0L, SEEK_SET);
239
240                 for (j = 0; j < i + 1; j++)
241                 {
242                     fread(&n, sizeof(struct fileentry), 1, hashfile);
243
244                     if (n.depth > MAXDEPTH)
245                     {
246                         printf("ERROR\n");
247                         exit(1);
248                     }
249
250                     if (n.depth)
251                     {
252                         nr[n.depth]++;
253                         nr[0]++;
254                     }
255                 }
256
257                 printf("The file contains %d entries out of max %ld\n", nr[0], i);
258
259                 for (j = 1; j < MAXDEPTH; j++)
260                     printf("%d ", nr[j]);
261
262                 printf("\n");
263             }
264
265             return 0;
266
267 #endif /* HASHFILE */
268 #endif /* ttblsz */
269
270         case 'v':
271             fprintf(stderr, "gnushogi version %s\n", PACKAGE_VERSION);
272             exit(1);
273
274
275         case 'X':
276             /* X interface. */
277             display_type = DISPLAY_X;
278             dsp = &raw_display;
279             break;
280
281         case 'x':
282             argc--;
283             argv++;
284
285             if (argc > 0)
286                 xwin = argv[0];
287             break;
288
289         default:
290             fputs("Usage: gnushogi [-a] [-t] [-c size] [-s savefile][-l listfile] [-x xwndw]\n", stderr);
291             exit(1);
292         }
293
294         argc--;
295         argv++;
296     }
297
298     if (argc == 2)
299     {
300         char *p;
301
302         MaxResponseTime = 100L * strtol(argv[1], &p, 10);
303
304         if (*p == ':')
305         {
306             MaxResponseTime = 60L * MaxResponseTime +
307                 100L * strtol(++p, (char **) NULL, 10);
308         }
309
310         TCflag    = false;
311         TCmoves   = 0;
312         TCminutes = 0;
313         TCseconds = 0;
314     }
315
316     if (argc >= 3)
317     {
318         char *p;
319
320         if (argc > 9)
321         {
322             printf("Time Control Error\n");
323             exit(1);
324         }
325
326         TCmoves   = atoi(argv[1]);
327         TCminutes = (short)strtol(argv[2], &p, 10);
328
329         if (*p == ':')
330             TCseconds = (short)strtol(p + 1, (char **) NULL, 10);
331         else
332             TCseconds = 0;
333
334         TCflag = true;
335         argc -= 3;
336         argv += 3;
337
338         while (argc > 1)
339         {
340             XCmoves[XC]   = atoi(argv[0]);
341             XCminutes[XC] = (short)strtol(argv[1], &p, 10);
342
343             if (*p == ':')
344                 XCseconds[XC] = (short)strtol(p + 1, (char **) NULL, 10);
345             else
346                 XCseconds[XC] = 0;
347
348             if (XCmoves[XC] && (XCminutes[XC] || XCseconds[XC]))
349                 XC++;
350             else
351             {
352                 printf("Time Control Error\n");
353                 exit(1);
354             }
355
356             argc -= 2;
357             argv += 2;
358         }
359
360         if (argc)
361         {
362             /*
363              * If we got here, there are unknown arguments, so issue
364              * an error message and quit.
365              */
366
367             printf("Invalid command-line arguments:\n");
368             print_arglist(argc, argv);
369             exit(1);
370         }
371     }
372
373     if (InitMain() != 0)
374         exit(1);
375
376     while (!flag.quit)
377     {
378         oppptr = (oppptr + 1) % MINGAMEIN;
379
380         if (flag.bothsides && !flag.mate)
381             SelectMove(opponent, FOREGROUND_MODE);
382         else
383             InputCommand(NULL);
384
385         if (opponent == white)
386         {
387             if (flag.gamein || TCadd)
388             {
389                 TimeCalc();
390             }
391             else if (TimeControl.moves[opponent] == 0)
392             {
393                 if (XC)
394                 {
395                     if (XCmore < XC)
396                     {
397                         TCmoves   = XCmoves[XCmore];
398                         TCminutes = XCminutes[XCmore];
399                         TCseconds = XCseconds[XCmore];
400                         XCmore++;
401                     }
402                 }
403
404                 SetTimeControl();
405             }
406         }
407
408         compptr = (compptr + 1) % MINGAMEIN;
409
410         if (!(flag.quit || flag.mate || flag.force))
411         {
412 #ifdef INTERRUPT_TEST
413             printf("starting search...\n");
414 #endif
415             SelectMove(computer, FOREGROUND_MODE);
416
417             if (computer == white)
418             {
419                 if (flag.gamein)
420                 {
421                     TimeCalc();
422                 }
423                 else if (TimeControl.moves[computer] == 0)
424                 {
425                     if (XC)
426                     {
427                         if (XCmore < XC)
428                         {
429                             TCmoves = XCmoves[XCmore];
430                             TCminutes = XCminutes[XCmore];
431                             TCseconds = XCseconds[XCmore];
432                             XCmore++;
433                         }
434                     }
435
436                     SetTimeControl();
437                 }
438             }
439         }
440     }
441
442     ExitMain();
443
444     return 0;
445 }
446
447