Rev 150 | Rev 154 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 150 | Rev 153 | ||
|---|---|---|---|
| Line 13... | Line 13... | ||
| 13 | 13 | ||
| 14 | // prototypes of local functions |
14 | // prototypes of local functions |
| 15 | static void PlayerEngine_Recv (player_t *player); |
15 | static void PlayerEngine_Recv (player_t *player); |
| 16 | static void PlayerEngine_Send (player_t *player); |
16 | static void PlayerEngine_Send (player_t *player); |
| 17 | static wchar_t *Move_BuildString (boardmove_t *move); |
17 | static wchar_t *Move_BuildString (boardmove_t *move); |
| - | 18 | static bool SendEngineHistoryToAuthor (void); |
|
| 18 | 19 | ||
| 19 | 20 | ||
| 20 | bool PlayerEngine_Init (player_t *player) |
21 | bool PlayerEngine_Init (player_t *player) |
| 21 | { |
22 | { |
| 22 | // this function starts a chess engine as a child process. This process's stdin and |
23 | // this function starts a chess engine as a child process. This process's stdin and |
| Line 79... | Line 80... | ||
| 79 | return (false); |
80 | return (false); |
| 80 | } |
81 | } |
| 81 | 82 | ||
| 82 | // optionally initialize the debug log file |
83 | // optionally initialize the debug log file |
| 83 | Debug_Init (L"Chess engine output.txt"); |
84 | Debug_Init (L"Chess engine output.txt"); |
| - | 85 | Debug_Log (L"===Using engine: %s [%s]===\n", program->friendly_name, chessengine_shellcommand); |
|
| 84 | 86 | ||
| 85 | // build the init file full qualified path name and try to open it |
87 | // build the init file full qualified path name and try to open it |
| 86 | swprintf_s (chessengineinitfile_pathname, WCHAR_SIZEOF (chessengineinitfile_pathname), L"%s/engines/%s/init.txt", app_path, program->folder); |
88 | swprintf_s (chessengineinitfile_pathname, WCHAR_SIZEOF (chessengineinitfile_pathname), L"%s/engines/%s/init.txt", app_path, program->folder); |
| 87 | _wfopen_s (&fp, chessengineinitfile_pathname, L"r"); |
89 | _wfopen_s (&fp, chessengineinitfile_pathname, L"r"); |
| 88 | 90 | ||
| 89 | // could the init file be opened ? |
91 | // could the init file be opened ? |
| 90 | if (fp != NULL) |
92 | if (fp != NULL) |
| 91 | { |
93 | { |
| 92 | Debug_Log (L"===Found initialization file, parsing...===\n"); |
94 | Debug_Log (L"===Found initialization file, parsing...===\n", chessengineinitfile_pathname); |
| 93 | 95 | ||
| 94 | // SMP HACK -- assume our engine is CECP compatible and set the max CPUs to use to core max - 1 |
96 | // SMP HACK -- assume our engine is CECP compatible and set the max CPUs to use to core max - 1 |
| 95 | // (the computer will look like hung if all CPU is taken) |
97 | // (the computer will look like hung if all CPU is taken) |
| 96 | GetSystemInfo (&sysinfo); // get the number of cores and build the corresponding engine initialization order |
98 | GetSystemInfo (&sysinfo); // get the number of cores and build the corresponding engine initialization order |
| 97 | Player_SendBuffer_Add (player, 1000, L"mt %d\n", max (1, sysinfo.dwNumberOfProcessors - 1)); |
99 | Player_SendBuffer_Add (player, 1000, L"mt %d\n", max (1, sysinfo.dwNumberOfProcessors - 1)); |
| Line 166... | Line 168... | ||
| 166 | do_update = false; |
168 | do_update = false; |
| 167 | 169 | ||
| 168 | // get current and opposite players |
170 | // get current and opposite players |
| 169 | current_player = Player_GetCurrent (); |
171 | current_player = Player_GetCurrent (); |
| 170 | opposite_player = Player_GetOpposite (); |
172 | opposite_player = Player_GetOpposite (); |
| - | 173 | ||
| - | 174 | // is the game still alive AND has the engine just died ? |
|
| - | 175 | if ((the_board.game_state == STATE_PLAYING) && !pipe_isalive (fpipe)) |
|
| - | 176 | { |
|
| - | 177 | Debug_Log (L"===Unrecoverable engine error: opponent wins!===\n"); |
|
| - | 178 | ||
| - | 179 | // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board |
|
| - | 180 | Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f); |
|
| - | 181 | ||
| - | 182 | // display a crash notification dialog box |
|
| - | 183 | if (MessageBox (hMainWnd, LOCALIZE (L"Error_EngineCrashed"), LOCALIZE (L"ImportantMessage"), MB_ICONWARNING | MB_YESNO) == IDYES) |
|
| - | 184 | if (!SendEngineHistoryToAuthor ()) |
|
| - | 185 | MessageBox (hMainWnd, LOCALIZE (L"NoInternetConnection"), LOCALIZE (L"FatalError"), MB_ICONWARNING | MB_OK); // send the game engine history to the author and display an error message if failed |
|
| - | 186 | ||
| - | 187 | // and display the game over dialog box |
|
| - | 188 | the_board.game_state = (opposite_player->color == COLOR_BLACK ? STATE_WHITEWIN_RESIGNORFORFEIT : STATE_BLACKWIN_RESIGNORFORFEIT); |
|
| - | 189 | DialogBox_EndGame (); |
|
| - | 190 | ||
| - | 191 | do_update = true; // remember to update the 3D scene |
|
| - | 192 | } |
|
| 171 | 193 | ||
| 172 | // read from pipe (non-blocking) |
194 | // read from pipe (non-blocking) |
| 173 | PlayerEngine_Recv (player); |
195 | PlayerEngine_Recv (player); |
| 174 | 196 | ||
| 175 | //////////////// |
197 | //////////////// |
| Line 269... | Line 291... | ||
| 269 | 291 | ||
| 270 | // has the game ended already ? |
292 | // has the game ended already ? |
| 271 | if (the_board.game_state > STATE_PLAYING) |
293 | if (the_board.game_state > STATE_PLAYING) |
| 272 | continue; // ignore all that the engine tells us. Game is over already. |
294 | continue; // ignore all that the engine tells us. Game is over already. |
| 273 | 295 | ||
| 274 | // else is it a normal move ? |
296 | // else is it a normal move AND not a polyglot error ? |
| 275 | else if ((move_string = wcsstr (line_buffer, program->replystring_move)) != NULL) |
297 | else if (((move_string = wcsstr (line_buffer, program->replystring_move)) != NULL) && (wcsstr (line_buffer, L"illegal") == NULL)) |
| 276 | move_string += wcslen (program->replystring_move); // go to the parsable data |
298 | move_string += wcslen (program->replystring_move); // go to the parsable data |
| - | 299 | ||
| - | 300 | // else is it an unrecoverable engine error ? |
|
| - | 301 | else if (wcsstr (line_buffer, L"illegal") != NULL) |
|
| - | 302 | { |
|
| - | 303 | Debug_Log (L"===Unrecoverable engine error: opponent wins!===\n"); |
|
| - | 304 | ||
| - | 305 | // if opponent player is human, play the victory sound, else, play defeat sound at the center of the board |
|
| - | 306 | Audio_PlaySound (opposite_player->type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT, 0.0f, 0.0f, 0.04f); |
|
| - | 307 | ||
| - | 308 | // display a crash notification dialog box |
|
| - | 309 | if (MessageBox (hMainWnd, LOCALIZE (L"Error_EngineCrashed"), LOCALIZE (L"ImportantMessage"), MB_ICONWARNING | MB_YESNO) == IDYES) |
|
| - | 310 | if (!SendEngineHistoryToAuthor ()) |
|
| - | 311 | MessageBox (hMainWnd, LOCALIZE (L"NoInternetConnection"), LOCALIZE (L"FatalError"), MB_ICONWARNING | MB_OK); // send the game engine history to the author and display an error message if failed |
|
| - | 312 | ||
| - | 313 | // and display the game over dialog box |
|
| - | 314 | the_board.game_state = (opposite_player->color == COLOR_BLACK ? STATE_WHITEWIN_RESIGNORFORFEIT : STATE_BLACKWIN_RESIGNORFORFEIT); |
|
| - | 315 | DialogBox_EndGame (); |
|
| - | 316 | ||
| - | 317 | do_update = true; // remember to update the 3D scene |
|
| - | 318 | } |
|
| 277 | 319 | ||
| 278 | // else it's any other sort of line |
320 | // else it's any other sort of line |
| 279 | else |
321 | else |
| 280 | continue; // skip lines that don't contain any valid move data |
322 | continue; // skip lines that don't contain any valid move data |
| 281 | 323 | ||
| Line 579... | Line 621... | ||
| 579 | wcscat_s (output_string, WCHAR_SIZEOF (output_string), L"b"); |
621 | wcscat_s (output_string, WCHAR_SIZEOF (output_string), L"b"); |
| 580 | else if (move->promotion_type == PART_QUEEN) |
622 | else if (move->promotion_type == PART_QUEEN) |
| 581 | wcscat_s (output_string, WCHAR_SIZEOF (output_string), L"q"); |
623 | wcscat_s (output_string, WCHAR_SIZEOF (output_string), L"q"); |
| 582 | 624 | ||
| 583 | return (output_string); // finished, return the move string |
625 | return (output_string); // finished, return the move string |
| - | 626 | } |
|
| - | 627 | ||
| - | 628 | ||
| - | 629 | static bool SendEngineHistoryToAuthor (void) |
|
| - | 630 | { |
|
| - | 631 | // this function upload the engine history to the remote server for debug purposes. |
|
| - | 632 | ||
| - | 633 | static char history_buffer[512 * 1024]; |
|
| - | 634 | static char base64_buffer[1024 * 1024]; |
|
| - | 635 | static char http_buffer[1024 * 1024]; // used both for request and reply |
|
| - | 636 | ||
| - | 637 | struct sockaddr_in service; |
|
| - | 638 | struct hostent *hostinfo; |
|
| - | 639 | int write_index; |
|
| - | 640 | int read_index; |
|
| - | 641 | int length; |
|
| - | 642 | SOCKET s; |
|
| - | 643 | FILE *fp; |
|
| - | 644 | ||
| - | 645 | // get a hand on the log file and read its contents |
|
| - | 646 | _wfopen_s (&fp, logfile_pathname, L"rb"); |
|
| - | 647 | if (fp == NULL) |
|
| - | 648 | return (false); // couldn't open game history log file, return an error condition |
|
| - | 649 | fseek (fp, 0, SEEK_END); |
|
| - | 650 | length = ftell (fp); // get file size |
|
| - | 651 | fseek (fp, 0, SEEK_SET); |
|
| - | 652 | if (length > sizeof (base64_buffer) - 1) |
|
| - | 653 | return (false); // history file too big, return an error condition |
|
| - | 654 | fread (base64_buffer, 1, length, fp); |
|
| - | 655 | base64_buffer[length] = 0; // terminate buffer ourselves |
|
| - | 656 | fclose (fp); |
|
| - | 657 | ConvertTo7BitASCII (history_buffer, sizeof (history_buffer), (wchar_t *) base64_buffer); |
|
| - | 658 | ||
| - | 659 | // initialize the network subsystem if required |
|
| - | 660 | if (!Network_Init ()) |
|
| - | 661 | return (false); // couldn't initialize WinSock, return an error condition |
|
| - | 662 | ||
| - | 663 | // get our distribution server's IP address from the host name |
|
| - | 664 | hostinfo = gethostbyname ("pmbaty.com"); |
|
| - | 665 | if (hostinfo == NULL) |
|
| - | 666 | return (false); // couldn't resolve hostname, return an error condition |
|
| - | 667 | ||
| - | 668 | // fill in the sockaddr server structure with the server hostinfo data |
|
| - | 669 | service.sin_family = AF_INET; |
|
| - | 670 | service.sin_addr.s_addr = inet_addr (inet_ntoa (*(struct in_addr *) hostinfo->h_addr_list[0])); |
|
| - | 671 | service.sin_port = htons (80); // connect to webserver there (port 80) |
|
| - | 672 | ||
| - | 673 | // create our socket |
|
| - | 674 | if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) |
|
| - | 675 | return (false); // couldn't resolve hostname, return an error condition |
|
| - | 676 | ||
| - | 677 | // connect to the distributor's webserver using that socket |
|
| - | 678 | if (connect (s, (struct sockaddr *) &service, sizeof (service)) == -1) |
|
| - | 679 | { |
|
| - | 680 | closesocket (s); // finished communicating, close TCP socket |
|
| - | 681 | return (false); // couldn't resolve hostname, return an error condition |
|
| - | 682 | } |
|
| - | 683 | ||
| - | 684 | // build the HTTP POST query and send it |
|
| - | 685 | length = strlen ("data=") + base64_encode (base64_buffer, history_buffer, strlen (history_buffer)); |
|
| - | 686 | sprintf_s (http_buffer, sizeof (http_buffer), |
|
| - | 687 | "POST /chess/sendcrash.php HTTP/1.1\r\n" |
|
| - | 688 | "Host: pmbaty.com\r\n" |
|
| - | 689 | "Content-Type: application/x-www-form-urlencoded\r\n" |
|
| - | 690 | "Content-Length: %d\r\n" |
|
| - | 691 | "Connection: close\r\n" |
|
| - | 692 | "\r\n" |
|
| - | 693 | "data=", length); |
|
| - | 694 | strcat_s (http_buffer, sizeof (http_buffer), base64_buffer); |
|
| - | 695 | length = strlen (http_buffer); |
|
| - | 696 | write_index = send (s, http_buffer, length, 0); // send the HTTP query |
|
| - | 697 | if (write_index != length) |
|
| - | 698 | { |
|
| - | 699 | closesocket (s); // finished communicating, close TCP socket |
|
| - | 700 | return (false); // couldn't resolve hostname, return an error condition |
|
| - | 701 | } |
|
| - | 702 | ||
| - | 703 | // read the reply (10 seconds timeout) |
|
| - | 704 | http_buffer[0] = 0; |
|
| - | 705 | read_index = RecvWithTimeout (s, 10.0f, http_buffer, sizeof (http_buffer), 0); |
|
| - | 706 | if (read_index < 1) |
|
| - | 707 | { |
|
| - | 708 | closesocket (s); // finished communicating, close TCP socket |
|
| - | 709 | return (false); // couldn't resolve hostname, return an error condition |
|
| - | 710 | } |
|
| - | 711 | ||
| - | 712 | closesocket (s); // finished communicating, close TCP socket |
|
| - | 713 | ||
| - | 714 | // terminate recv buffer ourselves |
|
| - | 715 | http_buffer[read_index] = 0; |
|
| - | 716 | ||
| - | 717 | //MessageBoxA (NULL, http_buffer, "HTTP response", MB_OK); |
|
| - | 718 | return (strstr (http_buffer, "Success") != NULL); // and return whether the server accepted our post |
|
| 584 | } |
719 | } |