// EXchess source code, (c) Daniel C. Homan  1997-2011
// Released under the GNU public license, see file license.txt

// Thanks to Jim Ablett for fixes to the polling code which 
// allow EXchess to work with the mingw compiler on windows!

/*  Main functions controlling program */


#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <csignal>
#include <fstream>
using namespace std;

#include "define.h"
#include "chess.h"
#include "search.h"

#if MSVC || MINGW
 #include <windows.h>
 #include <time.h>
 #include <conio.h>
 #if MSVC
  #undef BLACK
  #undef WHITE
  #define BLACK 0
  #define WHITE 1
 #endif
#else 
 #include <time.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/time.h>
#endif


// Custom headers, defining external functions and struct types for
// board, piece and moves.  And defining global variables.

#include "chess.h"
#include "const.h"
#include "funct.h"
#include "hash.h"
#include "extern.h"


// Main Game Structure
game_rec game;

// Logging variables
ofstream logfile;
int MAX_LOGS = 100;

// Flags for input and display
int display_board = 0;
int input_test = 0;
int command_parse = 0;
char response[60];        // first word of input string from command prompt

// Basic control flags for whole game
int xboard, post, ics, ALLEG = 0, hintflag = 0, tcount = 1;
int ponder_flag = 1, shout_book;

// Executable directory
char exec_path[FILENAME_MAX];

#if UNIX
 fd_set read_fds;
 struct timeval timeout = { 0, 0 };
#endif

#if FLTK_GUI
 int FLTKmain(int argc, char** argv);
#endif

/*------------------------- Main Function ---------------------------*/
//  Main control function that interacts with the User

int main(int argc, char *argv[])
{
  char mstring[10], outstring[200];
  move hint;
  xboard = 0; game.ts.ponder = 0; ics = 0; shout_book = 0;

    setbuf(stdout, NULL);
    setbuf(stdin, NULL);
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stdin, NULL, _IONBF, 0);   


   strcpy(exec_path, argv[0]);
   // parsing exec path
   int last_slash = -1;
   for(int j = 0; j < 100; j++) {
     if(exec_path[j] == '\0') break;
     if(exec_path[j] == '\\') last_slash = j;
     if(exec_path[j] == '/') last_slash = j;
   }

   if(last_slash == 0) strcpy(exec_path, "./");
   else exec_path[last_slash+1] = '\0';

 /* initializing hash tables, check tables, scoring parameters,
    and the random number seed and tablebases */
  open_hash(); gen_check_table(); set_search_param(); read_scores();

 // Do we learn?
  game.td_learning = SCORE_LEARNING;
  game.learn_bk = BOOK_LEARNING;

 // Set chess skill
  game.knowledge_scale = CHESS_SKILL;
  if(game.knowledge_scale < 1) game.knowledge_scale = 1;
  if(game.knowledge_scale > 100) game.knowledge_scale = 100;

 // initialize board again to be sure hash numbers are correct.
  game.setboard(i_pos, 'w', "KQkq", "-");

#if TABLEBASES
  init_tb();
#endif   
   
  sgenrand(time(NULL));

 /* opening logging file */
  if(logging) {
    char lfile[FILENAME_MAX];
    strcpy(lfile, exec_path);
    strcpy(lfile, "run_icc.log");
    for(int li = 1; li <= MAX_LOGS; li++) {
     // if there is an icc log file, just append to that
     if(li==1) {
      logfile.open(lfile, ios::in);
      if(logfile.is_open()) { 
        logfile.close(); 
        logfile.open(lfile, ios::app); 
        break;
      } else {
        logfile.close();
      }
     }
     // otherwise find a new file name for log
     if(li < 10) sprintf(lfile, "%srun_00%i.log", exec_path, li);
     else if(li < 100) sprintf(lfile, "%srun_0%i.log", exec_path, li);
     else sprintf(lfile, "%srun_%i.log", exec_path, li);
     logfile.open(lfile, ios::in);
     if(!logfile.is_open()) {
       logfile.close();
       logfile.open(lfile, ios::out);       
       break;
     } else {
       logfile.close();
     }
    }
    if(!logfile.is_open()) {
     cout << "Error(Can't open logging file!)\n";
     logging = 0;
    } else {
     logfile.clear();
     logfile << "Log file for EXchess v" << VERS << VERS2 << "\n";
     logfile << "============================\n"; 
    }
  }

  /* parsing input line */
  if(argc > 1) {
    // command line score value change, use centipawn as smallest unit
    if(!strcmp(argv[1], "setvalue")) { 
      set_score_value(argv[2], (atoi(argv[3])*10));
      if(argc > 4 && !strcmp(argv[4], "test")) {
        game.test_suite(argv[5], argv[6], atoi(argv[7]));
        close_hash();
        return 0;
      }
    }
    if(!strcmp(argv[1], "xb")) { 
      xboard = 1;
    }
    if(!strcmp(argv[1], "hash")) set_hash_size(ABS(atoi(argv[2])));
    if(argc > 2) {
      if(!strcmp(argv[2], "hash")) set_hash_size(ABS(atoi(argv[3])));
      if(argc > 3 && !strcmp(argv[3], "test")) {
        game.test_suite(argv[4], argv[5], atoi(argv[6]));
        close_hash();
        return 0;
      }
   }
  }

#if FLTK_GUI
#if UNIX
  /* throw away cout output */
  streambuf *nullbuf;
  ofstream nullstr;
  nullstr.open("/dev/null");
  nullbuf = nullstr.rdbuf();
  cout.rdbuf(nullbuf);
#endif
  /* Start main loop for GUI interface */
  game.pos.allmoves(&game.movelist, &game.ts);     // find legal moves
  return FLTKmain(argc,argv);
