Subversion Repositories Games.Chess Giants

Rev

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

Rev 175 Rev 177
Line 27... Line 27...
27
   engineprogram_t *program;
27
   engineprogram_t *program;
28
   wchar_t current_path[MAX_PATH];
28
   wchar_t current_path[MAX_PATH];
29
   wchar_t widechar_buffer[1024];
29
   wchar_t widechar_buffer[1024];
30
   SYSTEM_INFO sysinfo;
30
   SYSTEM_INFO sysinfo;
31
   int attempt_index;
31
   int attempt_index;
-
 
32
   int64_t exit_code;
32
   FILE *fp;
33
   FILE *fp;
33
 
34
 
34
   // reset stuff first
35
   // reset stuff first
35
   player->wants_hint = false;
36
   player->wants_hint = false;
36
 
37
 
Line 45... Line 46...
45
   GetCurrentDirectory (WCHAR_SIZEOF (current_path), current_path); // save current directory
46
   GetCurrentDirectory (WCHAR_SIZEOF (current_path), current_path); // save current directory
46
   SetCurrentDirectory (chessengine_path); // temporarily set chess engine's startup directory as current directory
47
   SetCurrentDirectory (chessengine_path); // temporarily set chess engine's startup directory as current directory
47
   fpipe = pipe_open (chessengine_shellcommand, L"r+");
48
   fpipe = pipe_open (chessengine_shellcommand, L"r+");
48
   SetCurrentDirectory (current_path); // restore current directory
49
   SetCurrentDirectory (current_path); // restore current directory
49
   for (attempt_index = 0; attempt_index < 10; attempt_index++)
50
   for (attempt_index = 0; attempt_index < 10; attempt_index++)
50
      if (!pipe_isalive (fpipe))
51
      if (!pipe_isalive (fpipe, &exit_code))
51
         Sleep (100); // wait for the pipe to come to life, stop as soon as it's alive
52
         Sleep (100); // wait for the pipe to come to life, stop as soon as it's alive
52
      else
53
      else
53
         break; // wait for the pipe to come to life
54
         break; // wait for the pipe to come to life
54
   if ((fpipe == NULL) || (attempt_index == 10))
55
   if ((fpipe == NULL) || (attempt_index == 10))
