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 |
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 |
|
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 |
|
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 |