#endif

  if(!xboard) {
    cout << "\nExperimental Chess Program (EXchess) version " << VERS << VERS2 << " (beta),"
         << "\nCopyright (C) 1997-2011 Daniel C. Homan, Granville OH, USA"
         << "\nEXchess comes with ABSOLUTELY NO WARRANTY. This is free"
         << "\nsoftware, and you are welcome to redistribute it under"
         << "\ncertain conditions. This program is distributed under the"
         << "\nGNU public license.  See the files license.txt and readme.txt"
         << "\nfor more information.\n\n";

    cout << "Hash size = " << TAB_SIZE << " entries, "
         << TAB_SIZE*sizeof(hash_rec) << " bytes\n";
    cout << "Pawn size = " << PAWN_SIZE << " entries, "
         << PAWN_SIZE*sizeof(pawn_rec) << " bytes\n\n";
    cout << "Type 'help' for a list of commands.\n>";
  }

  /* main loop for text interface */

  while (tcount > 0)
   {

    // find a hint move, check book first then look in pv
    if(hintflag) {
      hint.t = 0;
      if(game.ts.last_ponder) hint = game.ts.ponder_move;
      else if(game.book) hint = opening_book(game.pos.hcode, game.pos, &game);
      if(!hint.t) hint = game.ts.pc[0][1];
      if(hint.t) {
       print_move(game.pos, hint, mstring);
       cout << "Hint: " << mstring << "\n";
      }
      hintflag = 0;
    }

    signal(SIGINT, SIG_IGN);

    // pondering if possible
    if(game.T > 2 && game.p_side == game.pos.wtm
       && !game.both && !game.ts.last_ponder && ponder_flag)
    {
      if(!xboard) cout << "pondering... (press any key to interrupt)\n";
      cout.flush();
      game.ts.ponder = 1;
      game.ts.search(game.pos, 1, game.T+1, &game);
      game.ts.ponder = 0;
      game.ts.last_ponder = 1;
    }

    // if analysis_mode, do some analysis
    if(game.ts.analysis_mode) {
      game.p_side = !game.pos.wtm;
      game.ts.search(game.pos, 36000000, game.T, &game);
      game.p_side = game.pos.wtm;
    }

    if(!game.pos.wtm)                        // if it is black's turn
    {
     if(game.both) game.p_side = 0;
     if(!xboard) cout << "Black-To-Move[" << floor((double)game.T/2) << "]: ";
     if(logging) logfile << "Black-To-Move[" << floor((double)game.T/2) << "]: ";
    }
    else                                         // or if it is white's
    {
     if(game.both) game.p_side = 1;
     if(!xboard) cout << "White-To-Move[" << (floor((double)game.T/2) + 1) << "]: ";
     if(logging) logfile << "White-To-Move[" << (floor((double)game.T/2) + 1) << "]: ";
    }

    cout.flush();

    game.pos.allmoves(&game.movelist, &game.ts);     // find legal moves

    if(game.p_side == game.pos.wtm || game.over) {
      if(!command_parse) cin >> response;      // get the command
      if(logging) logfile << response << "\n";
      if((game.ts.last_ponder || game.ts.analysis_mode) && UNIX) cout << "\n";       
      parse_command();      // parse it
    } else {
      if(!xboard) cout << "Thinking ...\n";
      if(logging) logfile << "Thinking ...\n";
      cout.flush();
      make_move();
      game.ts.last_ponder = 0;
      game.T++;
    }

    cout.flush();
    if(logging) logfile.flush();
   }

  if(logging) logfile.close();
  close_hash();

  return 0;
}

// Function to takeback moves
// tm is the number of moves to take back.
// 1 or 2 with current setup
void takeback(int tm)
{
 int temp_turn = game.T;
 // no book learning yet
 game.learn_count = 0; game.learned = 0;
 // game is not over
 game.over = 0;
 game.pos = game.reset;
 game.T = temp_turn; if(!(game.T % 2)) game.p_side = 0;
 if(game.p_side == 0 && tm == 1) game.p_side = 1;
 for (int ip = 0; ip <= game.T-2-tm; ip++)
 {
  game.pos.exec_move(game.game_history[ip], 0);
 }
 if(!xboard && !FLTK_GUI) drawboard();
 game.T = game.T - tm;
 game.pos.allmoves(&game.movelist, &game.ts);     // find legal moves
}


// Function to make the next move... If it is the computer's turn, this
// function calls the search algorithm, takes the best move given by that
// search, and makes the move - unless it is a check move: then it flagges
// stale-mate.....
// The function also looks to see if this move places the opponent in check
// or check-mate.