55
   {
56
   {
Line 106... Line 107...
106
void PlayerEngine_Shutdown (player_t *player)
107
void PlayerEngine_Shutdown (player_t *player)
107
{
108
{
108
   // this function terminates the chess engine process and releases all handles attached to it
109
   // this function terminates the chess engine process and releases all handles attached to it
109
 
110
 
110
   int attempt_index;
111
   int attempt_index;
-
 
112
   int64_t exit_code;
111
 
113
 
112
   // send the engine a quit command
114
   // send the engine a quit command
113
   Player_SendBuffer_Add (player, 1000, options.engine.programs[options.engine.selected_program].command_quit);
115
   Player_SendBuffer_Add (player, 1000, options.engine.programs[options.engine.selected_program].command_quit);
114
   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
116
   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
115
   PlayerEngine_Send (player);
117
   PlayerEngine_Send (player);
116
 
118
 
117
   // check 10 times if the engine process has ended cleanly
119
   // check 10 times if the engine process has ended cleanly
118
   for (attempt_index = 0; attempt_index < 10; attempt_index++)
120
   for (attempt_index = 0; attempt_index < 10; attempt_index++)
119
   {
121
   {
120
      if (!pipe_isalive (fpipe))
122
      if (!pipe_isalive (fpipe, &exit_code))
121
         break; // break as soon as we've told the process exited cleanly
123
         break; // break as soon as we've told the process exited cleanly
122
 
124
 
123
      Sleep (100); // else wait one tenth second
125
      Sleep (100); // else wait one tenth second
124
   }
126
   }
125
 
127
 
Line 137... Line 139...
137
 
139
 
138
   engineprogram_t *program;
140
   engineprogram_t *program;
139
   wchar_t line_buffer[1024];
141
   wchar_t line_buffer[1024];
140
   wchar_t *line_pointer;
142
   wchar_t *line_pointer;
141
   wchar_t *move_string;
143
   wchar_t *move_string;
-
 
144
   int64_t exit_code;
142
   int char_index;
145
   int char_index;
143
   int length;
146
   int length;
144
   boardmove_t move;
147
   boardmove_t move;
145
   player_t *current_player;
148
   player_t *current_player;
146
   player_t *opposite_player;
149
   player_t *opposite_player;
Line 155... Line 158...
155
   // get current and opposite players
158
   // get current and opposite players
156
   current_player = Player_GetCurrent ();
159
   current_player = Player_GetCurrent ();
157
   opposite_player = Player_GetOpposite ();
160
   opposite_player = Player_GetOpposite ();
158
 
161
 
159
   // is the game still alive AND has the engine just died ?
162
   // is the game still alive AND has the engine just died ?
160
   if ((the_board.game_state == STATE_PLAYING) && !pipe_isalive (fpipe))
163
   if ((the_board.game_state == STATE_PLAYING) && !pipe_isalive (fpipe, &exit_code))
161
   {
164
   {
162
      Debug_Log (L"===Unrecoverable engine error: opponent wins!===\n");
165
      Debug_Log (L"===Unrecoverable engine error (engine disappeared unexpectedly with exit code %lld): opponent wins!===\n", exit_code);
163
      dont_nag = true; // remember NOT to nag the user if he experienced any bug
166
      dont_nag = true; // remember NOT to nag the user if he experienced any bug
164
 
167
 
165
      // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board
168
      // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board
166
      Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f);
169
      Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f);
167
 
170
 
168
      // display a crash notification dialog box
171
      // display a crash notification dialog box
169
      if (MessageBox (hMainWnd, LOCALIZE (L"Error_EngineCrashed"), LOCALIZE (L"ImportantMessage"), MB_ICONWARNING | MB_YESNO) == IDYES)
172
      if (MessageBox (hMainWnd, LOCALIZE (L"Error_EngineCrashed"), LOCALIZE (L"ImportantMessage"), MB_ICONWARNING | MB_YESNO) == IDYES)
-
 
173
      {
-
 
174
         sprintf_s ((char *) line_buffer, sizeof (line_buffer), "engine disappeared unexpectedly (exit code %lld)", exit_code);
170
         if (Debug_SendLogToAuthor (true))
175
         if (Debug_SendLogToAuthor ((char *) line_buffer, true))
171
            MessageBox (hMainWnd, LOCALIZE (L"MessageSent"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK); // send the game engine history to the author
176
            MessageBox (hMainWnd, LOCALIZE (L"MessageSent"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK); // send the game engine history to the author
172
         else
177
         else
173
            MessageBox (hMainWnd, LOCALIZE (L"NoInternetConnection"), LOCALIZE (L"FatalError"), MB_ICONWARNING | MB_OK); // and display an error message if failed
178
            MessageBox (hMainWnd, LOCALIZE (L"NoInternetConnection"), LOCALIZE (L"FatalError"), MB_ICONWARNING | MB_OK); // and display an error message if failed
-
 
179
      }
174
 
180
 
175
      // and display the game over dialog box
181
      // and display the game over dialog box
176
      the_board.game_state = (opposite_player->color == COLOR_BLACK ? STATE_WHITEWIN_RESIGNORFORFEIT : STATE_BLACKWIN_RESIGNORFORFEIT);
182
      the_board.game_state = (opposite_player->color == COLOR_BLACK ? STATE_WHITEWIN_RESIGNORFORFEIT : STATE_BLACKWIN_RESIGNORFORFEIT);
177
      DialogBox_EndGame ();
183
      DialogBox_EndGame ();
178
 
184
 
Line 245... Line 251...
245
               // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board
251
               // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board
246
               Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f);
252
               Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f);
247
 
253
 
248
               // display the game over dialog box
254
               // display the game over dialog box
249
               the_board.game_state = STATE_WHITEWIN_RESIGNORFORFEIT;
255
               the_board.game_state = STATE_WHITEWIN_RESIGNORFORFEIT;
250
               DialogBox_EndGame ();
256
               DialogBox_EndGame ();
251
 
257
 
252
               do_update = true; // remember to update the 3D scene
258
               do_update = true; // remember to update the 3D scene
253
            }
259
            }
254
 
260
 
255
            continue; // we processed that line
261
            continue; // we processed that line
Line 290... Line 296...
290
         // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board
296
         // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board
291
         Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f);
297
         Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f);
