Subversion Repositories Games.Chess Giants

Rev

Rev 116 | Rev 130 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 116 Rev 119
Line 24... Line 24...
24
bool PlayerEngine_Init (player_t *player)
24
bool PlayerEngine_Init (player_t *player)
25
{
25
{
26
   // this function starts a chess engine as a child process. This process's stdin and
26
   // this function starts a chess engine as a child process. This process's stdin and
27
   // stdout are redirected to the handles we give it, so that we may read/write to it.
27
   // stdout are redirected to the handles we give it, so that we may read/write to it.
28
 
28
 
-
 
29
   engineprogram_t *program;
29
   wchar_t widechar_buffer[256];
30
   wchar_t widechar_buffer[256];
30
   SYSTEM_INFO sysinfo;
31
   SYSTEM_INFO sysinfo;
31
   SECURITY_ATTRIBUTES saAttr;
32
   SECURITY_ATTRIBUTES saAttr;
32
   STARTUPINFO si;
33
   STARTUPINFO si;
33
   int try_index;
34
   int try_index;
Line 38... Line 39...
38
   hChessEngineStdinWr = NULL;
39
   hChessEngineStdinWr = NULL;
39
   hChessEngineStdoutRd = NULL;
40
   hChessEngineStdoutRd = NULL;
40
   hChessEngineStdoutWr = NULL;
41
   hChessEngineStdoutWr = NULL;
41
   player->wants_hint = false;
42
   player->wants_hint = false;
42
 
43
 
43
   // load the selected engine parameters
44
   // quick access to engine program
44
   Config_LoadEngine (options.engine.program);
45
   program = &options.engine.programs[options.engine.selected_program];
45
 
46
 
46
   // build the chess engine module path and pathname
47
   // build the chess engine module path and pathname
47
   swprintf_s (chessenginemodule_path, WCHAR_SIZEOF (chessenginemodule_path), L"%s/engines/%s", app_path, options.engine.program);
48
   swprintf_s (chessenginemodule_path, WCHAR_SIZEOF (chessenginemodule_path), L"%s/engines/%s", app_path, program->folder);
48
   swprintf_s (chessenginemodule_pathname, WCHAR_SIZEOF (chessenginemodule_pathname), L"%s/engines/%s/%s", app_path, options.engine.program, options.engine.program_options.cmdline);
49
   swprintf_s (chessenginemodule_pathname, WCHAR_SIZEOF (chessenginemodule_pathname), L"%s/engines/%s/%s", app_path, program->folder, program->cmdline);
49
 
50
 
50
   // prepare the pipes' security attributes
51
   // prepare the pipes' security attributes
51
   memset (&saAttr, 0, sizeof (saAttr));
52
   memset (&saAttr, 0, sizeof (saAttr));
52
   saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);
53
   saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);
53
   saAttr.bInheritHandle = true; // set the bInheritHandle flag so pipe handles are inherited
54
   saAttr.bInheritHandle = true; // set the bInheritHandle flag so pipe handles are inherited
Line 66... Line 67...
66
   si.dwFlags = STARTF_USESTDHANDLES;
67
   si.dwFlags = STARTF_USESTDHANDLES;
67
   si.hStdInput = hChessEngineStdinRd;
68
   si.hStdInput = hChessEngineStdinRd;
68
   si.hStdOutput = hChessEngineStdoutWr;
69
   si.hStdOutput = hChessEngineStdoutWr;
69
   si.hStdError = hChessEngineStdoutWr;
70
   si.hStdError = hChessEngineStdoutWr;