void make_move()
{
   int mtime = GetTime(); int time_limit, legal, ri;
   char mstring[10]; int time_div = 30; int rep_count = 0;
   char outstring[400];

   // if pondering is off, use a different time-control strategy
   if(!ponder_flag) time_div = 40;

   // If it is not the player's turn, figure out how much time to use,
   // execute the search algorithm to start the search process and return
   // the best move.

   if(game.mttc && game.mttc < time_div)
    { time_limit = int(game.timeleft[game.pos.wtm]/(game.mttc+1));
      if(game.timeleft[game.pos.wtm] > 6.0*game.inc*100) time_limit += game.inc*100;
      else if(game.timeleft[game.pos.wtm] > 3.0*game.inc*100) time_limit += game.inc*50; }
   else if (game.mttc >= time_div || xboard) { time_limit = int(game.timeleft[game.pos.wtm]/time_div);
      if(game.timeleft[game.pos.wtm] > 6.0*game.inc*100) time_limit += game.inc*100;
      else if(game.timeleft[game.pos.wtm] > 3.0*game.inc*100) time_limit += game.inc*50; }
   else { time_limit = int(game.timeleft[game.pos.wtm]); }

   if(time_limit > int(game.timeleft[game.pos.wtm]/2) && (game.mttc || xboard))
    time_limit = int(game.timeleft[game.pos.wtm]/2);

   if (game.p_side != game.pos.wtm)
   {
    game.best = game.ts.search(game.pos, time_limit, game.T, &game);
    game.timeleft[game.pos.wtm] -= float(GetTime() - mtime); 
    game.timeleft[game.pos.wtm] += float(game.inc*100);
   }

   // reduce time control by one move after every pair of moves in the game, should avoid the
   // winboard 'bug' introduced when forced moves are made by at the start of the game for the engine
   if(!(game.T&1)) {
    if(game.mttc) { 
      game.mttc--; 
      if(!game.mttc) { 
	game.timeleft[0] += game.base*100; 
	game.timeleft[1] += game.base*100; 
	game.mttc = game.omttc; 
      } 
    }
    if(game.mttc <= 0 && !xboard) { 
      game.timeleft[0] = game.base*100; 
      game.timeleft[1] = game.base*100;
      game.mttc = game.omttc; 
    }
   }

   // execute the move....
   game.temp = game.pos;
   legal = game.temp.exec_move(game.best, 0);

   // check input to see if the game ended while we were thinking
   input_test = 1;
   if(!FLTK_GUI) if(inter()) { 
	 cin >> response; 
	 if(!strcmp(response, "result")) { 
	   game.over = 1;
	 } else {
           command_parse = 1;
	 }
   }
   input_test = 0;

   // if game isn't over, make the move
   if(!game.over) {
    
    // Is the move legal? if not Error ....
    if (legal) {
      print_move(game.pos, game.best, mstring);
      strcpy(game.lmove,mstring);
      // if it is the computer's turn - echo the move
      if(game.p_side != game.pos.wtm || FLTK_GUI) {
	if(!xboard) {
	  if(game.pos.wtm) {
	    cout << (ceil((double)game.T/2) + 1) << ". ";
	    sprintf(outstring, "%i. ", (int(((double)game.T)/2) + 1));
	    write_out(outstring);
	  } else {
	    cout << ceil((double)game.T/2) << ". ... ";
	    sprintf(outstring, "%i. ... ", int(((double)game.T)/2));
	    write_out(outstring);
	  }
	} else {
	  cout << "move ";
	}
        cout << mstring << "\n"; cout.flush();
        write_out(mstring); write_out("\n");
      }

      game.last = game.pos;        // Save last position
      game.pos = game.temp;        // actually execute move

      // Check if we have, check_mate, stale_mate, or a continuing game...
      switch (game.pos.in_check_mate()) {
       case 0:
         if(game.pos.fifty >= 100) { 
           game.over = 1;
	   cout << "1/2-1/2 {50 moves}\n";
           sprintf(game.overstring,"1/2-1/2 {50 moves}"); 
	   write_out(game.overstring);
           if(ics) cout << "tellics draw\n"; 
	 } else if(game.pos.in_check() && !xboard) {
	   cout << "Check!\n"; 
	 }
         // check for a 3-rep
         for(ri = game.T-2; ri >= game.T-game.pos.fifty && rep_count < 2; ri -= 2)
          if(game.plist[ri] == game.pos.hcode) {
           rep_count++;
           if(rep_count > 1) {
	     game.over = 1;
	     cout << "1/2-1/2 {3-rep}\n";
	     sprintf(game.overstring,"1/2-1/2 {3-rep}"); 
	     write_out(game.overstring);
	     if(ics) cout << "tellics draw\n";
           }
          }    
         break;
       case 1:
         game.over = 1;
         if(!game.pos.wtm) { 
	   cout << "1-0 {White Mates}\n";
           sprintf(game.overstring,"1-0 {White Mates}"); 
	   write_out(game.overstring);
         } else {
	   cout << "0-1 {Black Mates}\n";
           sprintf(game.overstring,"0-1 {Black Mates}"); 
	   write_out(game.overstring);
	 }
         break;
       case 2:
         game.over = 1;
         cout << "1/2-1/2 {Stalemate}\n";
	 sprintf(game.overstring,"1/2-1/2 {Stalemate}"); 
	 write_out(game.overstring);
      }

      game.game_history[game.T-1] = game.best; // record the move in the history list
      game.plist[game.T] = game.pos.hcode;
      if(!xboard && display_board) drawboard();  // draw the resulting board
    } else { 
      game.over = 1; 
      cout << "Error - please reset"; 
      sprintf(game.overstring,"Error - please reset\n"); 
      write_out(game.overstring);
    }
   } 

}


// This function is a special edit mode for xboard/winboard
void board_edit()
{
   char edcom[4];    // edit command
   int edside = 1;   // side being edited
   int ex, ey;       // edit coordinates

   game.pos.castle = 0;

   // no book learning yet
   game.learn_count = 0; game.learned = 0;

   while(edside > -1) {
     cin >> edcom;
     if(edcom[0] == '#') {
       // clear the board
       for(int ci = 0; ci < 64; ci++) { game.pos.sq[ci] = empty; }
     } else if(edcom[0] == 'c') {
       edside ^= 1;           // change side to edit
       continue;
     } else if(edcom[0] == '.') {
       edside = -1;  // exit edit mode
     } else {
       ex = CHAR_FILE(edcom[1]);
       ey = CHAR_ROW(edcom[2]);
       game.pos.sq[SQR(ex,ey)].side = edside;
       switch(edcom[0]) {
          case 'P':
            game.pos.sq[SQR(ex,ey)].type = PAWN; break;
          case 'N':
            game.pos.sq[SQR(ex,ey)].type = KNIGHT; break;
          case 'B':
            game.pos.sq[SQR(ex,ey)].type = BISHOP; break;
          case 'R':
            game.pos.sq[SQR(ex,ey)].type = ROOK; break;
          case 'Q':
            game.pos.sq[SQR(ex,ey)].type = QUEEN; break;
          case 'K':
            game.pos.sq[SQR(ex,ey)].type = KING;
            break;
          case 'X':
            game.pos.sq[SQR(ex,ey)] = empty; break;
       }
     }
   }

   // setup castling rights... edit assumes castling is OK if
   // the king and rook are on their starting squares 
   if(ID(game.pos.sq[SQR(4,0)]) == WKING) {
     if(ID(game.pos.sq[SQR(7,0)]) == WROOK) game.pos.castle |= 1;  // kingside
     if(ID(game.pos.sq[SQR(0,0)]) == WROOK) game.pos.castle |= 2;  // queenside
   }  
   if(ID(game.pos.sq[SQR(4,7)]) == BKING) {
     if(ID(game.pos.sq[SQR(7,7)]) == BROOK) game.pos.castle |= 4;  // kingside
     if(ID(game.pos.sq[SQR(0,7)]) == BROOK) game.pos.castle |= 8;  // queenside
   }  

   // generate the hash_code for this position
   //  -- function also creates the piece lists and counts and game stage
   game.pos.gen_code();

   game.pos.has_castled[0] = 0;
   game.pos.has_castled[1] = 0;
   game.pos.in_check();
   game.plist[game.T-1] = game.pos.hcode;
   game.reset = game.pos;
   return;
}


