Add XBoard protocol drivers
[bonanza.git] / proce.c
1 #include <ctype.h>
2 #include <limits.h>
3 #include <math.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "shogi.h"
8
9 /* unacceptable when the program is thinking, or quit pondering */
10 #define AbortDifficultCommand                                              \
11           if ( game_status & flag_thinking )                               \
12             {                                                              \
13               str_error = str_busy_think;                                  \
14               return -2;                                                   \
15             }                                                              \
16           else if ( game_status & ( flag_pondering | flag_puzzling ) )     \
17             {                                                              \
18               game_status |= flag_quit_ponder;                             \
19               return 2;                                                    \
20             }
21
22 #if defined(MINIMUM)
23 #  define CmdBook(x,y) cmd_book(y);
24 static int CONV cmd_book( char **lasts );
25 #else
26 #  define CmdBook(x,y) cmd_book(x,y);
27 static int CONV cmd_learn( tree_t * restrict ptree, char **lasts );
28 static int CONV cmd_book( tree_t * restrict ptree, char **lasts );
29 #endif
30
31 #if ! defined(NO_STDOUT)
32 static int CONV cmd_stress( char **lasts );
33 #endif
34
35 #if defined(CSA_LAN)
36 static int CONV proce_csalan( tree_t * restrict ptree );
37 static int CONV cmd_connect( tree_t * restrict ptree, char **lasts );
38 static int CONV cmd_sendpv( char **lasts );
39 #endif
40
41 #if defined(MNJ_LAN)
42 static int CONV proce_mnj( tree_t * restrict ptree );
43 static int CONV cmd_mnjignore( tree_t *restrict ptree, char **lasts );
44 static int CONV cmd_mnj( char **lasts );
45 static int CONV cmd_mnjmove( tree_t * restrict ptree, char **lasts,
46                              int num_alter );
47 #endif
48
49 #if defined(USI)
50 static int CONV proce_usi( tree_t * restrict ptree );
51 static int CONV usi_posi( tree_t * restrict ptree, char **lasts );
52 static int CONV usi_go( tree_t * restrict ptree, char **lasts );
53 static int CONV usi_ignore( tree_t * restrict ptree, char **lasts );
54 #endif
55
56 #if defined(TLP)
57 static int CONV cmd_thread( char **lasts );
58 #endif
59
60 #if defined(MPV)
61 static int CONV cmd_mpv( char **lasts );
62 #endif
63
64 #if defined(DFPN)
65 static int CONV cmd_dfpn( tree_t * restrict ptree, char **lasts );
66 #endif
67
68 #if defined(DFPN_CLIENT)
69 static int CONV cmd_dfpn_client( tree_t * restrict ptree, char **lasts );
70 #endif
71
72 static int CONV proce_cui( tree_t * restrict ptree );
73 static int CONV cmd_usrmove( tree_t * restrict ptree, const char *str_move,
74                              char **last );
75 static int CONV cmd_outmove( tree_t * restrict ptree );
76 static int CONV cmd_move_now( void );
77 static int CONV cmd_ponder( char **lasts );
78 static int CONV cmd_limit( char **lasts );
79 static int CONV cmd_quit( void );
80 static int CONV cmd_beep( char **lasts );
81 static int CONV cmd_peek( char **lasts );
82 static int CONV cmd_stdout( char **lasts );
83 static int CONV cmd_newlog( char **lasts );
84 static int CONV cmd_hash( char **lasts );
85 static int CONV cmd_ping( void );
86 static int CONV cmd_suspend( void );
87 static int CONV cmd_problem( tree_t * restrict ptree, char **lasts );
88 static int CONV cmd_display( tree_t * restrict ptree, char **lasts );
89 static int CONV cmd_move( tree_t * restrict ptree, char **lasts );
90 static int CONV cmd_new( tree_t * restrict ptree, char **lasts );
91 static int CONV cmd_read( tree_t * restrict ptree, char **lasts );
92 static int CONV cmd_resign( tree_t * restrict ptree, char **lasts );
93 static int CONV cmd_time( char **lasts );
94
95
96 int CONV is_move( const char *str )
97 {
98   if ( isdigit( (int)str[0] ) && isdigit( (int)str[1] )
99        && isdigit( (int)str[2] ) && isdigit( (int)str[3] )
100        && isupper( (int)str[4] ) && isupper( (int)str[5] )
101        && str[6] == '\0' ) { return 1; }
102
103   return 0;
104 }
105
106
107 int CONV
108 procedure( tree_t * restrict ptree )
109 {
110 #if defined(CSA_LAN)
111   if ( sckt_csa != SCKT_NULL ) { return proce_csalan( ptree ); }
112 #endif
113
114 #if defined(MNJ_LAN)
115   if ( sckt_mnj != SCKT_NULL ) { return proce_mnj( ptree ); }
116 #endif
117
118 #if defined(USI)
119   if ( usi_mode != usi_off ) { return proce_usi( ptree ); }
120 #endif
121
122   return proce_cui( ptree );
123 }
124
125 #ifdef XBOARD
126 #define IF(X) else if(!strcmp(command, X))
127
128 int myTime, hisTime, movesPerSession, inc, plyNr;
129 char xboard_mode;
130
131 static void
132 SetTimes(void)
133 { // set white and black times from own and opponent time.
134   int moves;
135   if(movesPerSession <= 0) moves = 35; else {
136     moves = - plyNr/2;
137     while(moves <= 0) moves += movesPerSession;
138   }
139   time_limit = (myTime-inc-30)/(moves+2) + inc;
140   time_max_limit = 3*time_limit;
141   if(time_max_limit > myTime - 30)time_max_limit = myTime - 30; // keep 0.3 sec margin, as Bonanza reads the clock infrequently
142   time_limit *= 10; // msec
143   time_max_limit *= 10;
144 Out("# moves=%d, time=%d inc=%d t=%d, max=%d\n", moves, myTime, inc, time_limit, time_max_limit);
145 }
146
147 static int
148 proce_xboard(char *line, const char *command, tree_t * restrict ptree)
149 { // [HGM] added to make Bonanza.exe a native WinBoard engine
150   int value = -100000;
151   static char forceMode = 0;
152   sscanf(line + strlen(command) + 1, "%d", &value);
153 Out("# command = '%s'\n", line);
154   if(0) ;
155   IF("protover") { Out("feature variants=\"shogi\" usermove=1 myname=\"Bonanza " BNZ_VER
156                        "\" memory=1 smp=1 debug=1 colors=0 setboard=1 ping=1 done=1\n"); }
157   IF("new")      { forceMode = plyNr = 0; SetTimes(); return 0; }
158   IF("easy")     { strcpy(line, "ponder off"); return 0; }
159   IF("hard")     { strcpy(line, "ponder on");  return 0; }
160   IF("post")     { ; }
161   IF("nopost")   { ; }
162   IF("time")     { sscanf(line+5, "%d", &myTime); }
163   IF("otim")     { sscanf(line+5, "%d", &hisTime); }
164   IF("force")    { forceMode = 1; }
165   IF("go")       { forceMode = 0; SetTimes(); plyNr++; strcpy(line, "move"); return 0; }
166   IF("memory")   { ; }
167   IF("cores")    { sprintf(line, "tlp num %d", value); return 0; }
168   IF("sd")       { sprintf(line, "limit depth %d", value); return 0; }
169   IF("st")       { ; }
170   IF("quit")     { return 0; }
171   IF("analyze")  { ; }
172   IF("exit")     { ; }
173   IF("variant")  { /* ignore, since it must be Shogi */; }
174   IF("setboard") { ; }
175   IF("option")   { ; }
176   IF("level")    { int min, sec; float fsec=0.;
177                    if(sscanf(line+6, "%d %d:%d %f", &movesPerSession, &min, &sec, &fsec) != 4)
178                       sscanf(line+6, "%d %d %f", &movesPerSession, &min, &fsec);
179                    min = 60*min + sec; myTime = hisTime = 100*min; inc = 100 * fsec;
180                  }
181   IF("usermove") { char fromX=line[9], fromY=line[10], toX=line[11], toY=line[12], promo=line[13];
182                    int from;
183 {int i,j;for(i=0;i<81;i+=9){printf("# ");for(j=0;j<9;j++)printf(" %3d", BOARD[i+j]);printf("\n");}}
184                    if(forceMode) strcpy(line, "move "), line += 5; else plyNr++, SetTimes();
185                    if(fromY == '@') { // drop
186                        if(fromX >= 'a') fromX += 'A' - 'a';
187                        switch(fromX) { // encode piece
188                          case 'P': fromX = pawn;   break;
189                          case 'L': fromX = lance;  break;
190                          case 'N': fromX = knight; break;
191                          case 'S': fromX = silver; break;
192                          case 'G': fromX = gold;   break;
193                          case 'B': fromX = bishop; break;
194                          case 'R': fromX = rook;   break;
195                        }
196                        sprintf(line, "00%c%c%s", 'a'+'9'-toX, '1'+'9'-toY, astr_table_piece[(int)fromX]);
197                    } else {
198                        from = ('9' - fromY)*9 + (fromX - 'a');
199 Out("# from=%d\n",from);
200                        sprintf(line, "%c%c%c%c%s", 'a'+'9'-fromX, '1'+'9'-fromY, 'a'+'9'-toX, '1'+'9'-toY,
201                                  astr_table_piece[abs(BOARD[from]) + (promo == '+' ? promote : 0)]);
202                    }
203                    plyNr++; return 0;
204                  }
205   IF("undo")     { ; }
206   IF("remove")   { ; }
207   IF("ping")     { Out("pong %d\n", value); }
208   return 1;
209 }
210 #endif
211
212 static int CONV proce_cui( tree_t * restrict ptree )
213 {
214   const char *token;
215   char *last;
216
217   token = strtok_r( str_cmdline, str_delimiters, &last );
218
219   if ( token == NULL || *token == '#' ) { return 1; }
220 #ifdef XBOARD
221   { 
222     if(xboard_mode) {
223       if( proce_xboard(str_cmdline, token, ptree) )  return 1; // command already processed
224       Out("# translated command '%s'\n", str_cmdline);         // command translated for processing by Bonanza
225       token = strtok_r( str_cmdline, str_delimiters, &last );  // redo parsing
226     } else
227     if ( ! strcmp( token, "xboard" ) )  { xboard_mode = 1; game_status |= flag_noprompt; return 1; }
228   }
229 #endif
230   if ( is_move( token ) ) { return cmd_usrmove( ptree, token, &last ); }
231   if ( ! strcmp( token, "s" ) )         { return cmd_move_now(); }
232   if ( ! strcmp( token, "beep" ) )      { return cmd_beep( &last); }
233   if ( ! strcmp( token, "book" ) )      { return CmdBook( ptree, &last ); }
234   if ( ! strcmp( token, "display" ) )   { return cmd_display( ptree, &last ); }
235   if ( ! strcmp( token, "hash" ) )      { return cmd_hash( &last ); }
236   if ( ! strcmp( token, "limit" ) )     { return cmd_limit( &last ); }
237   if ( ! strcmp( token, "move" ) )      { return cmd_move( ptree, &last ); }
238   if ( ! strcmp( token, "new" ) )       { return cmd_new( ptree, &last ); }
239   if ( ! strcmp( token, "outmove" ) )   { return cmd_outmove( ptree ); }
240   if ( ! strcmp( token, "peek" ) )      { return cmd_peek( &last ); }
241   if ( ! strcmp( token, "stdout" ) )    { return cmd_stdout( &last ); }
242   if ( ! strcmp( token, "ping" ) )      { return cmd_ping(); }
243   if ( ! strcmp( token, "ponder" ) )    { return cmd_ponder( &last ); }
244   if ( ! strcmp( token, "problem" ) )   { return cmd_problem( ptree, &last ); }
245   if ( ! strcmp( token, "quit" ) )      { return cmd_quit(); }
246   if ( ! strcmp( token, "read" ) )      { return cmd_read( ptree, &last ); }
247   if ( ! strcmp( token, "resign" ) )    { return cmd_resign( ptree, &last ); }
248   if ( ! strcmp( token, "suspend" ) )   { return cmd_suspend(); }
249   if ( ! strcmp( token, "time" ) )      { return cmd_time( &last ); }
250   if ( ! strcmp( token, "newlog" ) )    { return cmd_newlog( &last ); }
251 #if defined(CSA_LAN)
252   if ( ! strcmp( token, "connect" ) )   { return cmd_connect( ptree, &last ); }
253   if ( ! strcmp( token, "sendpv" ) )    { return cmd_sendpv( &last ); }
254 #endif
255 #if defined(MNJ_LAN)
256   if ( ! strcmp( token, "mnj" ) )       { return cmd_mnj( &last ); }
257 #endif
258 #if defined(MPV)
259   if ( ! strcmp( token, "mpv" ) )       { return cmd_mpv( &last ); }
260 #endif
261 #if defined(DFPN)
262   if ( ! strcmp( token, "dfpn" ) )      { return cmd_dfpn( ptree, &last ); }
263 #endif
264 #if defined(DFPN_CLIENT)
265   if ( ! strcmp( token, "dfpn_client")) { return cmd_dfpn_client( ptree,
266                                                                   &last ); }
267 #endif
268 #if defined(TLP)
269   if ( ! strcmp( token, "tlp" ) )       { return cmd_thread( &last ); }
270 #endif
271 #if ! defined(NO_STDOUT)
272   if ( ! strcmp( token, "stress" ) )    { return cmd_stress( &last ); }
273 #endif
274 #if ! defined(MINIMUM)
275   if ( ! strcmp( token, "learn" ) )     { return cmd_learn( ptree, &last ); }
276 #endif
277
278   str_error = str_bad_cmdline;
279   return -2;
280 }
281
282
283 #if defined(CSA_LAN)
284 static int CONV proce_csalan( tree_t * restrict ptree )
285 {
286   const char *token;
287   char *last;
288
289   token = strtok_r( str_cmdline, str_delimiters, &last );
290     
291   if ( token == NULL ) { return 1; }
292   if ( *token == ach_turn[client_turn] && is_move( token+1 ) )
293     {
294       char *ptr;
295       long l;
296
297       token = strtok_r( NULL, str_delimiters, &last );
298       if ( token == NULL || *token != 'T' )
299         {
300           str_error = str_bad_cmdline;
301           return -1;
302         }
303       
304       l = strtol( token+1, &ptr, 0 );
305       if ( token+1 == ptr || l == LONG_MAX || l < 1 )
306         {
307           str_error = str_bad_cmdline;
308           return -1;
309         }
310
311       adjust_time( (unsigned int)l, client_turn );
312       Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
313       return 1;
314     }
315   if ( *token == ach_turn[Flip(client_turn)] && is_move( token+1 ) )
316     {
317       return cmd_usrmove( ptree, token+1, &last );
318     }
319   if ( ! strcmp( token, str_resign ) ) { return cmd_resign( ptree, &last ); }
320   if ( ! strcmp( token, "#WIN" )
321        || ! strcmp( token, "#LOSE" )
322        || ! strcmp( token, "#DRAW" )
323        || ! strcmp( token, "#CHUDAN" ) )
324     {
325       if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
326         {
327           game_status |= flag_suspend;
328           return 2;
329         }
330
331       if ( sckt_out( sckt_csa, "LOGOUT\n" ) < 0 ) { return -1; }
332       if ( sckt_recv_all( sckt_csa )        < 0 ) { return -1; }
333
334       ShutdownAll();
335       
336       if ( client_ngame == client_max_game ) { return cmd_quit(); }
337
338       return client_next_game( ptree, client_str_addr, (int)client_port );
339     }
340   
341   return 1;
342 }
343 #endif
344
345
346 #if defined(MNJ_LAN)
347 static int CONV proce_mnj( tree_t * restrict ptree )
348 {
349   const char *token;
350   char *last;
351   int iret;
352
353   token = strtok_r( str_cmdline, str_delimiters, &last );
354   if ( token == NULL ) { return 1; }
355
356   if ( ! strcmp( token, "new" ) )
357     {
358       iret = cmd_suspend();
359       if ( iret != 1 ) { return iret; }
360
361       mnj_posi_id = 0;
362       iret = cmd_new( ptree, &last );
363       if ( iret < 0 ) { return iret; }
364
365       moves_ignore[0] = MOVE_NA;
366       return analyze( ptree );
367     }
368   if ( ! strcmp( token, "ignore" ) ) { return cmd_mnjignore( ptree, &last ); }
369   if ( ! strcmp( token, "idle" ) )   { return cmd_suspend(); }
370   if ( ! strcmp( token, "alter" ) )  { return cmd_mnjmove( ptree, &last, 1 ); }
371   if ( ! strcmp( token, "retract" ) )
372     {
373       long l;
374       char *ptr;
375       const char *str = strtok_r( NULL, str_delimiters, &last );
376       if ( str == NULL )
377         {
378           str_error = str_bad_cmdline;
379           return -1;
380         }
381       l = strtol( str, &ptr, 0 );
382       if ( ptr == str || (long)NUM_UNMAKE < l )
383         {
384           str_error = str_bad_cmdline;
385           return -1;
386         }
387       
388       return cmd_mnjmove( ptree, &last, (int)l );
389     }
390   if ( ! strcmp( token, "move" ) )  { return cmd_mnjmove( ptree, &last, 0 ); }
391
392   str_error = str_bad_cmdline;
393   return -2;
394 }
395
396
397 static int CONV
398 cmd_mnjignore( tree_t *restrict ptree, char **lasts )
399 {
400   const char *token;
401   char *ptr;
402   int i;
403   unsigned int move;
404   long lid;
405
406
407   token = strtok_r( NULL, str_delimiters, lasts );
408   if ( token == NULL )
409     {
410       str_error = str_bad_cmdline;
411       return -1;
412     }
413   lid = strtol( token, &ptr, 0 );
414   if ( ptr == token || lid == LONG_MAX || lid < 1 )
415     {
416       str_error = str_bad_cmdline;
417       return -1;
418     }
419
420   AbortDifficultCommand;
421
422   for ( i = 0; ; i += 1 )
423     {
424       token = strtok_r( NULL, str_delimiters, lasts );
425       if ( token == NULL ) { break; }
426
427       if ( interpret_CSA_move( ptree, &move, token ) < 0 ) { return -1; }
428
429       moves_ignore[i] = move;
430     }
431   if ( i == 0 )
432     {
433       str_error = str_bad_cmdline;
434       return -1;
435     }
436   mnj_posi_id     = (int)lid;
437   moves_ignore[i] = MOVE_NA;
438
439   return analyze( ptree );
440 }
441
442
443 static int CONV
444 cmd_mnjmove( tree_t * restrict ptree, char **lasts, int num_alter )
445 {
446   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
447   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
448   char *ptr;
449   long lid;
450   unsigned int move;
451   int iret;
452
453   if ( sckt_mnj == SCKT_NULL ||  str1 == NULL || str2 == NULL )
454     {
455       str_error = str_bad_cmdline;
456       return -1;
457     }
458
459   lid = strtol( str2, &ptr, 0 );
460   if ( ptr == str2 || lid == LONG_MAX || lid < 1 )
461     {
462       str_error = str_bad_cmdline;
463       return -1;
464     }
465
466   AbortDifficultCommand;
467  
468   while ( num_alter )
469     {
470       iret = unmake_move_root( ptree );
471       if ( iret < 0 ) { return iret; }
472
473       num_alter -= 1;
474     }
475
476   iret = interpret_CSA_move( ptree, &move, str1 );
477   if ( iret < 0 ) { return iret; }
478     
479   iret = get_elapsed( &time_turn_start );
480   if ( iret < 0 ) { return iret; }
481
482   mnj_posi_id = (int)lid;
483
484   iret = make_move_root( ptree, move, ( flag_time | flag_rep
485                                         | flag_detect_hang ) );
486   if ( iret < 0 ) { return iret; }
487   
488 #  if ! defined(NO_STDOUT)
489   iret = out_board( ptree, stdout, 0, 0 );
490   if ( iret < 0 ) { return iret; }
491 #  endif
492
493   moves_ignore[0] = MOVE_NA;
494   return analyze( ptree );
495 }
496 #endif
497
498
499 #if defined(USI)
500 static int CONV proce_usi( tree_t * restrict ptree )
501 {
502   const char *token;
503   char *lasts;
504   int iret;
505
506   token = strtok_r( str_cmdline, str_delimiters, &lasts );
507   if ( token == NULL ) { return 1; }
508
509   if ( ! strcmp( token, "usi" ) )
510     {
511       USIOut( "id name %s\n", str_myname );
512       USIOut( "id author Kunihito Hoki\n" );
513       USIOut( "usiok\n" );
514       return 1;
515     }
516
517   if ( ! strcmp( token, "isready" ) )
518     {
519       USIOut( "readyok\n", str_myname );
520       return 1;
521     }
522
523   if ( ! strcmp( token, "echo" ) )
524     {
525       USIOut( "%s\n", lasts );
526       return 1;
527     }
528
529   if ( ! strcmp( token, "ignore_moves" ) )
530     {
531       return usi_ignore( ptree, &lasts );
532     }
533
534   if ( ! strcmp( token, "genmove_probability" ) )
535     {
536       if ( get_elapsed( &time_start ) < 0 ) { return -1; }
537       return usi_root_list( ptree );
538     }
539
540   if ( ! strcmp( token, "go" ) )
541     {
542       iret = usi_go( ptree, &lasts );
543       moves_ignore[0] = MOVE_NA;
544       return iret;
545     }
546
547   if ( ! strcmp( token, "stop" ) )     { return cmd_move_now(); }
548   if ( ! strcmp( token, "position" ) ) { return usi_posi( ptree, &lasts ); }
549   if ( ! strcmp( token, "quit" ) )     { return cmd_quit(); }
550   
551   str_error = str_bad_cmdline;
552   return -1;
553 }
554
555
556 static int CONV
557 usi_ignore( tree_t * restrict ptree, char **lasts )
558 {
559   const char *token;
560   char str_buf[7];
561   int i;
562   unsigned int move;
563
564   AbortDifficultCommand;
565
566   for ( i = 0; ; i += 1 )
567     {
568       token = strtok_r( NULL, str_delimiters, lasts );
569       if ( token == NULL ) { break; }
570       
571       if ( usi2csa( ptree, token, str_buf ) < 0 )            { return -1; }
572       if ( interpret_CSA_move( ptree, &move, str_buf ) < 0 ) { return -1; }
573
574       moves_ignore[i] = move;
575     }
576
577   moves_ignore[i] = MOVE_NA;
578
579   return 1;
580 }
581
582
583 static int CONV
584 usi_go( tree_t * restrict ptree, char **lasts )
585 {
586   const char *token;
587   char *ptr;
588   int iret;
589   long l;
590
591   AbortDifficultCommand;
592
593   if ( game_status & mask_game_end )
594     {
595       str_error = str_game_ended;
596       return -1;
597     }
598   
599   token = strtok_r( NULL, str_delimiters, lasts );
600
601   if ( ! strcmp( token, "book" ) )
602     {
603       AbortDifficultCommand;
604       if ( usi_book( ptree ) < 0 ) { return -1; }
605
606       return 1;
607     }
608
609
610   if ( ! strcmp( token, "infinite" ) )
611     {
612       usi_byoyomi     = UINT_MAX;
613       depth_limit     = PLY_MAX;
614       node_limit      = UINT64_MAX;
615       sec_limit_depth = UINT_MAX;
616     }
617   else if ( ! strcmp( token, "byoyomi" ) )
618     {
619       token = strtok_r( NULL, str_delimiters, lasts );
620       if ( token == NULL )
621         {
622           str_error = str_bad_cmdline;
623           return -1;
624         }
625
626       l = strtol( token, &ptr, 0 );
627       if ( ptr == token || l > UINT_MAX || l < 1 )
628         {
629           str_error = str_bad_cmdline;
630           return -1;
631         }
632       
633       usi_byoyomi     = (unsigned int)l;
634       depth_limit     = PLY_MAX;
635       node_limit      = UINT64_MAX;
636       sec_limit_depth = UINT_MAX;
637     }
638   else {
639     str_error = str_bad_cmdline;
640     return -1;
641   }
642
643       
644   if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
645
646   iret = com_turn_start( ptree, 0 );
647   if ( iret < 0 ) {
648     if ( str_error == str_no_legal_move ) { USIOut( "bestmove resign\n" ); }
649     else                                  { return -1; }
650   }
651   
652   return 1;
653 }
654
655
656 static int CONV
657 usi_posi( tree_t * restrict ptree, char **lasts )
658 {
659   const char *token;
660   char str_buf[7];
661   unsigned int move;
662     
663   AbortDifficultCommand;
664     
665   moves_ignore[0] = MOVE_NA;
666
667   token = strtok_r( NULL, str_delimiters, lasts );
668   if ( strcmp( token, "startpos" ) )
669     {
670       str_error = str_bad_cmdline;
671       return -1;
672     }
673     
674   if ( ini_game( ptree, &min_posi_no_handicap,
675                  flag_history, NULL, NULL ) < 0 ) { return -1; }
676     
677   token = strtok_r( NULL, str_delimiters, lasts );
678   if ( token == NULL ) { return 1; }
679
680   if ( strcmp( token, "moves" ) )
681     {
682       str_error = str_bad_cmdline;
683       return -1;
684     }
685     
686   for ( ;; )  {
687
688     token = strtok_r( NULL, str_delimiters, lasts );
689     if ( token == NULL ) { break; }
690       
691     if ( usi2csa( ptree, token, str_buf ) < 0 )            { return -1; }
692     if ( interpret_CSA_move( ptree, &move, str_buf ) < 0 ) { return -1; }
693     if ( make_move_root( ptree, move, ( flag_history | flag_time
694                                         | flag_rep
695                                         | flag_detect_hang ) ) < 0 )
696       {
697         return -1;
698       }
699   }
700     
701   if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
702   return 1;
703 }
704
705 #endif
706
707
708 static int CONV cmd_move_now( void )
709 {
710   if ( game_status & flag_thinking ) { game_status |= flag_move_now; }
711
712   return 1;
713 }
714
715
716 static int CONV
717 cmd_usrmove( tree_t * restrict ptree, const char *str_move, char **lasts )
718 {
719   const char *str;
720   char *ptr;
721   long lelapsed;
722   unsigned int move;
723   int iret;
724
725   if ( game_status & mask_game_end )
726     {
727       str_error = str_game_ended;
728       return -2;
729     }
730   
731   if ( game_status & flag_thinking )
732     {
733       str_error = str_busy_think;
734       return -2;
735     }
736
737   str = strtok_r( NULL, str_delimiters, lasts );
738   if ( str == NULL ) { lelapsed = 0; }
739   else {
740     if ( *str != 'T' )
741       {
742         str_error = str_bad_cmdline;
743         return -2;
744       }
745     str += 1;
746     lelapsed = strtol( str, &ptr, 0 );
747     if ( ptr == str || lelapsed == LONG_MAX || lelapsed < 1 )
748       {
749         str_error = str_bad_cmdline;
750         return -2;
751       }
752   }
753
754   if ( game_status & ( flag_pondering | flag_puzzling ) )
755     {
756       int i;
757
758       for ( i = 0; i < ponder_nmove; i++ )
759         {
760           if ( ! strcmp( str_move, str_CSA_move(ponder_move_list[i]) ) )
761             {
762               break;
763             }
764         }
765       if ( i == ponder_nmove )
766         {
767 #if defined(CSA_LAN)
768           if ( sckt_csa != SCKT_NULL ) { AbortDifficultCommand; }
769 #endif
770
771 #if defined(CSASHOGI)
772           AbortDifficultCommand;
773 #else
774           str_error = str_illegal_move;
775           return -2;
776 #endif
777         }
778
779       if ( ( game_status & flag_puzzling )
780            || strcmp( str_move, str_CSA_move(ponder_move) ) )
781         {
782           ponder_move  = MOVE_PONDER_FAILED;
783           game_status |= flag_quit_ponder;
784           return 2;
785         }
786       else {
787         iret = update_time( Flip(root_turn) );
788         if ( iret < 0 ) { return iret; }
789         if ( lelapsed )
790           {
791             adjust_time( (unsigned int)lelapsed, Flip(root_turn) );
792           }
793
794         out_CSA( ptree, &record_game, ponder_move );
795
796         game_status      &= ~flag_pondering;
797         game_status      |= flag_thinking;
798 #ifdef XBOARD
799       if(!xboard_mode)
800 #endif
801         set_search_limit_time( root_turn );
802
803         OutCsaShogi( "info ponder end\n" );
804
805         str = str_time_symple( time_turn_start - time_start );
806         Out( "    %6s          MOVE PREDICTION HIT\n"
807              "  elapsed: b%u, w%u\n", str, sec_b_total, sec_w_total );
808         return 1;
809       }
810     }
811
812   iret = interpret_CSA_move( ptree, &move, str_move );
813   if ( iret < 0 ) { return iret; }
814   move_evasion_pchk = 0;
815   iret = make_move_root( ptree, move, ( flag_rep | flag_history | flag_time
816                                         | flag_detect_hang ) );
817   if ( iret < 0 )
818       {
819
820 #if defined(CSA_LAN)
821         if ( sckt_csa != SCKT_NULL )
822           {
823             if ( move_evasion_pchk )
824               {
825                 str  = str_CSA_move( move_evasion_pchk );
826                 iret = sckt_out( sckt_csa, "%c%s\n",
827                                  ach_turn[Flip(root_turn)], str );
828                 if ( iret < 0 ) { return iret; }
829               }
830             return cmd_suspend();
831           }
832 #endif
833
834         if ( move_evasion_pchk )
835           {
836             str = str_CSA_move( move_evasion_pchk );
837 #if defined(CSASHOGI)
838             OutCsaShogi( "move%s\n", str );
839             return cmd_suspend();
840 #else
841             snprintf( str_message, SIZE_MESSAGE, "perpetual check (%c%s)",
842                       ach_turn[Flip(root_turn)], str );
843             str_error = str_message;
844             return -2;
845 #endif
846           }
847
848         return iret;
849       }
850
851   if ( lelapsed ) { adjust_time( (unsigned int)lelapsed, Flip(root_turn) ); }
852   Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
853
854 #if defined(CSA_LAN)
855   if ( sckt_csa != SCKT_NULL && ( game_status & flag_mated ) )
856     {
857       iret = sckt_out( sckt_csa, "%%TORYO\n" );
858       if ( iret < 0 ) { return iret; }
859     }
860 #endif
861
862   if ( ! ( game_status & mask_game_end ) )
863     {
864       iret = com_turn_start( ptree, 0 );
865       if ( iret < 0 ) { return iret; }
866     }
867
868   return 1;
869 }
870
871
872 static int CONV cmd_beep( char **lasts )
873 {
874   const char *str = strtok_r( NULL, str_delimiters, lasts );
875   if ( str == NULL )
876     {
877       str_error = str_bad_cmdline;
878       return -2;
879     }
880
881   if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nobeep; }
882   else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nobeep; }
883   else {
884     str_error = str_bad_cmdline;
885     return -2;
886   }
887
888   return 1;
889 }
890
891
892 static int CONV cmd_peek( char **lasts )
893 {
894   const char *str = strtok_r( NULL, str_delimiters, lasts );
895
896   if ( str == NULL )
897     {
898       str_error = str_bad_cmdline;
899       return -2;
900     }
901
902   if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nopeek; }
903   else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nopeek; }
904   else {
905     str_error = str_bad_cmdline;
906     return -2;
907   }
908
909   return 1;
910 }
911
912
913 static int CONV cmd_stdout( char **lasts )
914 {
915   const char *str = strtok_r( NULL, str_delimiters, lasts );
916
917   if ( str == NULL )
918     {
919       str_error = str_bad_cmdline;
920       return -2;
921     }
922
923   if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nostdout; }
924   else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nostdout; }
925   else {
926     str_error = str_bad_cmdline;
927     return -2;
928   }
929
930   return 1;
931 }
932
933
934 static int CONV cmd_newlog( char **lasts )
935 {
936   const char *str = strtok_r( NULL, str_delimiters, lasts );
937
938   if ( str == NULL )
939     {
940       str_error = str_bad_cmdline;
941       return -2;
942     }
943
944   if      ( ! strcmp( str, str_on )  ) { game_status &= ~flag_nonewlog; }
945   else if ( ! strcmp( str, str_off ) ) { game_status |=  flag_nonewlog; }
946   else {
947     str_error = str_bad_cmdline;
948     return -2;
949   }
950
951   return 1;
952 }
953
954
955 static int CONV cmd_ponder( char **lasts )
956 {
957   const char *str = strtok_r( NULL, str_delimiters, lasts );
958
959   if ( str == NULL )
960     {
961       str_error = str_bad_cmdline;
962       return -2;
963     }
964
965   if      ( ! strcmp( str, str_on )  ) { game_status &= ~flag_noponder; }
966   else if ( ! strcmp( str, str_off ) )
967     {
968       if ( game_status & ( flag_pondering | flag_puzzling ) )
969         {
970           game_status |= flag_quit_ponder;
971         }
972       game_status |= flag_noponder;
973     }
974   else {
975     str_error = str_bad_cmdline;
976     return -2;
977   }
978
979   return 1;
980 }
981
982
983 #if ! defined(NO_STDOUT)
984 static int CONV cmd_stress( char **lasts )
985 {
986   const char *str = strtok_r( NULL, str_delimiters, lasts );
987
988   if ( str == NULL )
989     {
990       str_error = str_bad_cmdline;
991       return -2;
992     }
993
994   if      ( ! strcmp( str, str_on  ) ) { game_status &= ~flag_nostress; }
995   else if ( ! strcmp( str, str_off ) ) { game_status |= flag_nostress; }
996   else {
997     str_error = str_bad_cmdline;
998     return -2;
999   }
1000
1001   return 1;
1002 }
1003 #endif
1004
1005
1006 static int CONV
1007 #if defined(MINIMUM)
1008 cmd_book( char **lasts )
1009 #else
1010 cmd_book( tree_t * restrict ptree, char **lasts )
1011 #endif
1012 {
1013   const char *str = strtok_r( NULL, str_delimiters, lasts );
1014   int iret = 1;
1015
1016   if ( str == NULL )
1017     {
1018       str_error = str_bad_cmdline;
1019       return -2;
1020     }
1021   if      ( ! strcmp( str, str_on ) )   { iret = book_on(); }
1022   else if ( ! strcmp( str, str_off ) )  { iret = book_off(); }
1023   else if ( ! strcmp( str, "narrow" ) ) { game_status |= flag_narrow_book; }
1024   else if ( ! strcmp( str, "wide" ) )   { game_status &= ~flag_narrow_book; }
1025 #if ! defined(MINIMUM)
1026   else if ( ! strcmp( str, "create" ) )
1027     {
1028       AbortDifficultCommand;
1029
1030       iret = book_create( ptree );
1031       if ( iret < 0 ) { return iret; }
1032
1033       iret = ini_game( ptree, &min_posi_no_handicap, flag_history,
1034                        NULL, NULL );
1035       if ( iret < 0 ) { return iret; }
1036
1037       iret = get_elapsed( &time_turn_start );
1038     }
1039 #endif
1040   else {
1041     str_error = str_bad_cmdline;
1042     iret = -2;
1043   }
1044
1045   return iret;
1046 }
1047
1048
1049 static int CONV cmd_display( tree_t * restrict ptree, char **lasts )
1050 {
1051   const char *str = strtok_r( NULL, str_delimiters, lasts );
1052   char *ptr;
1053   long l;
1054   int iret;
1055
1056   if ( str != NULL )
1057     {
1058       l = strtol( str, &ptr, 0 );
1059       if ( ptr == str )
1060         {
1061           str_error = str_bad_cmdline;
1062           return -2;
1063         }
1064       if      ( l == 1 ) { game_status &= ~flag_reverse; }
1065       else if ( l == 2 ) { game_status |= flag_reverse; }
1066       else {
1067         str_error = str_bad_cmdline;
1068         return -2;
1069       }
1070     }
1071   
1072   Out( "\n" );
1073   iret = out_board( ptree, stdout, 0, 0 );
1074   if ( iret < 0 ) { return iret; }
1075 #if ! defined(NO_LOGGING)
1076   iret = out_board( ptree, pf_log, 0, 0 );
1077   if ( iret < 0 ) { return iret; }
1078 #endif
1079   Out( "\n" );
1080
1081   return 1;
1082 }
1083
1084
1085 static int CONV cmd_ping( void )
1086 {
1087   OutCsaShogi( "pong\n" );
1088   Out( "pong\n" );
1089   return 1;
1090 }
1091
1092
1093 static int CONV cmd_hash( char **lasts )
1094 {
1095   const char *str = strtok_r( NULL, str_delimiters, lasts );
1096   char *ptr;
1097   long l;
1098
1099   if ( str == NULL )
1100     {
1101       str_error = str_bad_cmdline;
1102       return -2;
1103     }
1104
1105   l = strtol( str, &ptr, 0 );
1106   if ( ptr == str || l == LONG_MAX || l < 1 || l > 31 )
1107     {
1108       str_error = str_bad_cmdline;
1109       return -2;
1110     }
1111   
1112   AbortDifficultCommand;
1113   
1114   log2_ntrans_table = (int)l;
1115   memory_free( (void *)ptrans_table_orig );
1116   return ini_trans_table();
1117 }
1118
1119
1120 static int CONV cmd_limit( char **lasts )
1121 {
1122   const char *str = strtok_r( NULL, str_delimiters, lasts );
1123   char *ptr;
1124   long l1, l2, l3;
1125
1126   if ( str == NULL )
1127     {
1128       str_error = str_bad_cmdline;
1129       return -2;
1130     }
1131
1132   AbortDifficultCommand;
1133
1134   if ( ! strcmp( str, "depth" ) )
1135     {
1136       str = strtok_r( NULL, str_delimiters, lasts );
1137       if ( str == NULL )
1138         {
1139           str_error = str_bad_cmdline;
1140           return -2;
1141         }
1142       l1 = strtol( str, &ptr, 0 );
1143       if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
1144         {
1145           str_error = str_bad_cmdline;
1146           return -2;
1147         }
1148       sec_limit_up = UINT_MAX;
1149       node_limit   = UINT64_MAX;
1150       depth_limit  = (int)l1;
1151     }
1152   else if ( ! strcmp( str, "nodes" ) )
1153     {
1154       str = strtok_r( NULL, str_delimiters, lasts );
1155       if ( str == NULL )
1156         {
1157           str_error = str_bad_cmdline;
1158           return -2;
1159         }
1160       l1 = strtol( str, &ptr, 0 );
1161       if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
1162         {
1163           str_error = str_bad_cmdline;
1164           return -2;
1165         }
1166       sec_limit_up = UINT_MAX;
1167       depth_limit  = PLY_MAX;
1168       node_limit   = (uint64_t)l1;
1169     }
1170   else if ( ! strcmp( str, "time" ) )
1171     {
1172       str = strtok_r( NULL, str_delimiters, lasts );
1173       if ( str == NULL )
1174         {
1175           str_error = str_bad_cmdline;
1176           return -2;
1177         }
1178
1179       if ( ! strcmp( str, "extendable" ) )
1180         {
1181           game_status |= flag_time_extendable;
1182         }
1183       else if ( ! strcmp( str, "strict" ) )
1184         {
1185           game_status &= ~flag_time_extendable;
1186         }
1187       else {
1188         l1 = strtol( str, &ptr, 0 );
1189         if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
1190           {
1191             str_error = str_bad_cmdline;
1192             return -2;
1193           }
1194
1195         str = strtok_r( NULL, str_delimiters, lasts );
1196         if ( str == NULL )
1197           {
1198             str_error = str_bad_cmdline;
1199             return -2;
1200           }
1201         l2 = strtol( str, &ptr, 0 );
1202         if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
1203           {
1204             str_error = str_bad_cmdline;
1205             return -2;
1206           }
1207
1208         str = strtok_r( NULL, str_delimiters, lasts );
1209         if ( ! str ) { l3 = -1; }
1210         else {
1211           l3 = strtol( str, &ptr, 0 );
1212           if ( ptr == str || l3 >= PLY_MAX || l3 < -1 )
1213             {
1214               str_error = str_bad_cmdline;
1215               return -2;
1216             }
1217         }
1218
1219         if ( ! ( l1 | l2 ) ) { l2 = 1; }
1220
1221         depth_limit  = PLY_MAX;
1222         node_limit   = UINT64_MAX;
1223         sec_limit    = (unsigned int)l1 * 60U;
1224         sec_limit_up = (unsigned int)l2;
1225         if ( l3 == -1 ) { sec_limit_depth = UINT_MAX; }
1226         else            { sec_limit_depth = (unsigned int)l3; }
1227       }
1228     }
1229   else {
1230     str_error = str_bad_cmdline;
1231     return -2;
1232   }
1233
1234   return 1;
1235 }
1236
1237
1238 static int CONV
1239 cmd_read( tree_t * restrict ptree, char **lasts )
1240 {
1241   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
1242   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
1243   const char *str3 = strtok_r( NULL, str_delimiters, lasts );
1244   const char *str_tmp;
1245   FILE *pf_src, *pf_dest;
1246   char str_file[SIZE_FILENAME];
1247   char *ptr;
1248   unsigned int moves;
1249   long l;
1250   int iret, flag, c;
1251
1252   flag    = flag_history | flag_rep | flag_detect_hang;
1253   moves   = UINT_MAX;
1254   str_tmp = NULL;
1255
1256   if ( str1 == NULL )
1257     {
1258       str_error = str_bad_cmdline;
1259       return -2;
1260     }
1261
1262   if ( str2 != NULL )
1263     {
1264       if ( ! strcmp( str2, "t" ) ) { flag |= flag_time; }
1265       else if ( strcmp( str2, "nil" ) )
1266         {
1267           str_error = str_bad_cmdline;
1268           return -2;
1269         }
1270     }
1271
1272   if ( str3 != NULL )
1273     {
1274       l = strtol( str3, &ptr, 0 );
1275       if ( ptr == str3 || l == LONG_MAX || l < 1 )
1276         {
1277           str_error = str_bad_cmdline;
1278           return -2;
1279         }
1280       moves = (unsigned int)l - 1U;
1281     }
1282
1283   AbortDifficultCommand;
1284
1285   if ( ! strcmp( str1, "." ) )
1286     {
1287       str_tmp = "game.cs_";
1288
1289 #if defined(NO_LOGGING)
1290       strncpy( str_file, "game.csa", SIZE_FILENAME-1 );
1291 #else
1292       snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
1293                 str_dir_logs, record_num );
1294 #endif
1295       pf_dest = file_open( str_tmp, "w" );
1296       if ( pf_dest == NULL ) { return -2; }
1297
1298       pf_src = file_open( str_file, "r" );
1299       if ( pf_src == NULL )
1300         {
1301           file_close( pf_dest );
1302           return -2;
1303         }
1304
1305       while ( ( c = getc(pf_src) ) != EOF ) { putc( c, pf_dest ); }
1306
1307       iret = file_close( pf_src );
1308       if ( iret < 0 )
1309         {
1310           file_close( pf_dest );
1311           return iret;
1312         }
1313
1314       iret = file_close( pf_dest );
1315       if ( iret < 0 ) { return iret; }
1316
1317       flag |= flag_time;
1318       str1  = str_tmp;
1319     }
1320
1321   iret = read_record( ptree, str1, moves, flag );
1322   if ( iret < 0 ) { return iret; }
1323
1324   iret = get_elapsed( &time_turn_start );
1325   if ( iret < 0 ) { return iret; }
1326
1327   if ( str_tmp && remove( str_tmp ) )
1328     {
1329       out_warning( "remove() failed." );
1330       return -2;
1331     }
1332
1333   return 1;
1334 }
1335
1336
1337 static int CONV cmd_resign( tree_t * restrict ptree, char **lasts )
1338 {
1339   const char *str = strtok_r( NULL, str_delimiters, lasts );
1340   char *ptr;
1341   long l;
1342
1343   if ( str == NULL || *str == 'T' )
1344     {
1345       AbortDifficultCommand;
1346
1347       if ( game_status & mask_game_end ) { return 1; }
1348
1349       game_status |= flag_resigned;
1350       update_time( root_turn );
1351       out_CSA( ptree, &record_game, MOVE_RESIGN );
1352     }
1353   else {
1354     l = strtol( str, &ptr, 0 );
1355     if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
1356       {
1357         str_error = str_bad_cmdline;
1358         return -2;
1359       }
1360     resign_threshold = (int)l;
1361   }
1362
1363   return 1;
1364 }
1365
1366
1367 static int CONV cmd_move( tree_t * restrict ptree, char **lasts )
1368 {
1369   const char *str = strtok_r( NULL, str_delimiters, lasts );
1370   char *ptr;
1371   long l;
1372   unsigned int move;
1373   int iret, i;
1374
1375   if ( game_status & mask_game_end )
1376     {
1377       str_error = str_game_ended;
1378       return -2;
1379     }
1380   
1381   AbortDifficultCommand;
1382
1383   if ( str == NULL )
1384     {
1385       iret = get_elapsed( &time_turn_start );
1386       if ( iret < 0 ) { return iret; }
1387       
1388       return com_turn_start( ptree, 0 );
1389     }
1390
1391   l = strtol( str, &ptr, 0 );
1392   if ( str != ptr && l != LONG_MAX && l >= 1 && *ptr == '\0' )
1393     {
1394       for ( i = 0; i < l; i += 1 )
1395         {
1396           if ( game_status & ( flag_move_now | mask_game_end ) ) { break; }
1397
1398           iret = get_elapsed( &time_turn_start );
1399           if ( iret < 0 ) { return iret; }
1400         
1401           iret = com_turn_start( ptree, 0 );
1402           if ( iret < 0 ) { return iret; }
1403         }
1404
1405       return 1;
1406     }
1407
1408   do {
1409     iret = interpret_CSA_move( ptree, &move, str );
1410     if ( iret < 0 ) { return iret; }
1411     
1412     iret = get_elapsed( &time_turn_start );
1413     if ( iret < 0 ) { return iret; }
1414     
1415     iret = make_move_root( ptree, move,
1416                            ( flag_history | flag_time | flag_rep
1417                              | flag_detect_hang ) );
1418     if ( iret < 0 ) { return iret; }
1419     
1420     str = strtok_r( NULL, str_delimiters, lasts );
1421
1422   } while ( str != NULL );
1423   
1424   return 1;
1425 }
1426
1427
1428 static int CONV cmd_new( tree_t * restrict ptree, char **lasts )
1429 {
1430   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
1431   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
1432   const min_posi_t *pmp;
1433   min_posi_t min_posi;
1434   int iret;
1435
1436   AbortDifficultCommand;
1437
1438   if ( str1 != NULL )
1439     {
1440       memset( &min_posi.asquare, empty, nsquare );
1441       min_posi.hand_black = min_posi.hand_white = 0;
1442       iret = read_board_rep1( str1, &min_posi );
1443       if ( iret < 0 ) { return iret; }
1444
1445       if ( str2 != NULL )
1446         {
1447           if      ( ! strcmp( str2, "-" ) ) { min_posi.turn_to_move = white; }
1448           else if ( ! strcmp( str2, "+" ) ) { min_posi.turn_to_move = black; }
1449           else {
1450             str_error = str_bad_cmdline;
1451             return -2;
1452           }
1453         }
1454       else { min_posi.turn_to_move = black; }
1455
1456       pmp = &min_posi;
1457     }
1458   else { pmp = &min_posi_no_handicap; }
1459
1460   iret = ini_game( ptree, pmp, flag_history, NULL, NULL );
1461   if ( iret < 0 ) { return iret; }
1462
1463   return get_elapsed( &time_turn_start );
1464 }
1465
1466
1467 static int CONV cmd_outmove( tree_t * restrict ptree )
1468 {
1469   const char *str_move;
1470   char buffer[256];
1471   unsigned int move_list[ MAX_LEGAL_MOVES ];
1472   int i, c, n;
1473
1474   AbortDifficultCommand;
1475
1476   if ( game_status & mask_game_end )
1477     {
1478       Out( "NO LEGAL MOVE\n" );
1479       DFPNOut( "NO LEGAL MOVE\n" );
1480       return 1;
1481     }
1482
1483   n = gen_legal_moves( ptree, move_list, 0 );
1484
1485   buffer[0]='\0';
1486   for ( c = i = 0; i < n; i += 1 )
1487     {
1488       str_move = str_CSA_move(move_list[i]);
1489
1490       if ( i && ( i % 10 ) == 0 )
1491         {
1492           Out( "%s\n", buffer );
1493           DFPNOut( "%s ", buffer );
1494           memcpy( buffer, str_move, 6 );
1495           c = 6;
1496         }
1497       else if ( i )
1498         {
1499           buffer[c] = ' ';
1500           memcpy( buffer + c + 1, str_move, 6 );
1501           c += 7;
1502         }
1503       else {
1504         memcpy( buffer + c, str_move, 6 );
1505         c += 6;
1506       }
1507       buffer[c] = '\0';
1508     }
1509   Out( "%s\n", buffer );
1510   DFPNOut( "%s\n", buffer );
1511
1512   return 1;
1513 }
1514
1515
1516 static int CONV cmd_problem( tree_t * restrict ptree, char **lasts )
1517 {
1518   const char *str = strtok_r( NULL, str_delimiters, lasts );
1519   char *ptr;
1520   long l;
1521   unsigned int nposition;
1522   int iret;
1523 #if defined(DFPN)
1524   int is_mate;
1525 #endif
1526
1527   AbortDifficultCommand;
1528
1529
1530 #if defined(DFPN)
1531   is_mate = 0;
1532   if ( str != NULL && ! strcmp( str, "mate" ) )
1533     {
1534       is_mate = 1;
1535       str     = strtok_r( NULL, str_delimiters, lasts );
1536     }
1537 #endif
1538
1539   if ( str != NULL )
1540     {
1541       l = strtol( str, &ptr, 0 );
1542       if ( ptr == str || l == LONG_MAX || l < 1 )
1543         {
1544           str_error = str_bad_cmdline;
1545           return -2;
1546         }
1547       nposition = (unsigned int)l;
1548     }
1549   else { nposition = UINT_MAX; }
1550
1551   
1552   iret = record_open( &record_problems, "problem.csa", mode_read, NULL, NULL );
1553   if ( iret < 0 ) { return iret; }
1554
1555 #if defined(DFPN)
1556   iret = is_mate ? solve_mate_problems( ptree, nposition )
1557                  : solve_problems( ptree, nposition );
1558 #else
1559   iret = solve_problems( ptree, nposition );
1560 #endif
1561
1562   if ( iret < 0 )
1563     {
1564       record_close( &record_problems );
1565       return iret;
1566     }
1567
1568   iret = record_close( &record_problems );
1569   if ( iret < 0 ) { return iret; }
1570
1571   return get_elapsed( &time_turn_start );
1572 }
1573
1574
1575 static int CONV cmd_quit( void )
1576 {
1577   game_status |= flag_quit;
1578   return 1;
1579 }
1580
1581
1582 static int CONV cmd_suspend( void )
1583 {
1584   if ( game_status & ( flag_pondering | flag_puzzling ) )
1585     {
1586       game_status |= flag_quit_ponder;
1587       return 2;
1588     }
1589   
1590   game_status |= flag_suspend;
1591   return 1;
1592 }
1593
1594
1595 static int CONV cmd_time( char **lasts )
1596 {
1597   const char *str = strtok_r( NULL, str_delimiters, lasts );
1598   char *ptr;
1599
1600   if ( str == NULL )
1601     {
1602       str_error = str_bad_cmdline;
1603       return -2;
1604     }
1605   else if ( ! strcmp( str, "response" ) )
1606     {
1607       long l;
1608       str = strtok_r( NULL, str_delimiters, lasts );
1609       if ( str == NULL )
1610         {
1611           str_error = str_bad_cmdline;
1612           return -2;
1613         }
1614       l = strtol( str, &ptr, 0 );
1615       if ( ptr == str || l == LONG_MAX || l < 0 || l > 1000 )
1616         {
1617           str_error = str_bad_cmdline;
1618           return -2;
1619         }
1620       time_response = (unsigned int)l;
1621       return 1;
1622     }
1623   else if ( ! strcmp( str, "remain" ) )
1624     {
1625       long l1, l2;
1626       
1627       str = strtok_r( NULL, str_delimiters, lasts );
1628       if ( str == NULL )
1629         {
1630           str_error = str_bad_cmdline;
1631           return -2;
1632         }
1633       l1 = strtol( str, &ptr, 0 );
1634       if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
1635         {
1636           str_error = str_bad_cmdline;
1637           return -2;
1638         }
1639
1640       str = strtok_r( NULL, str_delimiters, lasts );
1641       if ( str == NULL )
1642         {
1643           str_error = str_bad_cmdline;
1644           return -2;
1645         }
1646       l2 = strtol( str, &ptr, 0 );
1647       if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
1648         {
1649           str_error = str_bad_cmdline;
1650           return -2;
1651         }
1652
1653       if ( sec_limit_up == UINT_MAX )
1654         {
1655           str_error = str_bad_cmdline;
1656           return -2;
1657         }
1658
1659       return reset_time( (unsigned int)l1, (unsigned int)l2 );
1660     }
1661
1662   str_error = str_bad_cmdline;
1663   return -2;
1664 }
1665
1666
1667 #if !defined(MINIMUM)
1668 /* learn (ini|no-ini) steps games iterations tlp1 tlp2 */
1669 static int CONV cmd_learn( tree_t * restrict ptree, char **lasts )
1670 {
1671   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
1672   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
1673   const char *str3 = strtok_r( NULL, str_delimiters, lasts );
1674   const char *str4 = strtok_r( NULL, str_delimiters, lasts );
1675 #  if defined(TLP)
1676   const char *str5 = strtok_r( NULL, str_delimiters, lasts );
1677   const char *str6 = strtok_r( NULL, str_delimiters, lasts );
1678 #  endif
1679   char *ptr;
1680   long l;
1681   unsigned int max_games;
1682   int is_ini, nsteps, max_iterations, nworker1, nworker2, iret;
1683
1684   if ( str1 == NULL )
1685     {
1686       str_error = str_bad_cmdline;
1687       return -2;
1688     }
1689   if      ( ! strcmp( str1, "ini" ) )    { is_ini = 1; }
1690   else if ( ! strcmp( str1, "no-ini" ) ) { is_ini = 0; }
1691   else {
1692     str_error = str_bad_cmdline;
1693     return -2;
1694   }
1695
1696   max_games      = UINT_MAX;
1697   max_iterations = INT_MAX;
1698   nworker1 = nworker2 = nsteps = 1;
1699
1700   if ( str2 != NULL )
1701     {
1702       l = strtol( str2, &ptr, 0 );
1703       if ( ptr == str2 || l == LONG_MAX || l < 1 )
1704         {
1705           str_error = str_bad_cmdline;
1706           return -2;
1707         }
1708       nsteps = (int)l;
1709     }
1710
1711   if ( str3 != NULL )
1712     {
1713       l = strtol( str3, &ptr, 0 );
1714       if ( ptr == str3 || l == LONG_MAX || l == LONG_MIN )
1715         {
1716           str_error = str_bad_cmdline;
1717           return -2;
1718         }
1719       if ( l > 0 ) { max_games = (unsigned int)l; }
1720     }
1721
1722   if ( str4 != NULL )
1723     {
1724       l = strtol( str4, &ptr, 0 );
1725       if ( ptr == str4 || l == LONG_MAX || l == LONG_MIN )
1726         {
1727           str_error = str_bad_cmdline;
1728           return -2;
1729         }
1730       if ( l > 0 ) { max_iterations = (int)l; }
1731     }
1732
1733 #  if defined(TLP)
1734   if ( str5 != NULL )
1735     {
1736       l = strtol( str5, &ptr, 0 );
1737       if ( ptr == str5 || l > TLP_MAX_THREADS || l < 1 )
1738         {
1739           str_error = str_bad_cmdline;
1740           return -2;
1741         }
1742       nworker1 = (int)l;
1743     }
1744
1745   if ( str6 != NULL )
1746     {
1747       l = strtol( str6, &ptr, 0 );
1748       if ( ptr == str6 || l > TLP_MAX_THREADS || l < 1 )
1749         {
1750           str_error = str_bad_cmdline;
1751           return -2;
1752         }
1753       nworker2 = (int)l;
1754     }
1755 #  endif
1756
1757   AbortDifficultCommand;
1758
1759   log2_ntrans_table = 12;
1760
1761   memory_free( (void *)ptrans_table_orig );
1762
1763   iret = ini_trans_table();
1764   if ( iret < 0 ) { return iret; }
1765
1766   iret = learn( ptree, is_ini, nsteps, max_games, max_iterations,
1767                 nworker1, nworker2 );
1768   if ( iret < 0 ) { return -1; }
1769
1770   iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
1771   if ( iret < 0 ) { return -1; }
1772
1773   iret = get_elapsed( &time_turn_start );
1774   if ( iret < 0 ) { return iret; }
1775
1776   return 1;
1777 }
1778 #endif /* MINIMUM */
1779
1780
1781 #if defined(MPV)
1782 static int CONV cmd_mpv( char **lasts )
1783 {
1784   const char *str = strtok_r( NULL, str_delimiters, lasts );
1785   char *ptr;
1786   long l;
1787
1788   if ( str == NULL )
1789     {
1790       str_error = str_bad_cmdline;
1791       return -2;
1792     }
1793   else if ( ! strcmp( str, "num" ) )
1794     {
1795       str = strtok_r( NULL, str_delimiters, lasts );
1796       if ( str == NULL )
1797         {
1798           str_error = str_bad_cmdline;
1799           return -2;
1800         }
1801       l = strtol( str, &ptr, 0 );
1802       if ( ptr == str || l == LONG_MAX || l < 1 || l > MPV_MAX_PV )
1803         {
1804           str_error = str_bad_cmdline;
1805           return -2;
1806         }
1807
1808       AbortDifficultCommand;
1809
1810       mpv_num = (int)l;
1811
1812       return 1;
1813     }
1814   else if ( ! strcmp( str, "width" ) )
1815     {
1816       str = strtok_r( NULL, str_delimiters, lasts );
1817       if ( str == NULL )
1818         {
1819           str_error = str_bad_cmdline;
1820           return -2;
1821         }
1822       l = strtol( str, &ptr, 0 );
1823       if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
1824         {
1825           str_error = str_bad_cmdline;
1826           return -2;
1827         }
1828
1829       AbortDifficultCommand;
1830
1831       mpv_width = (int)l;
1832
1833       return 1;
1834     }
1835
1836   str_error = str_bad_cmdline;
1837   return -2;
1838 }
1839 #endif
1840
1841
1842 #if defined(DFPN)
1843 static int CONV cmd_dfpn( tree_t * restrict ptree, char **lasts )
1844 {
1845   const char *str = strtok_r( NULL, str_delimiters, lasts );
1846
1847   if ( str == NULL )
1848     {
1849       str_error = str_bad_cmdline;
1850       return -2;
1851     }
1852   else if ( ! strcmp( str, "hash" ) )
1853     {
1854       char *ptr;
1855       long l;
1856
1857       str = strtok_r( NULL, str_delimiters, lasts );
1858       if ( str == NULL )
1859         {
1860           str_error = str_bad_cmdline;
1861           return -2;
1862         }
1863       l = strtol( str, &ptr, 0 );
1864       if ( ptr == str || l == LONG_MAX || l < 1 )
1865         {
1866           str_error = str_bad_cmdline;
1867           return -2;
1868         }
1869
1870       AbortDifficultCommand;
1871
1872       dfpn_hash_log2 = (unsigned int)l;
1873       return dfpn_ini_hash();
1874     }
1875   else if ( ! strcmp( str, "go" ) )
1876     {
1877       AbortDifficultCommand;
1878
1879       return dfpn( ptree, root_turn, 1 );
1880     }
1881   else if ( ! strcmp( str, "connect" ) )
1882     {
1883       char str_addr[256];
1884       char str_id[256];
1885       char *ptr;
1886       long l;
1887       int port;
1888
1889       str = strtok_r( NULL, str_delimiters, lasts );
1890       if ( ! str || ! strcmp( str, "." ) ) { str = "127.0.0.1"; }
1891       strncpy( str_addr, str, 255 );
1892       str_addr[255] = '\0';
1893
1894       str = strtok_r( NULL, str_delimiters, lasts );
1895       if ( ! str || ! strcmp( str, "." ) ) { str = "4083"; }
1896       l = strtol( str, &ptr, 0 );
1897       if ( ptr == str || l == LONG_MAX || l < 0 || l > USHRT_MAX )
1898         {
1899           str_error = str_bad_cmdline;
1900           return -2;
1901         }
1902       port = (int)l;
1903
1904       str = strtok_r( NULL, str_delimiters, lasts );
1905       if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza1"; }
1906       strncpy( str_id, str, 255 );
1907       str_id[255] = '\0';
1908
1909       AbortDifficultCommand;
1910       
1911       dfpn_sckt = sckt_connect( str_addr, port );
1912       if ( dfpn_sckt == SCKT_NULL ) { return -2; }
1913
1914       str_buffer_cmdline[0] = '\0';
1915       DFPNOut( "Worker: %s\n", str_id );
1916
1917       return 1;
1918     }
1919
1920   str_error = str_bad_cmdline;
1921   return -2;
1922 }
1923 #endif
1924
1925
1926 #if defined(TLP)
1927 static int CONV cmd_thread( char **lasts )
1928 {
1929   const char *str = strtok_r( NULL, str_delimiters, lasts );
1930
1931   if ( str == NULL )
1932     {
1933       str_error = str_bad_cmdline;
1934       return -2;
1935     }
1936   else if ( ! strcmp( str, "num" ) )
1937     {
1938       char *ptr;
1939       long l;
1940
1941       str = strtok_r( NULL, str_delimiters, lasts );
1942       if ( str == NULL )
1943         {
1944           str_error = str_bad_cmdline;
1945           return -2;
1946         }
1947       l = strtol( str, &ptr, 0 );
1948       if ( ptr == str || l == LONG_MAX || l < 1 || l > TLP_MAX_THREADS )
1949         {
1950           str_error = str_bad_cmdline;
1951           return -2;
1952         }
1953
1954       TlpEnd();
1955
1956       tlp_max = (int)l;
1957
1958       if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
1959         {
1960           return tlp_start();
1961         }
1962       return 1;
1963     }
1964
1965   str_error = str_bad_cmdline;
1966   return -2;
1967 }
1968 #endif
1969
1970
1971 #if defined(DFPN_CLIENT)
1972 static int CONV cmd_dfpn_client( tree_t * restrict ptree, char **lasts )
1973 {
1974   const char *str;
1975   char *ptr;
1976   int iret;
1977
1978   AbortDifficultCommand;
1979
1980   str = strtok_r( NULL, str_delimiters, lasts );
1981   if ( ! str || ! strcmp( str, "." ) ) { str = "127.0.0.1"; }
1982   strncpy( dfpn_client_str_addr, str, 255 );
1983   dfpn_client_str_addr[255] = '\0';
1984
1985   str = strtok_r( NULL, str_delimiters, lasts );
1986   if ( ! str || ! strcmp( str, "." ) ) { str = "4083"; }
1987   dfpn_client_port = strtol( str, &ptr, 0 );
1988   if ( ptr == str || dfpn_client_port == LONG_MAX || dfpn_client_port < 0
1989        || dfpn_client_port > USHRT_MAX )
1990     {
1991       str_error = str_bad_cmdline;
1992       return -2;
1993     }
1994
1995   Out( "DFPN Server: %s %d\n", dfpn_client_str_addr, dfpn_client_port );
1996
1997   iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
1998   if ( iret < 0 ) { return iret; }
1999
2000   if ( dfpn_client_sckt == SCKT_NULL )
2001     {
2002       str_error = "Check network status.";
2003       return -1;
2004     }
2005
2006   return get_elapsed( &time_turn_start );
2007 }
2008 #endif
2009
2010
2011 #if defined(CSA_LAN)
2012 static int CONV cmd_connect( tree_t * restrict ptree, char **lasts )
2013 {
2014   const char *str;
2015   char *ptr;
2016   long max_games;
2017
2018   str = strtok_r( NULL, str_delimiters, lasts );
2019   if ( ! str || ! strcmp( str, "." ) ) { str = "gserver.computer-shogi.org"; }
2020   strncpy( client_str_addr, str, 255 );
2021   client_str_addr[255] = '\0';
2022
2023   str = strtok_r( NULL, str_delimiters, lasts );
2024   if ( ! str || ! strcmp( str, "." ) ) { str = "4081"; }
2025   client_port = strtol( str, &ptr, 0 );
2026   if ( ptr == str || client_port == LONG_MAX || client_port < 0
2027        || client_port > USHRT_MAX )
2028     {
2029       str_error = str_bad_cmdline;
2030       return -2;
2031     }
2032
2033   str = strtok_r( NULL, str_delimiters, lasts );
2034   if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
2035   strncpy( client_str_id, str, 255 );
2036   client_str_id[255] = '\0';
2037
2038   str = strtok_r( NULL, " \t", lasts );
2039   if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
2040   strncpy( client_str_pwd, str, 255 );
2041   client_str_pwd[255] = '\0';
2042
2043   str = strtok_r( NULL, str_delimiters, lasts );
2044   if ( ! str || ! strcmp( str, "." ) ) { client_max_game = INT_MAX; }
2045   else {
2046     max_games = strtol( str, &ptr, 0 );
2047     if ( ptr == str || max_games == LONG_MAX || max_games < 1 )
2048     {
2049       str_error = str_bad_cmdline;
2050       return -2;
2051     }
2052     client_max_game = max_games;
2053   }
2054
2055   AbortDifficultCommand;
2056
2057   client_ngame          = 0;
2058
2059   return client_next_game( ptree, client_str_addr, (int)client_port );
2060 }
2061
2062
2063 static int CONV cmd_sendpv( char **lasts )
2064 {
2065   const char *str = strtok_r( NULL, str_delimiters, lasts );
2066
2067   if ( str == NULL )
2068     {
2069       str_error = str_bad_cmdline;
2070       return -2;
2071     }
2072
2073   if      ( ! strcmp( str, str_off ) ) {  game_status &= ~flag_sendpv; }
2074   else if ( ! strcmp( str, str_on ) )  {  game_status |=  flag_sendpv; }
2075   else {
2076     str_error = str_bad_cmdline;
2077     return -2;
2078   }
2079
2080   return 1;
2081 }
2082 #endif
2083
2084
2085 #if defined(MNJ_LAN)
2086 /* mnj sd seed addr port name factor stable_depth */
2087 static int CONV cmd_mnj( char **lasts )
2088 {
2089   char client_str_addr[256];
2090   char client_str_id[256];
2091   const char *str;
2092   char *ptr;
2093   unsigned int seed;
2094   long l;
2095   int client_port, sd;
2096   double factor;
2097
2098   str = strtok_r( NULL, str_delimiters, lasts );
2099   if ( ! str )
2100     {
2101       str_error = str_bad_cmdline;
2102       return -2;
2103     }
2104   l = strtol( str, &ptr, 0 );
2105   if ( ptr == str || l == LONG_MAX || l < 0 )
2106     {
2107       str_error = str_bad_cmdline;
2108       return -2;
2109     }
2110   sd = (int)l;
2111
2112
2113   str = strtok_r( NULL, str_delimiters, lasts );
2114   if ( ! str )
2115     {
2116       str_error = str_bad_cmdline;
2117       return -2;
2118     }
2119   l = strtol( str, &ptr, 0 );
2120   if ( ptr == str || l == LONG_MAX || l < 0 )
2121     {
2122       str_error = str_bad_cmdline;
2123       return -2;
2124     }
2125   seed = (unsigned int)l;
2126
2127
2128   str = strtok_r( NULL, str_delimiters, lasts );
2129   if ( ! str || ! strcmp( str, "." ) ) { str = "localhost"; }
2130   strncpy( client_str_addr, str, 255 );
2131   client_str_addr[255] = '\0';
2132
2133
2134   str = strtok_r( NULL, str_delimiters, lasts );
2135   if ( ! str || ! strcmp( str, "." ) ) { str = "4082"; }
2136   l = strtol( str, &ptr, 0 );
2137   if ( ptr == str || l == LONG_MAX || l < 0 || l > USHRT_MAX )
2138     {
2139       str_error = str_bad_cmdline;
2140       return -2;
2141     }
2142   client_port = (int)l;
2143
2144
2145   str = strtok_r( NULL, str_delimiters, lasts );
2146   if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza1"; }
2147   strncpy( client_str_id, str, 255 );
2148   client_str_id[255] = '\0';
2149
2150   str = strtok_r( NULL, str_delimiters, lasts );
2151   if ( ! str || ! strcmp( str, "." ) ) { str = "1.0"; }
2152   factor = strtod( str, &ptr );
2153   if ( ptr == str || factor < 0.0 )
2154     {
2155       str_error = str_bad_cmdline;
2156       return -2;
2157     }
2158
2159   str = strtok_r( NULL, str_delimiters, lasts );
2160   if ( ! str || ! strcmp( str, "." ) ) { l = -1; }
2161   else {
2162     l = strtol( str, &ptr, 0 );
2163     if ( ptr == str || l == LONG_MAX )
2164       {
2165         str_error = str_bad_cmdline;
2166         return -2;
2167       }
2168   }
2169   if ( l <= 0 ) { mnj_depth_stable = INT_MAX; }
2170   else          { mnj_depth_stable = (int)l; }
2171
2172   AbortDifficultCommand;
2173
2174   resign_threshold  = 65535;
2175   game_status      |= ( flag_noponder | flag_noprompt );
2176   if ( mnj_reset_tbl( sd, seed ) < 0 ) { return -1; }
2177
2178   sckt_mnj = sckt_connect( client_str_addr, (int)client_port );
2179   if ( sckt_mnj == SCKT_NULL ) { return -2; }
2180
2181   str_buffer_cmdline[0] = '\0';
2182
2183   Out( "Sending my name %s", client_str_id );
2184   MnjOut( "%s %g final%s\n", client_str_id, factor,
2185           ( mnj_depth_stable == INT_MAX ) ? "" : " stable" );
2186
2187   return cmd_suspend();
2188 }
2189 #endif
2190
2191