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