// This function draws the graphical board in a very simple way
void drawboard()
{
  char mstring[10];     // character string to hold move

 // the following for loop steps through the board and paints each square
  for (int j = 7; j >= 0; j--)
  {
   cout << "\n  +---+---+---+---+---+---+---+---+\n" << (j+1) << " | ";
   for (int i = 0; i <= 7; i++)
   {
    if(!game.pos.sq[SQR(i,j)].side) cout << "\b<" << name[game.pos.sq[SQR(i,j)].type] << ">| ";
    else if(game.pos.sq[SQR(i,j)].side == 1) cout << name[game.pos.sq[SQR(i,j)].type] << " | ";
    else if(!((i+j)&1)) cout << "\b:::| ";
    else cout << "  | ";
   }
   if(j==7) { if(game.pos.wtm) cout << "   White to move";
                          else cout << "   Black to move"; }
   if(j==6) {
     cout << "   castle: ";
     if(game.pos.castle&1) cout << "K";
     if(game.pos.castle&2) cout << "Q";
     if(game.pos.castle&4) cout << "k";
     if(game.pos.castle&8) cout << "q";
     if(!game.pos.castle)  cout << "-";
   }
   if(j==5 && game.pos.ep)
     cout << "   ep: " << char(FILE(game.pos.ep) + 97) << (RANK(game.pos.ep) + 1);
   if(j==4 && game.pos.last.t) {
     cout << "   last: ";
     print_move(game.last, game.pos.last, mstring);
     cout << mstring;
    }
   if(j==3) cout << "   fifty: " << ceil((double)game.pos.fifty/2);
   if(j==2) cout << "   Computer time: " << int(game.timeleft[game.p_side^1]/100) << " seconds";
  }
   cout << "\n  +---+---+---+---+---+---+---+---+";
   cout << "\n    a   b   c   d   e   f   g   h  \n\n";
}


// Help function
void help()
{
 char ch;   // dummy character

 cout <<   "\n Commands ........ ";
 cout << "\n\n   Enter a move in standard algebraic notation,";
 cout <<   "\n      Nf3, e4, O-O, d8=Q, Bxf7, Ned7, etc....";
 cout <<   "\n      Other notation's like: g1f3, e2e4, etc... are also ok.";
 cout << "\n\n   new            -> start a new game";
 cout <<   "\n   quit           -> end EXchess";
 cout <<   "\n   save           -> save the game to a text file";
 cout <<   "\n   go             -> computer takes side on move";
 cout <<   "\n   white          -> white to move, EXchess takes black";
 cout <<   "\n   black          -> black to move, EXchess takes white";
 cout <<   "\n   book           -> toggle opening book";
 cout <<   "\n   post           -> turn on display of computer thinking";
 cout <<   "\n   nopost         -> turn off display of computer thinking";
 cout <<   "\n   setboard rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -";
 cout <<   "\n                  -> setup board using EPD/FEN notation";
 cout <<   "\n                     The last two fields are castling rights and";
 cout <<   "\n                      the en-passant square, if possible. If";
 cout <<   "\n                      either is not, use a '-' instead.";
 cout <<   "\n   level 40 5 0   -> set level of play:";
 cout <<   "\n                       1st number is the number of move till time control";
 cout <<   "\n                       2nd number is the base time control in minutes";
 cout <<   "\n                       3rd number is the increment in seconds";
 cout <<   "\n   takeback       -> takeback last move";
 cout <<   "\n------------ Enter 'n' for remaining commands: ";
 cin >> ch;
 if(ch == 'n') {
  cout <<   "\n   hint           -> get a hint from the program";
  cout <<   "\n   testsuite      -> run a testsuite";
  cout <<   "\n   display        -> display the board";
  cout <<   "\n   nodisplay      -> turn off board display";
  cout <<   "\n   list           -> list the legal moves";
  cout <<   "\n   clist          -> list the legal captures";
  cout <<   "\n   score          -> score the current position";
  cout <<   "\n   analyze        -> enter analysis mode";
  cout <<   "\n   exit           -> exit analysis mode";
  cout <<   "\n   ponder         -> toggle pondering";
  cout <<   "\n   hash n         -> set hash table size to n Mbytes";
  cout <<   "\n   build          -> build a new opening book from a pgn file";
  cout <<   "\n   edit_book      -> directly edit the current opening book";
 }
 cout << "\n\n";
}

/* Function to print the possible moves to the screen */
// Useful for debugging
void type_moves()
{
  int j = 0;   // dummy count variable to determine when to
               // send a newline character
  char mstring[10]; // character string for the move

  for(int i = 0; i < game.movelist.count; i++) {
      game.temp = game.pos;
      // if it is legal, print it!
      if(game.temp.exec_move(game.movelist.mv[i].m, 0)) {
         if(!(j%6) && j) cout << "\n";    // newline if we have printed
                                          // 6 moves on a line
         else if(j) cout << ", ";         // comma to separate moves
         print_move(game.pos, game.movelist.mv[i].m, mstring); // print the move
                                                            // to the string
         cout << mstring;
         j++;                              // increment printed moves variable
      }
  }
  cout << "\n";
}

/* Function to print out the possible captures to the screen */
// Useful for debugging
void type_capts()
{
  int j = 0;              // dummy variable for counting printed moves
  char mstring[10];       // character string to hold move
  move_list clist;        // capture list

  game.pos.captures(&clist, -10000);
  for(int i = 0; i < clist.count; i++) {
      game.temp = game.pos;
      // if it is legal, print it!
      if(game.temp.exec_move(clist.mv[i].m, 0)) {
         if(!(j%6) && j) cout << "\n";    // newline if we have printed
                                          // 6 moves on a line
         else if(j) cout << ", ";         // comma to separate moves
         print_move(game.pos, clist.mv[i].m, mstring); // print the move
                                                            // to the string
         cout << mstring;
         j++;                              // increment printed moves variable
      }
  }
  cout << "\n";
}

/* Function to parse the command from the user */
// Some of these commands are xboard/winboard specific

