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