292
 
298
 
293
         // display a crash notification dialog box
299
         // display a crash notification dialog box
294
         if (MessageBox (hMainWnd, LOCALIZE (L"Error_EngineCrashed"), LOCALIZE (L"ImportantMessage"), MB_ICONWARNING | MB_YESNO) == IDYES)
300
         if (MessageBox (hMainWnd, LOCALIZE (L"Error_EngineCrashed"), LOCALIZE (L"ImportantMessage"), MB_ICONWARNING | MB_YESNO) == IDYES)
295
            if (Debug_SendLogToAuthor (true))
301
            if (Debug_SendLogToAuthor ("engine refused our command", true))
296
               MessageBox (hMainWnd, LOCALIZE (L"MessageSent"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK); // send the game engine history to the author
302
               MessageBox (hMainWnd, LOCALIZE (L"MessageSent"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK); // send the game engine history to the author
297
            else
303
            else
298
               MessageBox (hMainWnd, LOCALIZE (L"NoInternetConnection"), LOCALIZE (L"FatalError"), MB_ICONWARNING | MB_OK); // and display an error message if failed
304
               MessageBox (hMainWnd, LOCALIZE (L"NoInternetConnection"), LOCALIZE (L"FatalError"), MB_ICONWARNING | MB_OK); // and display an error message if failed
299
 
305
 
300
         // and display the game over dialog box
306
         // and display the game over dialog box
Line 337... Line 343...
337
 
343
 
338
      // is it NOT a hint, are blunders allowed, should we do one now AND can we do one now ?
344
      // is it NOT a hint, are blunders allowed, should we do one now AND can we do one now ?
339
      if (!is_hint_pending && (options.engine.blunder_chances > 0) && (rand () % 100 < options.engine.blunder_chances)
345
      if (!is_hint_pending && (options.engine.blunder_chances > 0) && (rand () % 100 < options.engine.blunder_chances)
340
          && Move_FindRandomMove (&the_board.moves[the_board.move_count - 1], player->color, &move))
346
          && Move_FindRandomMove (&the_board.moves[the_board.move_count - 1], player->color, &move))
341
      {
347
      {
342
         if (program->command_force[0] != 0)
348
         if (program->command_force[0] != 0) // "force" commands are only used with CECP engines such as Crafty. Others are sent the game history, so no need to force anything
343
         {
349
         {
344
            Player_SendBuffer_Add (player, 1000, program->command_force, Move_BuildString (&move)); // send the blunderous move to the engine
350
            Player_SendBuffer_Add (player, 1000, program->command_force, Move_BuildString (&move)); // send the blunderous move to the engine
345
            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
351
            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
346
            if (_wcsnicmp (program->friendly_name, L"Crafty", 6) == 0)
-
 
347
               Player_SendBuffer_Add (player, 1000, L"disp\n"); // FIXME: we no longer need this Crafty-specific hack, do we?
-
 
348
         }
352
         }
349
         Debug_Log (L"===Discarding engine move, forcing a blunderous move (%s) instead===\n", Move_BuildString (&move)); // blunder
353
         Debug_LogMove (&move, L"===Overriding engine choice with blunderous move: [%s]===\n", Move_BuildString (&move)); // blunder
350
      }
354
      }
351
 
355
 
352
      // mark the engine's selected and hovered squares
356
      // mark the engine's selected and hovered squares
353
      Board_SetSelectedAndHovered (&the_board, move.source[0], move.source[1], move.target[0], move.target[1]);
357
      Board_SetSelectedAndHovered (&the_board, move.source[0], move.source[1], move.target[0], move.target[1]);
354
 
358
 
Line 372... Line 376...
372
         the_scene.gui.central_text.disappear_time = current_time + 0.1f; // fade the "thinking" phrase out now quickly (FIXME: ugly)
376
         the_scene.gui.central_text.disappear_time = current_time + 0.1f; // fade the "thinking" phrase out now quickly (FIXME: ugly)
373
         the_scene.gui.want_spinwheel = false; // stop spinning wheel
377
         the_scene.gui.want_spinwheel = false; // stop spinning wheel
374
 
378
 
375
         highlight_endtime = current_time + 2.0f; // just highlight this part for a little more than one second
379
         highlight_endtime = current_time + 2.0f; // just highlight this part for a little more than one second
376
         is_hint_pending = false; // remember no hint is pending any longer
380
         is_hint_pending = false; // remember no hint is pending any longer
377
 
381
 
378
         // we must now restore the board to its last state. Just set up the board again from its current Forsyth-Edwards notation
382
         // we must now restore the board to its last state. Just set up the board again from its current Forsyth-Edwards notation
379
         Debug_Log (L"===Hint received, rebuilding board and telling engine to backup 1 move===\n");
383
         Debug_Log (L"===Hint received, rebuilding board and telling engine to backup 1 move===\n");
380
         Debug_Log (L"===setting up board using FEN string===\n");
384
         Debug_LogMove (&the_board.moves[the_board.move_count - 1], L"===setting up board using FEN string: [%s]===\n", the_board.moves[the_board.move_count - 1].fen_string);
381
 
385
 
382
         // get the current game state in FEN format and feed it to the engine
386
         // get the current game state in FEN format and feed it to the engine
383
         Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
387
         Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
384
         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
388
         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
385
 
-
 
386
         if (_wcsnicmp (program->friendly_name, L"Crafty", 6) == 0)
-
 
387
            Player_SendBuffer_Add (player, 1000, L"disp\n"); // FIXME: we no longer need this Crafty-specific hack, do we?
-
 
388
      }
389
      }