void parse_command()
{
  char inboard[256], ms, castle[5], ep[3], basestring[12];
  char outstring[400];
  char * options;
  char line[256];
  int rating1, rating2, Mbytes, fsq, tsq, protN;

  command_parse = 0;

  // if the command is an instruction
  if(!strcmp(response, "level"))
   { cin >> game.mttc >> basestring >> game.inc; game.base = float(atof(basestring)*60.0);
     game.omttc = game.mttc; game.timeleft[0] = game.base*100; game.timeleft[1] = game.base*100; }
  else if(!strcmp(response, "time")) { cin >> game.timeleft[game.p_side^1]; }
  else if(!strcmp(response, "otim")) { cin >> game.timeleft[game.p_side];}
  else if(!strcmp(response, "display") && !xboard)
   { display_board = 1; drawboard(); }
  else if(!strcmp(response, "nodisplay") && !xboard)
   { display_board = 0; }
  else if(!strcmp(response, "force")) { game.both = 1; }
  else if(!strcmp(response, "black"))
   { game.pos.wtm = 0; game.p_side = 0; game.both = 0;
     game.pos.gen_code();
     game.pos.in_check(); }
  else if(!strcmp(response, "white"))
   { game.pos.wtm = 1; game.p_side = 1; game.both = 0;
     game.pos.gen_code();
     game.pos.in_check(); }
  else if(!strcmp(response, "go"))
   { game.p_side = game.pos.wtm^1; game.both = 0; game.ts.analysis_mode = 0; }
  else if(!strcmp(response, "playother"))
   { game.p_side = game.pos.wtm; game.both = 0; game.ts.analysis_mode = 0; }
  else if(!strcmp(response, "edit")) { board_edit(); }
  else if(!strcmp(response, "testsuite") && !xboard) { game.test_suite("wac.epd","wac.ans",0); }
  else if(!strcmp(response, "analyze")) { 
  post = 1; 
  game.learn_bk = 0; 
  game.ts.analysis_mode = 1; 
  analyze_mode = true;
  game.book = 0; 
  game.both = 1;
     if(!xboard) cout << "Analysis mode: Enter commands/moves as ready.\n\n"; }
  else if(!strcmp(response, "exit"))
   { cout << "Analysis mode: off\n"; game.ts.analysis_mode = 0; 
  analyze_mode = false;
  }
  else if(!strcmp(response, "new"))
   { if(!game.ts.analysis_mode) { game.both = 0; game.book = 1; game.learn_bk = BOOK_LEARNING; }
     game.ts.no_book = 0;
     game.ts.max_search_depth = MAXD;
     game.ts.max_search_time = MAXT;
     game.td_learning = SCORE_LEARNING;
     game.setboard(i_pos, 'w', "KQkq", "-"); 
  }
  else if(!strcmp(response, "remove"))
   { takeback(2); }
  else if(!strcmp(response, "takeback") && !xboard)
   { takeback(2); }
  else if(!strcmp(response, "undo")) { takeback(1); }
  else if(!strcmp(response, "sd")) { cin >> game.ts.max_search_depth; }
  else if(!strcmp(response, "st")) { cin >> game.ts.max_search_time; }
  else if(!strcmp(response, "bk") || !strcmp(response, "book"))
   { if(game.book) { game.book = 0; cout << " Book off\n\n"; }
     else { game.book = 1; cout << " Book on\n\n"; } }
  else if(!strcmp(response, "hint")) { hintflag = 1; }
  else if(!strcmp(response, "edit_book") && !xboard) {
   edit_book(game.pos.hcode, &game.pos);
  }
  else if(!strcmp(response, "shout")) { shout_book = 1; }
  else if(!strcmp(response, "post")) { post = 1; }
  else if(!strcmp(response, "swap") && !xboard) { 
    cin >> fsq >> tsq;  
    cout << swap(tsq,game.pos,game.pos.wtm,fsq) << "\n"; 
  }
  else if(!strcmp(response, "xboard")) { 
    /* only do something if xboard mode is not already set */
    if(!xboard) xboard = 1; 
    cout << "feature done=0\n";
  }    
  else if(!strcmp(response, "protover")) {
    cin >> protN;
    if(protN > 1) {
      cout << "feature setboard=1\n";
      cout << "feature playother=1\n";
      cout << "feature usermove=1\n";
      cout << "feature ics=1\n";
      cout << "feature reuse=0\n";  //  needed for 'auto analysis' in Arena - JA
      cout << "feature myname=\"EXchess v" << VERS << VERS2 << "\"\n";
      sprintf(outstring,"feature option=\"Playing Strength -slider %i 1 100\n", game.knowledge_scale);
      cout << outstring;
      cout << "feature done=1\n";
      cout.flush();
    }
  }
  else if(!strcmp(response, "option")) { 
    cin.getline(line, 256);
    if(strstr(line, "=") != NULL) {    // Thanks to Alex Guerrero for this fix!
      options = strtok(line,"=");
      if(!strcmp(options, " Playing Strength")) {
	options = strtok(NULL,"\n");
	game.knowledge_scale = atoi(options);
      }
    }
  }

else if(!strcmp(response, "?") || !strcmp(response, ".") || !strcmp(response, "0")
		|| !strcmp(response, "1")) {
  ;
  }


  else if(!strcmp(response, "build") && !xboard) { 
    game.setboard(i_pos, 'w', "KQkq", "-");
    build_book(game.pos); 
  }
  else if(!strcmp(response, "hash") && !xboard)
   { cin >> Mbytes; set_hash_size(ABS(Mbytes));
     cout << " Hash size = " << TAB_SIZE << " entries, "
          << TAB_SIZE*sizeof(hash_rec) << " bytes\n";
     cout << " Pawn size = " << PAWN_SIZE << " entries, "
          << PAWN_SIZE*sizeof(pawn_rec) << " bytes\n\n"; }
  //else if(!strcmp(response, "sum") || !strcmp(response, "ics"))
  // { ics = 1; if(!xboard) cout << " Search summary is on\n\n"; }
  else if(!strcmp(response, "ponder") && !xboard)
   { if(ponder_flag) { ponder_flag = 0; cout << " Pondering off\n\n"; }
     else { ponder_flag = 1; cout << " Pondering on\n\n"; } }
  else if(!strcmp(response, "easy")) // pondering off in xboard/winboard
   { ponder_flag = 0; }
  else if(!strcmp(response, "hard")) // pondering on in xboard/winboard
   { ponder_flag = 1; }
  else if(!strcmp(response, "list") && !xboard) {  type_moves(); }
  else if(!strcmp(response, "clist") && !xboard) { type_capts(); }
  else if(!strcmp(response, "score") && !xboard)
    { game.p_side = game.pos.wtm^1;
      cout << "score = " << game.pos.score_pos(-MATE, MATE, &game) << "\n";
      cout << "material = " << game.pos.material << "\n";
      game.p_side = game.pos.wtm; }
  else if(!xboard && !strcmp(response, "help")) { help(); }
  else if(!strcmp(response, "nopost")) { post = 0; }
#if TABLEBASES
  else if(!strcmp(response, "probe") && !xboard) { cout << probe_tb(&game.pos,0) << "\n"; }
#endif
  else if((!strcmp(response, "save") || !strcmp(response, "SR")) && !xboard) { save_game(); }
  else if(!strcmp(response, "quit")) { game.over = 1; tcount = 0; }
  else if(!strcmp(response, "result")) { game.over = 1; }
  else if(!strcmp(response, "setvalue")) { 
    char par_string[50]; float par_val;
    cin >> par_string >> par_val;
    set_score_value(par_string, int(par_val*10));
  }
  else if(!strcmp(response, "performance") && !xboard) { performance(); }
  else if(!strcmp(response, "name")) 
    { cin.getline(line, 256); if(logging) logfile << "--> Opponent: " << line << "\n"; }
  else if(!strcmp(response, "ics")) 
    { ics = 1; cin.getline(line, 256); if(logging) logfile << "--> ICS Host: " << line << "\n"; }
  else if(!strcmp(response, "rating")) 
    { cin >> rating1 >> rating2; 
      if(logging) logfile << "--> My rating  : " << rating1 << "\n"
                          << "--> Opp. rating: " << rating2 << "\n"; }
  else if(!strcmp(response, "setboard"))
   { cin >> inboard >> ms >> castle >> ep; game.setboard(inboard, ms, castle, ep); }
  else if(!strcmp(response, "accepted")) { cin.getline(line, 256); }  // ignore accepted command
  else if(!strcmp(response, "rejected")) { cin.getline(line, 256); }  // ignore rejected command
  // if command is a move
  else if(!strcmp(response, "usermove")) { 
    cin >> response; 
    game.best = parse_move(game.pos, response);
    if(game.best.t) { make_move(); game.T++; }
    else { 
      cout << "Illegal move: " << response << "\n"; 
      cin.getline(line, 256);
    }
    cout.flush();
  } 
  else { 
    game.best = parse_move(game.pos, response);
    if(game.best.t) { make_move(); game.T++; }    
    else { 
      cout << "Error (unknown command): " << response << "\n"; 
      cin.getline(line, 256);
    }
    cout.flush();
  }
}

