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 ( |
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 ( |
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 ( |
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 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 |
|
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 375... | Line 379... | ||
| 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 |
|
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 |
|
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 |
|
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 |
|
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 | ||