389
 
390
 
390
      do_update = true; // remember to update the 3D scene
391
      do_update = true; // remember to update the 3D scene
391
   }
392
   }
392
 
393
 
Line 415... Line 416...
415
      // send a new game command to the chess engine
416
      // send a new game command to the chess engine
416
      Player_SendBuffer_Add (player, 1000, program->command_new);
417
      Player_SendBuffer_Add (player, 1000, program->command_new);
417
      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
418
      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
418
 
419
 
419
      // just set up the board from its Forsyth-Edwards notation
420
      // just set up the board from its Forsyth-Edwards notation
420
      Debug_Log (L"===setting up board using FEN string===\n");
421
      Debug_LogMove (&the_board.moves[the_board.move_count - 1], L"===setting up board using FEN string: [%s]===\n", the_board.moves[the_board.move_count - 1].fen_string);
421
 
422
 
422
      // get the current game state in FEN format and feed it to the engine
423
      // get the current game state in FEN format and feed it to the engine
423
      Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
424
      Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
424
      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
425
      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
425
 
426
 
426
      current_obstinacy = 0; // reset current obstinacy
427
      current_obstinacy = 0; // reset current obstinacy
427
      is_hint_pending = false; // no hint was requested so far
428
      is_hint_pending = false; // no hint was requested so far
428
 
-
 
429
      if (_wcsnicmp (program->friendly_name, L"Crafty", 6) == 0)
-
 