70
   if (!CreateProcess (chessenginemodule_pathname, // module pathname
71
   if (!CreateProcess (chessenginemodule_pathname, // module pathname
71
                       options.engine.program_options.cmdline, // command line
72
                       program->cmdline, // command line
72
                       NULL, NULL,
73
                       NULL, NULL,
73
                       true, // handles are inherited
74
                       true, // handles are inherited
74
                       CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
75
                       CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
75
                       NULL,
76
                       NULL,
76
                       chessenginemodule_path, // process path
77
                       chessenginemodule_path, // process path
Line 100... Line 101...
100
   // has the engine process not spoken yet ?
101
   // has the engine process not spoken yet ?
101
   if (player->recvbuffer[0] == 0)
102
   if (player->recvbuffer[0] == 0)
102
   {
103
   {
103
      messagebox.hWndParent = hMainWnd;
104
      messagebox.hWndParent = hMainWnd;
104
      wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
105
      wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
105
      wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_ChessEngineInitializationFailed"));
106
      swprintf_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_ChessEngineInitializationFailed"), program->folder);
106
      messagebox.flags = MB_ICONWARNING | MB_OK;
107
      messagebox.flags = MB_ICONWARNING | MB_OK;
107
      DialogBox_Message (&messagebox); // display a modeless error message box
108
      DialogBox_Message (&messagebox); // display a modeless error message box
108
 
109
 
109
      PlayerEngine_Shutdown (player); // on error, shutdown the engine
110
      PlayerEngine_Shutdown (player); // on error, shutdown the engine
110
      return (false);
111
      return (false);
Line 112... Line 113...
112
 
113
 
113
   // eventually initialize the debug log file
114
   // eventually initialize the debug log file
114
   Debug_Init (L"Chess engine output.txt");
115
   Debug_Init (L"Chess engine output.txt");
115
 
116
 
116
   // build the init file full qualified path name and try to open it
117
   // build the init file full qualified path name and try to open it
117
   swprintf_s (chessengineinitfile_pathname, WCHAR_SIZEOF (chessengineinitfile_pathname), L"%s/engines/%s/init.txt", app_path, options.engine.program);
118
   swprintf_s (chessengineinitfile_pathname, WCHAR_SIZEOF (chessengineinitfile_pathname), L"%s/engines/%s/init.txt", app_path, program->folder);
118
   _wfopen_s (&fp, chessengineinitfile_pathname, L"r");
119
   _wfopen_s (&fp, chessengineinitfile_pathname, L"r");
119
 
120
 
120
   // could the init file be opened ?
121
   // could the init file be opened ?
121
   if (fp != NULL)
122
   if (fp != NULL)
122
   {
123
   {
Line 139... Line 140...
139
 
140
 
140
      fclose (fp); // finished, close the file
141
      fclose (fp); // finished, close the file
141
   }
142
   }
142
 
143
 
143
   // everything's okay, set engine name as the player's name
144
   // everything's okay, set engine name as the player's name
144
   wcscpy_s (player->name, WCHAR_SIZEOF (player->name), options.engine.program_options.name);
145
   wcscpy_s (player->name, WCHAR_SIZEOF (player->name), program->name);
145
 
146
 
146
   return (true); // finished
147
   return (true); // finished
147
}
148
}
148
 
149
 
149
 
150
 
Line 154... Line 155...
154
   unsigned long exit_code;
155
   unsigned long exit_code;
155
   unsigned long handle_flags;
156
   unsigned long handle_flags;
156
   int attempt_index;
157
   int attempt_index;
157
 
158
 
158
   // send the engine a quit command
159
   // send the engine a quit command
159
   Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_quit);
160
   Player_SendBuffer_Add (player, 1000, options.engine.programs[options.engine.selected_program].command_quit);
160
   Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
161
   Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
161
   PlayerEngine_Send (player);
162
   PlayerEngine_Send (player);
162
 
163
 
163
   // close the pipe handles
164
   // close the pipe handles
164
   if (hChessEngineStdinRd)
165
   if (hChessEngineStdinRd)
Line 211... Line 212...
211
 
212
 
212
bool PlayerEngine_Think (player_t *player)
213
bool PlayerEngine_Think (player_t *player)
213
{
214
{
214
   // this function reads and writes any necessary data from and to the chess engine. Returns TRUE if scene needs to be updated.
215
   // this function reads and writes any necessary data from and to the chess engine. Returns TRUE if scene needs to be updated.
215
 
216
 
-
 
217
   engineprogram_t *program;
216
   wchar_t line_buffer[256];
218
   wchar_t line_buffer[256];
217
   wchar_t *line_pointer;
219
   wchar_t *line_pointer;
218
   wchar_t *move_string;
220
   wchar_t *move_string;
219
   int char_index;
221
   int char_index;
220
   int length;
222
   int length;
221
   boardmove_t move;
223
   boardmove_t move;
222
   player_t *current_player;
224
   player_t *current_player;
223
   player_t *opposite_player;
225
   player_t *opposite_player;
224
   bool do_update;
226
   bool do_update;
-
 
227
 
-
 
228
   // quick access to chess engine program
-
 
229
   program = &options.engine.programs[options.engine.selected_program];
225
 
230
 
226
   // don't update the scene until told otherwise
231
   // don't update the scene until told otherwise
227
   do_update = false;
232
   do_update = false;
228
 
233
 
229
   // get current and opposite players
234
   // get current and opposite players
Line 331... Line 336...
331
      // has the game ended already ?
336
      // has the game ended already ?
332
      if (the_board.game_state > STATE_PLAYING)
337
      if (the_board.game_state > STATE_PLAYING)
333
         continue; // ignore all that the engine tells us. Game is over already.
338
         continue; // ignore all that the engine tells us. Game is over already.
334
 
339
 
335
      // else is it a normal move ?
340
      // else is it a normal move ?
336
      else if ((move_string = wcsstr (line_buffer, options.engine.program_options.replystring_move)) != NULL)
341
      else if ((move_string = wcsstr (line_buffer, program->replystring_move)) != NULL)
337
         move_string += wcslen (options.engine.program_options.replystring_move); // go to the parsable data
342
         move_string += wcslen (program->replystring_move); // go to the parsable data
338
 
343
 
339
      // else it's any other sort of line
344
      // else it's any other sort of line
340
      else
345
      else
341
         continue; // skip lines that don't contain any valid move data
346
         continue; // skip lines that don't contain any valid move data
342
 
347
 
Line 359... Line 364...
359
 
364
 
360
      // is it NOT a hint, are blunders allowed, should we do one now AND can we do one now ?
365
      // is it NOT a hint, are blunders allowed, should we do one now AND can we do one now ?
361
      if (!is_hint_pending && (options.engine.blunder_chances > 0) && (rand () % 100 < options.engine.blunder_chances)
366
      if (!is_hint_pending && (options.engine.blunder_chances > 0) && (rand () % 100 < options.engine.blunder_chances)
362
          && Move_FindRandomMove (&the_board.moves[the_board.move_count - 1], player->color, &move))
367
          && Move_FindRandomMove (&the_board.moves[the_board.move_count - 1], player->color, &move))
363
      {
368
      {
364
         Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_force, Move_BuildString (&move)); // send the blunderous move to the engine
369
         Player_SendBuffer_Add (player, 1000, program->command_force, Move_BuildString (&move)); // send the blunderous move to the engine
365
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
370
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
366
         if (wcscmp (options.engine.program, L"Crafty") == 0)
371
         if (_wcsnicmp (program->name, L"Crafty", 6) == 0)
367
            Player_SendBuffer_Add (player, 1000, L"disp\n");
372
            Player_SendBuffer_Add (player, 1000, L"disp\n");
368
         Debug_Log (L"===Discarding engine move, forcing a blunderous move (%s) instead===\n", Move_BuildString (&move)); // blunder
373
         Debug_Log (L"===Discarding engine move, forcing a blunderous move (%s) instead===\n", Move_BuildString (&move)); // blunder
369
      }
374
      }
370
 
375
 
371
      // mark the engine's selected and hovered squares
376
      // mark the engine's selected and hovered squares
Line 399... Line 404...
399
         Debug_Log (L"===Hint received, rebuilding board and telling engine to backup 1 move===\n");
404
         Debug_Log (L"===Hint received, rebuilding board and telling engine to backup 1 move===\n");
400
         Debug_Log (L"===setting up board using FEN string===\n");
405
         Debug_Log (L"===setting up board using FEN string===\n");
401
 
406
 
402
         // instruct it about its allowed search depth BEFORE each table set (this ensures engine will be "ready" to handle the command)
407
         // instruct it about its allowed search depth BEFORE each table set (this ensures engine will be "ready" to handle the command)
403
         // then get the current game state in FEN format and feed it to the engine
408
         // then get the current game state in FEN format and feed it to the engine
404
         Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_sd, options.engine.depth);
409
         Player_SendBuffer_Add (player, 1000, program->command_sd, options.engine.depth);
405
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
410
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
406
         Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
411
         Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
407
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
412
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
408
 
413
 
409
         if (wcscmp (options.engine.program, L"Crafty") == 0)
414
         if (_wcsnicmp (program->name, L"Crafty", 6) == 0)
410
            Player_SendBuffer_Add (player, 1000, L"disp\n");
415
            Player_SendBuffer_Add (player, 1000, L"disp\n");
411
      }
416
      }
412
 
417
 
413
      do_update = true; // remember to update the 3D scene
418
      do_update = true; // remember to update the 3D scene
414
   }
