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