430
         Player_SendBuffer_Add (player, 1000, L"disp\n"); // FIXME: we no longer need this Crafty-specific hack, do we?
-
 
431
   }
429
   }
432
 
430
 
433
   // 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)
431
   // 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)
434
   if (the_board.want_playerswap)
432
   if (the_board.want_playerswap)
435
   {
433
   {
Line 447... Line 445...
447
      if (Board_ColorToMove (&the_board) == player->color)
445
      if (Board_ColorToMove (&the_board) == player->color)
448
      {
446
      {
449
         // is it NOT a board setup AND has at least one move been played (meaning it was just the other's turn before) ?
447
         // is it NOT a board setup AND has at least one move been played (meaning it was just the other's turn before) ?
450
         if (!the_board.was_setup && (the_board.move_count > 1))
448
         if (!the_board.was_setup && (the_board.move_count > 1))
451
         {
449
         {
452
            Debug_Log (L"===Player just played, sending the chosen move to engine===\n");
450
            Debug_LogMove (&the_board.moves[the_board.move_count - 1], L"===Player just played, sending the chosen move to engine: [%s]===\n", Move_BuildString (&the_board.moves[the_board.move_count - 1]));
453
            if (_wcsnicmp (program->friendly_name, L"Crafty", 6) == 0)
-
 
454
               Player_SendBuffer_Add (player, 1000, L"disp\n"); // FIXME: we no longer need this Crafty-specific hack, do we?
-
 
455
 
451
 
456
            // build the move string, and send the move string to the engine
452
            // build the move string, and send the move string to the engine
457
            Player_SendBuffer_Add (player, 1000, program->command_move, Move_BuildString (&the_board.moves[the_board.move_count - 1]));
453
            Player_SendBuffer_Add (player, 1000, program->command_move, Move_BuildString (&the_board.moves[the_board.move_count - 1]));
458
            Player_SendBuffer_Add (player, 1000, L"\n"); // end the send buffer with a carriage return
454
            Player_SendBuffer_Add (player, 1000, L"\n"); // end the send buffer with a carriage return
459
         }
455
         }
Line 501... Line 497...
501
         the_board.move_count = max (1, the_board.move_count - 2); // figure out how many moves we have now
497
         the_board.move_count = max (1, the_board.move_count - 2); // figure out how many moves we have now
502
         the_board.viewed_move = the_board.move_count - 1; // take us back to the last move
498
         the_board.viewed_move = the_board.move_count - 1; // take us back to the last move
503
         the_board.game_state = STATE_PLAYING; // remember the game is now playing (in case we wanted to cancel the closing move of a finished game, this opens the game again)
499
         the_board.game_state = STATE_PLAYING; // remember the game is now playing (in case we wanted to cancel the closing move of a finished game, this opens the game again)
504
 
500
 
505
         // just set up the board from its Forsyth-Edwards notation
501
         // just set up the board from its Forsyth-Edwards notation
506
         Debug_Log (L"===setting up board using FEN string===\n");
502
         Debug_LogMove (&the_board.moves[the_board.move_count - 1], L"===setting up board using FEN string: [%s]===\n", the_board.moves[the_board.move_count - 1].fen_string);
507
 
503
 
508
         // get the current game state in FEN format and feed it to the engine
504
         // get the current game state in FEN format and feed it to the engine
509
         Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
505
         Player_SendBuffer_Add (player, 1000, program->command_setboard, the_board.moves[the_board.move_count - 1].fen_string);
510
         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
506
         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
511
 
-
 
512
         if (_wcsnicmp (program->friendly_name, L"Crafty", 6) == 0)
-
 
513
            Player_SendBuffer_Add (player, 1000, L"disp\n"); // FIXME: we no longer need this Crafty-specific hack, do we?
-
 
514
 
507
 
515
         do_update = true; // remember to update the 3D scene
508
         do_update = true; // remember to update the 3D scene
516
      }
509
      }
517
   }
510
   }
518
 
511