419
   }
Line 434... Line 439...
434
   if (the_board.was_setup)
439
   if (the_board.was_setup)
435
   {
440
   {
436
      Debug_Log (L"===Got board setup notification from interface===\n");
441
      Debug_Log (L"===Got board setup notification from interface===\n");
437
 
442
 
438
      // send a new game command to the chess engine
443
      // send a new game command to the chess engine
439
      Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_new);
444
      Player_SendBuffer_Add (player, 1000, program->command_new);
440
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
445
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
441
 
446
 
442
      // just set up the board from its Forsyth-Edwards notation
447
      // just set up the board from its Forsyth-Edwards notation
443
      Debug_Log (L"===setting up board using FEN string===\n");
448
      Debug_Log (L"===setting up board using FEN string===\n");
444
 
449
 
445
      // instruct it about its allowed search depth BEFORE each table set (this ensures engine will be "ready" to handle the command)
450
      // instruct it about its allowed search depth BEFORE each table set (this ensures engine will be "ready" to handle the command)
446
      // then get the current game state in FEN format and feed it to the engine
451
      // then get the current game state in FEN format and feed it to the engine
447
      Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_sd, options.engine.depth);
452
      Player_SendBuffer_Add (player, 1000, program->command_sd, options.engine.depth);
448
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
453
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
449
      Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
