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