// Function to run a perfomance test on generating and making move
void performance()
{
 position perf_pos = game.pos;
 move_list perf_list;
 int gen_count = 0;
 int start_time = GetTime();
 int loop = 0, perfi;

 while(1) {
  perf_pos.allmoves(&perf_list, &game.ts);   
  gen_count += perf_list.count;
  loop++; if(loop > 1000) { loop = 0; if(GetTime()-start_time > 500) break; }
 }

 cout << "Generated " << gen_count << " moves in " << float(GetTime()-start_time)/100 << " seconds\n";

 loop = 0; start_time = GetTime(); gen_count = 0;

 while(1) {
  perf_pos.allmoves(&perf_list, &game.ts);   
  gen_count += perf_list.count;
  for(perfi = 0; perfi < perf_list.count; perfi++) {
   game.temp = perf_pos;
   game.temp.exec_move(perf_list.mv[perfi].m, 0);
  }   
  loop++; if(loop > 1000) { loop = 0; if(GetTime()-start_time > 500) break; }
 }

 cout << "Generated/Made/Unmade " << gen_count << " moves in " << float(GetTime()-start_time)/100 << " seconds\n";
}

// Function to run a test suite.  The following variables are
// designed to work with the search_display function to determine
// when the best move was first found and held on to.

void game_rec::test_suite(const char *testfile, const char *resfile, int testtime)
{
  char testpos[256], ms, bookm[256], h1[5], h2[3], h4[256], id[256];
  char reply = 'n';
  char mstring[10];
  char filein[60], fileout[60];
  int cst[4], inter = 0, correct = 0, total = 0, dtotal = 0;
  int e, wac = 0, stime[300], bmexit;
  float total_time_sq = 0, total_depth = 0;
  unsigned int nodes = 0, test_time = 0;

  ts.bmcount = 0; ts.tsuite = 1;
  learn_bk = 0;
  // turn off opening book and turn on search posting
  book = 0; post = 1; 


  if(!testtime) {
   cout << "\nEnter file name for test suite in EPD format: ";
   cin >> filein; testfile = &filein[0];

   cout << "\nEnter file name for test results: ";
   cin >> fileout; resfile = &fileout[0];

   cout << "\nInteractive run? (y/n): "; cin >> reply;
   if (reply == 'y') inter = 1;
   else { cout << "\nEnter search time per move: "; cin >> testtime; }
  }

  cout << "\n--------------------*** " << testfile << " ***--------------------\n";
  if(!strcmp(testfile, "wac.epd")) wac = 1;

  ifstream infile(testfile, IOS_IN_TEXT);
  ofstream outfile(resfile);
  if (!(infile.is_open())) { cout << "\nUnable to open file. "; return; }
  if (!(outfile.is_open())) { cout << "\nUnable to open results file. "; return; }

  do
   {
    ts.soltime = -1;
    if (reply != 's') {
      for(int j = 0; j < 4; j++) { h1[j] = '*'; cst[j] = 0; }
      infile >> testpos;
      if(infile.eof() || testpos[0] == '*') {
       cout << "\nNo more test positions.\n";
       break;
      }
      infile >> ms >> h1 >> h2 >> ts.bmtype;
      ts.bmcount = 0;
      setboard(testpos, ms, h1, h2);

      do {
       infile >> bookm;
       bmexit = 0;
       for(int d = 0; d < sizeof(bookm); d++) {
        if(bookm[d] == '\0') break;
        if(bookm[d] == ';')
         { bookm[d] = '\0'; bmexit = 1; break; }
       }
       ts.bmoves[ts.bmcount] = parse_move(pos, bookm);
       ts.bmcount++;
      } while(!bmexit && ts.bmcount < sizeof(ts.bmoves)/sizeof(ts.bmoves[0]));

      infile >> h4;
      infile.getline(id,sizeof(id));

      p_side = pos.wtm;

      if(inter) drawboard(); else cout << "\n";
      if (ms == 'w') { cout << "\nWhite to Move"; } else { cout << "\nBlack to Move"; }

      cout << "  Book Move(s):";
      for(e = 0; e < ts.bmcount; e++) {
       print_move(pos, ts.bmoves[e], mstring);
       cout  << " " << mstring;
       if(e < (ts.bmcount-1)) cout << ",";
      }

      cout << "\n  Test Position: " << id << "\b ";

      if (inter) {
        cout << "\n\nPress 's' to search, 'n' for the next position, 'q' to exit: ";
        cin >> reply;
        if(reply == 'n') continue;
        if(reply == 'q') break;
        cout << "Please enter a search time (in seconds): ";
        cin >> testtime;
      }
    }

    if(!inter) cout << "\n";

    ts.best_depth = 0;
    p_side = pos.wtm^1;
    best = ts.search(pos, testtime*100, 1, &game);
    p_side = pos.wtm;

    nodes += ts.node_count; test_time += GetTime() - ts.start_time;
 
    for(e = 0; e < ts.bmcount; e++) {
     if(best.t == ts.bmoves[e].t && ts.bmtype[0] == 'b')
     { correct++; if(ts.soltime < 0) ts.soltime = 0; break; }
	 if(best.t == ts.bmoves[e].t && ts.bmtype[0] == 'a') { break; }
	 if(e == ts.bmcount-1 && ts.bmtype[0] == 'a') 
     { correct++; if(ts.soltime < 0) ts.soltime = 0; break; } 
	}
    total++; 

    if(ts.best_score < (MATE>>1)) { 
      dtotal++;
      total_depth += ts.best_depth;
    }

    print_move(pos, best, mstring);
    print_move(pos, ts.bmoves[0], bookm);

    cout << "\nSearched Move: " << mstring << "\n";
    cout << "Right = " << correct << "/" << total;
    cout << " Stime = " << setprecision(3) << ts.soltime;
    cout << " Total NPS = " << int((nodes)/(float(test_time)/100));

    cout.flush();

    if(ts.soltime > -1) total_time_sq += ts.soltime*ts.soltime;
    if(wac) stime[total-1] = int(ts.soltime);

    if(correct)
     { cout << " <time_sq> = "
            << setprecision(3) << float(total_time_sq)/float(correct); }

    if(total_depth)
     cout << " <depth> = " << float(total_depth)/float(dtotal);

    outfile << "\n" << id << " Smove: " << mstring;
    outfile << " Stime = " << ts.soltime;
    outfile << " Right = " << correct << "/" << total;
    outfile << " Total NPS = " << int((nodes)/(float(test_time)/100));
    if(correct)
     { outfile << " <time_sq> = "
              << setprecision(3) << float(total_time_sq)/float(correct); }
    if(total_depth)
     outfile << " <depth> = " << float(total_depth)/float(dtotal);

    if (inter) {
      cout << "\n\nPress 's' to search again, 'n' for the next position, 'q' to exit: ";
      cin >> reply;
    }

   } while (reply != 'q');

  if(wac && total >= 300) {
    cout << "           0    20    40    60    80   100   120   140   160   180   200   220   240   260   280\n";
    cout << "      -------------------------------------------------------------------------------------------\n";
    for(e = 1; e <= 20 ; e++) {
      cout << setw(4) << e << " |" 
           << setw(6) << stime[e-1] 
           << setw(6) << stime[20+e-1]
           << setw(6) << stime[40+e-1] 
           << setw(6) << stime[60+e-1] 
           << setw(6) << stime[80+e-1] 
           << setw(6) << stime[100+e-1] 
           << setw(6) << stime[120+e-1] 
           << setw(6) << stime[140+e-1] 
           << setw(6) << stime[160+e-1] 
           << setw(6) << stime[180+e-1]
           << setw(6) << stime[200+e-1] 
           << setw(6) << stime[220+e-1] 
           << setw(6) << stime[240+e-1] 
           << setw(6) << stime[260+e-1] 
           << setw(6) << stime[280+e-1] << "\n";      
    }
    cout << "\n";
    outfile << "\n           0    20    40    60    80   100   120   140   160   180   200   220   240   260   280\n";
    outfile << "      -------------------------------------------------------------------------------------------\n";
    for(e = 1; e <= 20 ; e++) {
      outfile << setw(4) << e << " |" 
           << setw(6) << stime[e-1] 
           << setw(6) << stime[20+e-1]
           << setw(6) << stime[40+e-1] 
           << setw(6) << stime[60+e-1] 
           << setw(6) << stime[80+e-1] 
           << setw(6) << stime[100+e-1] 
           << setw(6) << stime[120+e-1] 
           << setw(6) << stime[140+e-1] 
           << setw(6) << stime[160+e-1] 
           << setw(6) << stime[180+e-1]
           << setw(6) << stime[200+e-1] 
           << setw(6) << stime[220+e-1] 
           << setw(6) << stime[240+e-1] 
           << setw(6) << stime[260+e-1] 
           << setw(6) << stime[280+e-1] << "\n";      
    }
    outfile << "\n";
  }

  outfile.close();
  infile.close();
  ts.tsuite = 0;
  return;
}