454
      Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
450
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
455
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
451
 
456
 
452
      current_obstinacy = 0; // reset current obstinacy
457
      current_obstinacy = 0; // reset current obstinacy
453
      is_hint_pending = false; // no hint was requested so far
458
      is_hint_pending = false; // no hint was requested so far
454
 
459
 
455
      if (wcscmp (options.engine.program, L"Crafty") == 0)
460
      if (_wcsnicmp (program->name, L"Crafty", 6) == 0)
456
         Player_SendBuffer_Add (player, 1000, L"disp\n");
461
         Player_SendBuffer_Add (player, 1000, L"disp\n");
457
   }
462
   }
458
 
463
 
459
   // have we been notified that players are swapping colors ? (N.B. when this happens in human vs. computer mode, it's always that the human player is *GIVING* his turn)
464
   // have we been notified that players are swapping colors ? (N.B. when this happens in human vs. computer mode, it's always that the human player is *GIVING* his turn)
460
   if (the_board.want_playerswap)
465
   if (the_board.want_playerswap)
461
   {
466
   {
462
      Debug_Log (L"===Got player SWAP notification from interface===\n");
467
      Debug_Log (L"===Got player SWAP notification from interface===\n");
463
      Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_go); // tell engine it's now the current player
468
      Player_SendBuffer_Add (player, 1000, program->command_go); // tell engine it's now the current player
464
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
469
      Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
465
   }
470
   }
466
 
471
 
467
   // have we been notified that the current player just changed ?
472
   // have we been notified that the current player just changed ?
468
   if (the_board.has_playerchanged)
473
   if (the_board.has_playerchanged)
