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