// Save game function to save the game to a text file
void save_game()
{
  int TURN; TURN = game.T;
  char gname[] = "lastgame.gam";
  char resp, mstring[10];
  char Event[30], White[30], Black[30], Date[30], result[30];

  cout << "\nFile Name : ";
  cin >> gname;
  cout << "Custom Header? (y/n): ";
  cin >> resp;

  if(resp == 'y' || resp == 'Y')
  {
    cout << "Event: ";  cin >> Event;
    cout << "Date: "; cin >> Date;
    cout << "White: ";  cin >> White;
    cout << "Black: ";  cin >> Black;
  } else {
    strcpy(Event, "Chess Match");
    strcpy(Date, "??.??.????");
    if (game.p_side)
     { strcpy(White, "Human"); strcpy(Black, "EXchess"); }
    else
     { strcpy(White, "EXchess"); strcpy(Black, "Human"); }
  }

  ofstream outfile(gname);

  outfile <<   "[Event: " << Event << " ]";
  outfile << "\n[Date: " << Date << " ]";
  outfile << "\n[White: " << White << " ]";
  outfile << "\n[Black: " << Black << " ]";

  // set the result string
  switch (game.pos.in_check_mate())
   {
    case 0:
     if(game.pos.fifty >= 100)
      { strcpy(result, " 1/2-1/2 {50 moves}"); }
     else strcpy(result, " adjourned");
      break;
    case 1:
     if(!game.pos.wtm) strcpy(result, " 1-0 {White Mates}");
     else strcpy(result, " 0-1 {Black Mates}");
     break;
    case 2:
     strcpy(result, " 1/2-1/2 {Stalemate}");
   }

  outfile << "\n[Result: " << result << " ]\n\n";

  // set the board up from the starting position
  game.setboard(i_pos, 'w', "KQkq", "-");

  // play through the game and record the moves in a file
  for(int i = 1; i < TURN; i++)
   {
    print_move(game.pos, game.game_history[i-1], mstring);
    if (game.pos.wtm) outfile << (ceil((double)i/2) + 1) << ". " << mstring;
    else outfile << mstring;
    outfile << " ";
    if(!(game.T%8)) outfile << "\n";
    game.pos.exec_move(game.game_history[i-1], 0);
    game.T++;
   }

   outfile << result;

}