Line 474... Line 479...
474
      {
479
      {
475
         // is it NOT a board setup AND has at least one move been played (meaning it was just the other's turn before) ?
480
         // is it NOT a board setup AND has at least one move been played (meaning it was just the other's turn before) ?
476
         if (!the_board.was_setup && (the_board.move_count > 1))
481
         if (!the_board.was_setup && (the_board.move_count > 1))
477
         {
482
         {
478
            Debug_Log (L"===Player just played, sending the chosen move to engine===\n");
483
            Debug_Log (L"===Player just played, sending the chosen move to engine===\n");
479
            if (wcscmp (options.engine.program, L"Crafty") == 0)
484
            if (_wcsnicmp (program->name, L"Crafty", 6) == 0)
480
               Player_SendBuffer_Add (player, 1000, L"disp\n");
485
               Player_SendBuffer_Add (player, 1000, L"disp\n");
481
 
486
 
482
            // instruct it about its allowed search depth BEFORE each move (this ensures engine will be "ready" to handle the command)
487
            // instruct it about its allowed search depth BEFORE each move (this ensures engine will be "ready" to handle the command)
483
            // then build the move string, and send the move string to the engine
488
            // then build the move string, and send the move string to the engine
484
            Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_sd, options.engine.depth);
489
            Player_SendBuffer_Add (player, 1000, program->command_sd, options.engine.depth);
485
            Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
490
            Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
486
            Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_move, Move_BuildString (&the_board.moves[the_board.move_count - 1]));
491
            Player_SendBuffer_Add (player, 1000, program->command_move, Move_BuildString (&the_board.moves[the_board.move_count - 1]));
487
            Player_SendBuffer_Add (player, 1000, L"\n"); // end the send buffer with a carriage return
492
            Player_SendBuffer_Add (player, 1000, L"\n"); // end the send buffer with a carriage return
488
         }
493
         }
489
 
494
 
490
         // else game has not started yet, but it's our turn
495
         // else game has not started yet, but it's our turn
491
         else
496
         else
492
         {
497
         {
493
            Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_go); // so let's start the game
498
            Player_SendBuffer_Add (player, 1000, program->command_go); // so let's start the game
494
            Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
499
            Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
495
         }
500
         }
496
      }
501
      }
497
   }
502
   }
498
 
503
 
Line 505... Line 510...
505
      // does our opponent want a hint ?
510
      // does our opponent want a hint ?
506
      if (current_player->wants_hint)
511
      if (current_player->wants_hint)
507
      {
512
      {
508
         current_player->wants_hint = false; // don't ask twice
513
         current_player->wants_hint = false; // don't ask twice
509
         Debug_Log (L"===Hint requested, asking engine for it===\n");
514
         Debug_Log (L"===Hint requested, asking engine for it===\n");
510
         Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_go); // tell the computer to analyze this position
515
         Player_SendBuffer_Add (player, 1000, program->command_go); // tell the computer to analyze this position
511
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
516
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
512
         is_hint_pending = true; // remember a hint is pending
517
         is_hint_pending = true; // remember a hint is pending
513
 
518
 
514
         // FIXME: move to scene.cpp
519
         // FIXME: move to scene.cpp
515
         Scene_SetText (&the_scene.gui.central_text, 50.0f, 40.0f, -1, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, centermsg_fontindex, RGBA_TO_RGBACOLOR (255, 255, 255, 191),
520
         Scene_SetText (&the_scene.gui.central_text, 50.0f, 40.0f, -1, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, centermsg_fontindex, RGBA_TO_RGBACOLOR (255, 255, 255, 191),
Line 532... Line 537...
532
         // just set up the board from its Forsyth-Edwards notation
537
         // just set up the board from its Forsyth-Edwards notation
533
         Debug_Log (L"===setting up board using FEN string===\n");
538
         Debug_Log (L"===setting up board using FEN string===\n");
534
 
539
 
535
         // instruct it about its allowed search depth BEFORE each table set (this ensures engine will be "ready" to handle the command)
540
         // instruct it about its allowed search depth BEFORE each table set (this ensures engine will be "ready" to handle the command)
536
         // then get the current game state in FEN format and feed it to the engine
541
         // then get the current game state in FEN format and feed it to the engine
537
         Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_sd, options.engine.depth);
542
         Player_SendBuffer_Add (player, 1000, program->command_sd, options.engine.depth);
538
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
543
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
539
         Player_SendBuffer_Add (player, 1000, options.engine.program_options.command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
544
         Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
540
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
545
         Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
541
 
546
 
542
         if (wcscmp (options.engine.program, L"Crafty") == 0)
547
         if (_wcsnicmp (program->name, L"Crafty", 6) == 0)
543
            Player_SendBuffer_Add (player, 1000, L"disp\n");
548
            Player_SendBuffer_Add (player, 1000, L"disp\n");
544
 
549
 
545
         do_update = true; // remember to update the 3D scene
550
         do_update = true; // remember to update the 3D scene
546
      }
551
      }
547
   }
552
   }