/* Function to write search output */
// very simple and self-explanatory
void tree_search::search_display(int score)
{
 char outstring[400], mstring[10];
 position p = n[0].pos;

 int total_time = GetTime()-start_time;

 if(!xboard) {
  if(fail == 1) { cout << setw(3) << max_ply << ".   ++   ";  }
  if(fail == -1) { cout << setw(3) << max_ply << ".   --   \n"; return; }

  if(score < MATE/2 && score > -MATE/2) {
   sprintf(outstring, " %2i.  %5.2f ", max_ply, float(score)/value[PAWN]);
  } else if (score >= MATE/2) {
   sprintf(outstring, " %2i.  MATE+ ", max_ply);
  } else {
   sprintf(outstring, " %2i.  MATE- ", max_ply);
  }
  if(!fail) cout << outstring;
  sprintf(outstring, " %4i %8d  ", int(total_time)/100, node_count);
  cout << outstring;
 } else {
  if (fail == 1) {cout << "++\n"; return; }
  if (fail == -1) {cout << "--\n"; return; } 

  sprintf(outstring, "  %2i  %5i ", max_ply, int(float(score*100)/value[PAWN]));
  cout << outstring;
  sprintf(outstring, "%7i %6d ", int(total_time), node_count);
  cout << outstring;
 }

 int j = 0;
 if(!p.wtm && pc[0][0].t) {
  cout << " 1. ...";
  j++;
 }

 for (int i = 0; i < MAXD && j < MAXD; i++, j++)
 {
   if (!(pc[0][i].t)) break;
   print_move(p, pc[0][i], mstring);
   if(!p.exec_move(pc[0][i],0)) break;
   if(!(j&1)) cout << " " << (j/2 + 1) << ".";
   cout << " " << mstring;
 }
 cout << "\n";
 cout.flush();

 if(tsuite) {
  int correct = 0;
  for(int e = 0; e < bmcount; e++) {
   if(pc[0][0].t == bmoves[e].t && bmtype[0] == 'b') { correct = 1; break; }
   if(pc[0][0].t == bmoves[e].t && bmtype[0] == 'a') { break; }
   if(e == bmcount-1 && bmtype[0] == 'a') { correct = 1; }
  }
  if(!correct) soltime = -1;
  if(correct && soltime == -1) soltime = float(total_time)/100;
  best_score = score;
 }

}

#if FLTK_GUI

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
//#include <FL/Fl_Bitmap.H>
//#include <FL/fl_draw.H>
//#include <FL/Fl_Menu_Item.H>
//#include <FL/fl_ask.H>

#endif

//-----------------------------------------------------------------------------------
// Function returns a 1 if a pondering session should be interrupted
int inter()
{
#if FLTK_GUI
  Fl::check();
  if(abortflag) { abortflag = 0; return 1; } else { return 0; }
#endif
 
 if(!game.ts.ponder && !game.ts.analysis_mode && !xboard && !input_test) return 0;

 if(cin.rdbuf() -> in_avail() > 1) return 1;


#if MSVC || MINGW
 static int init = 0, pipe;
 static HANDLE inh;
 DWORD dw;
 if(xboard) {     // winboard interrupt code taken from crafty
  if (!init) {
       init = 1;
       inh = GetStdHandle(STD_INPUT_HANDLE);
       pipe = !GetConsoleMode(inh, &dw);
       if (!pipe) {
         SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT|ENABLE_WINDOW_INPUT));
         FlushConsoleInputBuffer(inh);
         FlushConsoleInputBuffer(inh);
       }
     }
  if(pipe) {
    if(!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL)) return 1;
    return dw;
  } else {
    GetNumberOfConsoleInputEvents(inh, &dw);
    return dw <= 1 ? 0 : dw;
  }
 }
 if(kbhit()) return 1; else return 0;

#else // unix

FD_ZERO(&read_fds);
 FD_SET(0,&read_fds);
 timeout.tv_sec = timeout.tv_usec = 0;
 select(1,&read_fds,NULL,NULL,&timeout);
 if((game.ts.ponder || game.ts.analysis_mode) && FD_ISSET(0,&read_fds)) return 1;
 else return 0;

#endif
}


/* Function to log search output to a file */
// very simple and self-explanatory
void tree_search::log_search(int score)
{
 char outstring[400], mstring[10];
 position p = n[0].pos;

 int total_time = GetTime()-start_time;

 if(fail == 1) { 
   sprintf(outstring, "%3i.   ++   ", max_ply); 
   write_out(outstring);  
 }
 if(fail == -1) { 
   sprintf(outstring, "%3i.   --   \n", max_ply); 
   write_out(outstring);  
   return;
 }
 
 if(score < MATE/2 && score > -MATE/2) {
   sprintf(outstring, " %2i.  %5.2f ", max_ply, float(score)/value[PAWN]);
 } else if (score >= MATE/2) {
   sprintf(outstring, " %2i.  MATE+ ", max_ply);
 } else {
   sprintf(outstring, " %2i.  MATE- ", max_ply);
 }
 if(!fail) { 
   write_out(outstring);
 }
 sprintf(outstring, " %4i %8d  ", int(total_time)/100, node_count);
 write_out(outstring);
  
 int j = 0;
 if(!p.wtm && pc[0][0].t) {
  sprintf(outstring, " 1. ...");
  write_out(outstring);
  j++;
 }

 for (int i = 0; i < MAXD && j < MAXD; i++, j++)
 {
   if (!(pc[0][i].t)) break;
   print_move(p, pc[0][i], mstring);
   if(!p.exec_move(pc[0][i],0)) break;
   if(!(j&1)) {
     sprintf(outstring, " %i. %s", (j/2+1), mstring); 
     write_out(outstring);
   } else {
     sprintf(outstring, " %s", mstring); 
     write_out(outstring);   
   }
 }
 sprintf(outstring, "\n");
 write_out(outstring);   
 if(total_time >= 300) logfile.flush();
}

// ------------ function to write stuff to logfile or to search posting buffer 
//
void write_out(const char *outline) {
  if(logging) logfile << outline;
#if FLTK_GUI
  if(FLTK_post) { 
   searchout_buffer->append(outline);
   searchout->move_down();
   searchout->show_insert_position();
  }
#endif
}












