// uses ChessAlpha2.ttf fonts #include #include "resource.h" #define WhiteBishop 192 #define WhiteKnight 194 #define WhiteRook 196 #define WhiteQueen 198 #define WhiteKing 200 #define WhitePawn 202 #define BlackBishop 224 #define BlackKnight 226 #define BlackRook 228 #define BlackQueen 230 #define BlackKing 232 #define BlackPawn 234 #define Check 1 #define EitherOne 2 #define DiscoveredCheck 3 int x, y, z, f, fBiggest, SquareSize, SquareSize2, AllSquareSize, LeftSide, TopSide, endoffens, Shifted; int X, Y, X2, Y2, xPos, yPos, cX, cY, cX2, cY2; int ScreenWidth, ScreenHeight, Title, Menu, Border = 16; int BlackKingX, BlackKingY, WhiteKingX, WhiteKingY; int KingX, KingY, King, BlackKingcX, BlackKingcY, WhiteKingcX, WhiteKingcY; int checktype, HalfMoves = 0, FullMoves = 1, NumberOfOnes = 32; DWORD dwBytesWritten, dwBytesRead, fileSize, PrevBestMove; BYTE MovedPiece, ReplacedPiece, chessenginemove = FALSE, chessengine = FALSE, notfound = FALSE, done = FALSE, frompromoted = FALSE; BOOL first = TRUE, WhitesMove = TRUE, movingPiece = FALSE, choosePiece = FALSE, itsdiscoveredcheck = FALSE, leftright = FALSE; BOOL promoted = FALSE, returned, rotated = FALSE, placepieces = FALSE, itscheck = FALSE, checkmate = FALSE, enpassant1 = FALSE, enpassant2 = FALSE; BOOL bk = FALSE, wk = FALSE, bqr = FALSE, bkr = FALSE, wqr = FALSE, wkr = FALSE; // if Fen[Y][X] is a 'B' (a white bishop), it's 66 in ASCII decimal and the 66th entry in Pieces is 192 which is the number of a white bishop in the ChessAlpha2.ttf font, so (BYTE*)&Pieces[Fen[Y][X]] will display a white bishop BYTE Pieces[] = {000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,192,000,000,000,000,000,000,000,000,200,000,000,194,000,202,198,196,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,224,000,000,000,000,000,000,000,000,232,000,000,226,000,234,230,228}; // B,K,N,P,Q,R b,k,n,p,q,r char szAppName[] = " SimpleChess"; char WhiteMoves[] = " WHITE'S MOVE"; char BlackMoves[] = " BLACK'S MOVE"; char Letters[] = "abcdefgh"; char letter[1], num[1], piece; char ChessAlpha2[] = "Chess Alpha 2"; char Filename[MAX_PATH]; char FullFilename[MAX_PATH]; char CurrentDir[MAX_PATH]; char EnPassant[4] = "--"; // "e3" or "-" char PlacePieces[] = "&Place Pieces Help"; char Knight; char OptionsHelp[] = "\ PLACE PIECES \n\ To place a piece, move the mouse pointer to a square,\n\ and press one of these letters\n\ (and press Shift for a white piece):\n\ K - King\n\ Q - Queen\n\ B - Bishop\n\ N - Knight\n\ R - Rook\n\ P - Pawn\n\ Press Delete to delete the piece the mouse pointer is over.\n\ \n\ ROTATE BOARD\n\ Pressing this or X will rotate the board."; char Help[] = "\ Move a piece by holding the LEFT mouse button down while moving it.\n\ \n\ Use the left and right arrow keys to go back/ahead in the game.\n\ If you play a piece after going back in a game,\n\ it becomes the last piece played.\n\ \n\ To Castle, move the King two places left or right.\n\ \n\ To take a pawn En Passant, move your pawn to where it would end up.\n\ \n\ If you want to play against the computer,\n\ download a chess engine from the Internet,\n\ and then select File -Open Chess Engine on the Menu\n\ and find and select that chess engine.\n\ \n\ Pressing the RIGHT mouse button causes\n\ the chess engine to make the move.\n\ \n\ Pressing 0 thru 9 or A thru F on your\n\ computer keyboard will change the depth\n\ of search the chess engine makes.\n\ (A thru F are 10 thru 15 in hexadecimal)\n\ \n\ Doug Cox jdmcox@jdmcox.com\n\ Updates at jdmcox.com\n\ Put this font with your other fonts:\n\ http:\\\\jdmcox.com\\ChessAlpha2.ttf"; char AdvancedHelp[] = "\ Opening a chess engine will show CHECKMATE (if it happens) because it's calculated by the chess engine, not SimpleChess.\n\ \n\ You can see what a chess engine is doing by opening it directly (click on it in the directory it's in). The first command you can send it is \"uci\" followed by pressing the Enter key. It should respond with a screen of strange options. If it doesn't, maybe that chess engine doesn't support the Universal Chess Interface (UCI)). You can then enter \"isready\" followed by Enter if you want. I don't. Then you can even enter \"ucinewgame\" followed by Enter. I don't.\n\ \n\ The first important command to send to a chess engine is a special line of characters that represent the current location of the chess pieces followed by some other information. SimpleChess automatically sends this when you press the right mouse button while playing SimpleChess. This string is called the Forsythe-Edwards Notation (FEN). It looks like this:\n\ position fen rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n\ this is a chess board layout with no pieces having been moved (the lower case pieces are black). The small w following the chess pieces means it's white's move. The KQkq tells the chess engine if the kings can or can't castle in each of the 4 possible directions. The - indicates no pawn can be taken en passant. Next is the number of moves since the last capture or pawn move, and the last number is the total moves divided by 2 (1 is there at the beginning of a game).\n\ \n\ You can see the FEN string that will go to the chess engine by pressing the Z key in SimpleChess (you'll also see the chess engine's name if a move has been made). This FEN string is put into the Windows Clipboard every time a move is made. Thus you can paste the current FEN string from SimpleChess into a chess engine you opened directly (it will include the Enter command at the end).\n\ \n\ The next command to send to a chess engine is simply \"go\" (followed by pressing the Enter key). This tells the chess engine to begin searching for the best move. SimpleChess alters this \"go\" command to include how deep a search the chess engine makes by using the \"Go Depth x\" command. I've found that 16 is the best maximum depth to use in SimpleChess. To alter the depth, press a number between 0 and 9 or a letter between A and F (16 hexadecimal numbers) on your computer keyboard. Pressing F sends \"go depth 16\". Zero is the default setting.\n\ \n\ If you open a chess engine directly, and then you play a move in SimpleChess, and then press Ctrl-V at the flashing cursor on the chess engine's screen, SimpleChess' move will be pasted into the chess engine. Then you only need to enter \"go\" or \"go depth x\" at the next flashing cursor (followed by Enter). This will show you a line of data for each depth of the chess engine's search for the best move. If you just entered \"go\", you might have to enter \"stop\" (followed by Enter) while the search is going on to stop it. You can also enter \"quit\" to quit.\n\ \n\ C:\\Users\\Public\\Chess Engines\\CurrentEngine.txt\ncontains the current chess engine's name."; HWND hwnd, hwndEdit, hwndCheck, hwndCheckMate; HINSTANCE hInst; HANDLE hFile, hFindFile; HFONT hFont; LOGFONT lf; OPENFILENAME ofn; HBRUSH hBeigeBrush, hBrownBrush, hBorderBrush, hGreyBrush; HPEN hBeigePen, hBrownPen, hBorderPen, hGreyPen; HGDIOBJ hOldBrush, hOldPen, hOldFont; RECT rect; HBITMAP hMemBitmap, hMem2Bitmap; HDC hdc, hdcMem = 0, hdcMem2; PAINTSTRUCT ps; ////////////////////////////////////// chess engine stuff HGLOBAL hGlob = 0; HANDLE hClipboard; SECURITY_ATTRIBUTES saAttr; HANDLE IN_Rd = NULL; HANDLE IN_Wr = NULL; HANDLE OUT_Rd = NULL; HANDLE OUT_Wr = NULL; PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; WIN32_FIND_DATA fd; int fook, fook2, x0, x1, y0, y1, dx, dy, sx, sy, err, e2, skip, Size = 12; char CurrentEngine[] = "C:\\Users\\Public\\ChessEngines\\CurrentEngine.txt"; char ChessEngine[MAX_PATH]; char GoDepth[16] = "go depth 1\r\n\0"; char GoDepth2[16] = "go depth 10\r\n\0"; char Quit[7] = "quit\r\n\0"; char cBuf[10240]; DWORD dwRead, dwWritten; char fen, Promoted = 'x'; char Fen[8][12]; // 12 to have a following zero char Fens[500][108]; char OrigPositions[72] = "rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR"; char OrigFenString[100] = "position fen rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR w KQkq - 0 1\r\n"; char PlPoFenString[100] = "position fen r111k11r/11111111/11111111/11111111/11111111/11111111/11111111/R111K11R w KQkq - 0 1\r\n"; ////////////////////////////////////// int CheckKing(int, int, int); BOOL CheckMove(void); BOOL CheckRook(void); BOOL CheckKnight(void); BOOL CheckBishop(void); BOOL CheckQueen(void); void UpdateMoves(void); void Enpassant(int); void GetFensData(void); void PlacePiece(WPARAM); void LeftRight(void); void InCommon(void); void LoadChessEngine(void); int CALLBACK CheckProc(HWND, UINT, WPARAM, LPARAM); int CALLBACK CheckMateProc(HWND, UINT, WPARAM, LPARAM); int CALLBACK PromotionProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MSG msg; WNDCLASS wndclass; hInst = hInstance; wndclass.style = CS_HREDRAW|CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE ("PAWN")); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = "MENU"; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) return 0; hwnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, SW_SHOWNORMAL); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_CREATE: f = fBiggest = 0; for (x = 0; OrigFenString[x] != 0; x++) Fens[f][x] = OrigFenString[x]; Fens[f][x] = 0; for (y = 0, z = 0; z < 8; z++) { for (x = 0; x < 8; x++, y++) Fen[z][x] = OrigPositions[y]; y++; // past '/' } AddFontResource("ChessAlpha2.ttf"); SetWindowText(hwnd, WhiteMoves); Filename[0] = 0; hBeigeBrush = CreateSolidBrush(0x95B3BA); hBeigePen = CreatePen(PS_SOLID, 1, 0x65838A); hBrownBrush = CreateSolidBrush(0x6084A2); hBrownPen = CreatePen(PS_SOLID, 1, 0x305472); hBorderBrush = CreateSolidBrush(0x2D4868); hBorderPen = CreatePen(PS_SOLID, 1, 0x2D4868); hGreyBrush = CreateSolidBrush(0xBBBBBB); hGreyPen = CreatePen(PS_SOLID, 1, 0xBBBBBB); ofn.lStructSize = sizeof(OPENFILENAME); ofn.lpstrFilter = TEXT(" *.*\0*.*\0\0"); ofn.lpstrCustomFilter = NULL; ofn.lpstrFile = FullFilename; ofn.lpstrFileTitle = Filename; ofn.Flags = OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_OVERWRITEPROMPT; ofn.lpstrDefExt = NULL; ofn.hwndOwner = hwnd; ofn.hInstance = NULL; ofn.nMaxFile = MAX_PATH; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrInitialDir = NULL; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; ScreenWidth = GetSystemMetrics(SM_CXFULLSCREEN); ScreenHeight = GetSystemMetrics(SM_CYFULLSCREEN); Menu = GetSystemMetrics(SM_CYMENU); Title = GetSystemMetrics(SM_CYCAPTION); GetClientRect(hwnd, &rect); // CW_USEDEFAULT (the sizing here and in WM_SIZE is weird but necessary) if (rect.bottom < rect.right) SquareSize = (rect.bottom - (2*Border)) / 8; else SquareSize = (rect.right - (2*Border)) / 8; AllSquareSize = 8 * SquareSize; LeftSide = (ScreenWidth / 2) - (Border + (SquareSize * 4)); TopSide = (ScreenHeight / 2) - (Border + (SquareSize * 4)); MoveWindow(hwnd, LeftSide, TopSide, AllSquareSize+(2*Border), rect.bottom+Title+Menu, FALSE); break; case WM_SIZE: // in case I put sizing capability back rect.right = LOWORD(lParam); rect.bottom = HIWORD(lParam); if (rect.bottom < rect.right) SquareSize = (rect.bottom - (2*Border)) / 8; // height else SquareSize = (rect.right - (2*Border)) / 8; // width AllSquareSize = 8 * SquareSize; SquareSize2 = (2 * SquareSize); lf.lfHeight = -((SquareSize*3*96)/(4*72)); // presumes 96 = dots/inch of monitor lf.lfWeight = 700; lf.lfItalic = 0; lf.lfUnderline = 0; lf.lfStrikeOut = 0; lf.lfCharSet = 0; lf.lfOutPrecision = 3; lf.lfClipPrecision = 2; lf.lfQuality = 1; lf.lfPitchAndFamily = 0x22; for (x = 0; ChessAlpha2[x] != 0; x++) lf.lfFaceName[x] = ChessAlpha2[x]; lf.lfFaceName[x] = 0; hFont = CreateFontIndirect(&lf); // chess pieces break; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_FILE_CHESSENGINE: for (x = 0; ofn.lpstrFile[x] != 0; x++) ofn.lpstrFile[x] = 0; if (GetOpenFileName(&ofn)) { if (chessengine) WriteFile(IN_Wr, Quit, 7, &dwBytesWritten, NULL); for (x = 0; ofn.lpstrFile[x] != 0; x++) ; hFile = CreateFile(CurrentEngine, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { WriteFile(hFile, ofn.lpstrFile, x, &dwBytesWritten, NULL); // new current engine name saved in CurrentEngine CloseHandle(hFile); LoadChessEngine(); } else { GetCurrentDirectory(255, CurrentDir); SetCurrentDirectory(TEXT("C:\\USERS\\PUBLIC\\")); hFindFile = FindFirstFile(TEXT("ChessEngines"), &fd); if (INVALID_HANDLE_VALUE == hFindFile) CreateDirectory(TEXT("ChessEngines"), NULL); SetCurrentDirectory(CurrentDir); hFile = CreateFile(CurrentEngine, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { WriteFile(hFile, ofn.lpstrFile, x, &dwBytesWritten, NULL); // new current engine name saved in CurrentEngine FlushFileBuffers(hFile); CloseHandle(hFile); LoadChessEngine(); } else MessageBox(hwnd, "?", "", MB_OK); } } break; case FILE_SAVE: for (x = 0; ofn.lpstrFile[x] != 0; x++) ofn.lpstrFile[x] = 0; if (GetSaveFileName(&ofn)) { if (INVALID_HANDLE_VALUE != (hFile = CreateFile(FullFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL))) { for (x = 0; x <= f; x++) WriteFile(hFile, Fens[x], 108, &dwBytesWritten, NULL); CloseHandle(hFile); } } break; case ID_FILE_LOADGAME: if (GetOpenFileName(&ofn)) { if (INVALID_HANDLE_VALUE != (hFile = CreateFile(FullFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))) { if (fileSize = GetFileSize(hFile, NULL)) { f = fileSize / 108; for (x = 0; x < f; x++) ReadFile(hFile, Fens[x], 108, &dwBytesRead, NULL); CloseHandle(hFile); f--; fBiggest = f; if (Fens[f][85] == 'w') { WhitesMove = TRUE; SetWindowText(hwnd, WhiteMoves); } else { WhitesMove = FALSE; SetWindowText(hwnd, BlackMoves); } for (y = 13, z = 0; z < 8; z++) { for (x = 0; x < 8; x++, y++) Fen[z][x] = Fens[f][y]; y++; // past '/' } GetFensData(); rotated = FALSE; placepieces = FALSE; } InvalidateRect(hwnd, &rect, FALSE); UpdateWindow(hwnd); } } break; case ID_FILE_EXIT: DestroyWindow(hwnd); break; case ID_OPTIONSHELP: MessageBox(hwnd, OptionsHelp, "Options Help", MB_OK); break; case ID_SETUPPIECES: SetWindowText(hwnd, szAppName); bk = FALSE; wk = FALSE; bqr = FALSE; bkr = FALSE; wqr = FALSE; wkr = FALSE; // both kings can castle either way rotated = FALSE; WhitesMove = TRUE; SetWindowText(hwnd, WhiteMoves); placepieces = TRUE; if (IDNO == MessageBox(hwnd, "Place pieces from game?", "", MB_YESNO|MB_DEFBUTTON2)) { for (x = 0; PlPoFenString[x] != 0; x++) Fens[f][x] = PlPoFenString[x]; x = 13; for (z = 0; z < 8; z++) { // update Fen from Fens for (y = 0; y < 8; y++) Fen[z][y] = Fens[f][x++]; x++; } } InvalidateRect(hwnd, &rect, FALSE); break; case ROTATE: if (rotated) rotated = FALSE; else rotated = TRUE; first = TRUE; // to rotate letters and numbers on border InvalidateRect(hwnd, &rect, FALSE); break; case ID_HELP40029: MessageBox(hwnd, Help, szAppName, MB_OK); break; case ID_ADVANCEDHELP: MessageBox(hwnd, AdvancedHelp, szAppName, MB_OK); break; } // end of case WM_COMMAND: break; case WM_KEYDOWN: Shifted = GetKeyState(VK_SHIFT) & 0x00008000; // for PlacePiece switch(wParam) { case VK_DELETE: case 'B': case 'K': case 'N': case 'P': case 'Q': case 'R': if (placepieces) PlacePiece(wParam); break; case 'Z': for (x = 0; ChessEngine[x] != 0; x++) ; for ( ; (x >= 0) && (ChessEngine[x] != '\\'); x--) ; x++; MessageBox(hwnd, Fens[f], &ChessEngine[x], MB_OK); break; case 'X': SendMessage (hwnd, WM_COMMAND, ROTATE, 0); break; case VK_LEFT: if (f) { f--; LeftRight(); } Sleep(5); SetFocus(hwnd); // this has to be here for a necessary delay after CHECK or CHECKMATE break; case VK_RIGHT: if (f < fBiggest) { f++; LeftRight(); } Sleep(5); SetFocus(hwnd); // this has to be here for a necessary delay after CHECK or CHECKMATE break; } // end of switch if ((wParam >= '0') && (wParam <= '8')) { GoDepth[9] = wParam + 1; Size = 12; } else if ((wParam >= 'A') && (wParam <= 'F')) { if ((!placepieces) || (wParam != 'B')) { GoDepth2[9] = '1'; GoDepth2[10] = wParam - 16; // make 'A' a '1' Size = 13; } } else if (wParam == '9') { GoDepth2[9] = '1'; GoDepth2[10] = '0'; Size = 13; } break; case WM_MOUSEMOVE: xPos = LOWORD(lParam) - LeftSide; yPos = HIWORD(lParam); if (!chessenginemove && (movingPiece || placepieces)) { InvalidateRect(hwnd, &rect, FALSE); UpdateWindow(hwnd); } break; case WM_LBUTTONDOWN: if (checkmate) break; DestroyWindow(hwndCheck); chessenginemove = FALSE; xPos = LOWORD(lParam) - LeftSide; yPos = HIWORD(lParam); X = xPos / SquareSize; Y = yPos / SquareSize; if (!rotated) fen = Fen[Y][X]; else fen = Fen[7-Y][7-X]; if (((WhitesMove) && (fen < 98)) || ((!WhitesMove) && (fen >= 98))) { // 98 is ASCII for 'b' if (!rotated) Fen[Y][X] = '1'; else Fen[7-Y][7-X] = '1'; MovedPiece = fen; movingPiece = TRUE; InvalidateRect(hwnd, &rect, FALSE); UpdateWindow(hwnd); } break; case WM_LBUTTONUP: // piece was moved by me if (checkmate) break; if ((!chessengine) && (!notfound)) LoadChessEngine(); if (leftright) { leftright = FALSE; UpdateMoves(); } if (movingPiece) { xPos = LOWORD(lParam) - LeftSide; yPos = HIWORD(lParam); X2 = xPos / SquareSize; Y2 = yPos / SquareSize; if (!rotated) { cX = X; cY = Y; cX2 = X2; cY2 = Y2; } else { cX = 7-X; cY = 7-Y; cX2 = 7-X2; cY2 = 7-Y2; } ReplacedPiece = Fen[cY2][cX2]; Fen[cY2][cX2] = MovedPiece; if (FALSE == CheckMove()) { if ((cX != cX2) || (cY != cY2)) { Fen[cY][cX] = MovedPiece; Fen[cY2][cX2] = ReplacedPiece; } choosePiece = FALSE; movingPiece = FALSE; InvalidateRect(hwnd, &rect, FALSE); break; // out of case WM_LBUTTONUP } InCommon(); } break; // end of WM_LBUTTONUP case WM_RBUTTONDOWN: // to have the chess engine move piece if (checkmate) break; DestroyWindow(hwndCheck); if ((!chessengine) && (!notfound)) LoadChessEngine(); if (notfound) break; if (leftright) { leftright = FALSE; UpdateMoves(); } chessenginemove = TRUE; for (x = 0; Fens[f][x] != 0; x++) ; WriteFile(IN_Wr, Fens[f], x, &dwBytesWritten, NULL); if (Size == 12) WriteFile(IN_Wr, GoDepth, 12, &dwWritten, NULL); if (Size == 13) WriteFile(IN_Wr, GoDepth2, 13, &dwWritten, NULL); for (fook2 = 0; fook2 < 0x6FFFFF; fook2++) { fileSize = GetFileSize(OUT_Rd, NULL); if (!fileSize) continue; ReadFile(OUT_Rd, cBuf, fileSize, &dwRead, NULL); for (x = 0; x < (int)dwRead; x++) { if ((0x74736562 == *(DWORD*)&cBuf[x]) && (0x65766F6D == *(DWORD*)&cBuf[x+4])) // bestmove break; } Sleep(5); if (x < (int)dwRead) { // if "bestmove" found PrevBestMove = *(DWORD*)&cBuf[x+9]; X = cBuf[x+9] - 'a'; X2 = cBuf[x+11] - 'a'; Y = '8' - cBuf[x+10]; Y2 = '8' - cBuf[x+12]; if (rotated) { X = 7 - X; X2 = 7 - X2; Y = 7 - Y; Y2 = 7 - Y2; } break; } } // end of for (fook = 0;... if (fook2 >= 0x6FFFFF) { MessageBox(hwnd, Fens[f], "The chess engine thought for over 7 million loops over this Fen string:", MB_OK); DestroyWindow(hwnd); break; } movingPiece = TRUE; if (!rotated) fen = Fen[Y][X]; // used in WM_PAINT else fen = Fen[7-Y][7-X]; if (!rotated) Fen[Y][X] = '1'; // used in WM_PAINT else Fen[7-Y][7-X] = '1'; x0 = LeftSide+(SquareSize*X)+(SquareSize/2); // Bresenham's algorithm y0 = Border+(SquareSize*Y)+(SquareSize/2); x1 = LeftSide+(SquareSize*X2)+(SquareSize/2); y1 = Border+(SquareSize*Y2)+(SquareSize/2); dx = abs(x1-x0); dy = abs(y1-y0); if (x0 < x1) sx = 1; else sx = -1; if (y0 < y1) sy = 1; else sy = -1; err = dx-dy; hdc = GetDC(hwnd); for (skip = 0; (x0 != x1) || (y0 != y1); skip++) { // this shows moving piece e2 = 2*err; if (e2 > (-dy)) { err = err - dy; x0 = x0 + sx; } if (e2 < dx) { err = err + dx; y0 = y0 + sy; } if (0 == (skip % 2)) { xPos = x0-LeftSide; // used in WM_PAINT yPos = y0; // used in WM_PAINT BitBlt(hdcMem2, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY); for (y = 0; y < 8; y++) { // place pieces for (x = 0; x < 8; x++) { if (!rotated) TextOut(hdcMem2, LeftSide+(SquareSize*x), Border+(SquareSize*y), (BYTE*)&Pieces[Fen[y][x]], 1); else TextOut(hdcMem2, LeftSide+(SquareSize*x), Border+(SquareSize*y), (BYTE*)&Pieces[Fen[7-y][7-x]], 1); } } TextOut(hdcMem2, LeftSide+xPos-(SquareSize/2), yPos-(SquareSize/2), (BYTE*)&Pieces[fen], 1); BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem2, 0, 0, SRCCOPY); } } ReleaseDC(hwnd, hdc); if (!rotated) { cX = X; cY = Y; cX2 = X2; cY2 = Y2; } else { cX = 7-X; cY = 7-Y; cX2 = 7-X2; cY2 = 7-Y2; } MovedPiece = fen; ReplacedPiece = Fen[cY2][cX2]; Fen[cY2][cX2] = MovedPiece; CheckMove(); InCommon(); break; // end of case WM_RBUTTONDOWN case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (first) { first = FALSE; if (!hdcMem) { hdcMem = CreateCompatibleDC(hdc); hMemBitmap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom); SelectObject(hdcMem, hMemBitmap); FillRect(hdcMem, &rect, hGreyBrush); hdcMem2 = CreateCompatibleDC(hdc); hMem2Bitmap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom); SelectObject(hdcMem2, hMem2Bitmap); } hOldPen = SelectObject(hdcMem, hBorderPen); hOldBrush = SelectObject(hdcMem, hBorderBrush); SetBkMode(hdcMem, TRANSPARENT); LeftSide = Border; Rectangle(hdcMem, LeftSide, 0, LeftSide+AllSquareSize, Border); // top border Rectangle(hdcMem, LeftSide, Border+AllSquareSize, LeftSide+AllSquareSize, Border + AllSquareSize + Border); // bottom border Rectangle(hdcMem, LeftSide-Border, 0, LeftSide+Border, Border + AllSquareSize + Border); // left border Rectangle(hdcMem, LeftSide+AllSquareSize, 0, LeftSide+AllSquareSize+Border, Border + AllSquareSize + Border); // right border SelectObject(hdcMem, hOldBrush); SelectObject(hdcMem, hOldPen); hOldPen = SelectObject(hdcMem, hBeigePen); hOldBrush = SelectObject(hdcMem, hBeigeBrush); SetTextColor(hdcMem, 0xCCCCCC); if (!rotated) { letter[0] = 'a'; for (x = 0; x < AllSquareSize; x += SquareSize, letter[0]++) { TextOut(hdcMem, LeftSide+x+(SquareSize/2), Border+AllSquareSize, &letter[0], 1); TextOut(hdcMem, LeftSide+x+(SquareSize/2), 0, &letter[0], 1); } num[0] = '8'; for (y = 0; y < AllSquareSize; y += SquareSize, num[0]--) { TextOut(hdcMem, LeftSide-(Border*3/4), (Border/2)+y+(SquareSize/2), &num[0], 1); TextOut(hdcMem, LeftSide+(Border/4)+AllSquareSize, (Border/2)+y+(SquareSize/2), &num[0], 1); } } else { letter[0] = 'h'; for (x = 0; x < AllSquareSize; x += SquareSize, letter[0]--) { TextOut(hdcMem, LeftSide+x+(SquareSize/2), Border+AllSquareSize, &letter[0], 1); TextOut(hdcMem, LeftSide+x+(SquareSize/2), 0, &letter[0], 1); } num[0] = '1'; for (y = 0; y < AllSquareSize; y += SquareSize, num[0]++) { TextOut(hdcMem, LeftSide-(Border*3/4), (Border/2)+y+(SquareSize/2), &num[0], 1); TextOut(hdcMem, LeftSide+(Border/4)+AllSquareSize, (Border/2)+y+(SquareSize/2), &num[0], 1); } } SelectObject(hdcMem, hOldBrush); SelectObject(hdcMem, hOldPen); hOldPen = SelectObject(hdcMem, hBeigePen); hOldBrush = SelectObject(hdcMem, hBeigeBrush); for (y = Border; y < (Border + AllSquareSize); y += SquareSize2) { for (x = LeftSide; x < (LeftSide+AllSquareSize); x += SquareSize2) Rectangle(hdcMem, x, y, x+SquareSize, y+SquareSize); } for (y = Border+SquareSize; y < (Border+AllSquareSize); y += SquareSize2) { for (x = LeftSide+SquareSize; x < (LeftSide+SquareSize+AllSquareSize); x += SquareSize2) Rectangle(hdcMem, x, y, x+SquareSize, y+SquareSize); } SelectObject(hdcMem, hOldBrush); SelectObject(hdcMem, hOldPen); hOldBrush = SelectObject(hdcMem, hBrownBrush); hOldPen = SelectObject(hdcMem, hBrownPen); for (y = Border+SquareSize; y < (Border + AllSquareSize); y += SquareSize2) { for (x = LeftSide; x < (LeftSide+AllSquareSize); x += SquareSize2) Rectangle(hdcMem, x, y, x+SquareSize, y+SquareSize); } for (y = Border; y < (Border + AllSquareSize); y += SquareSize2) { for (x = LeftSide+SquareSize; x < (LeftSide+SquareSize+AllSquareSize); x += SquareSize2) Rectangle(hdcMem, x, y, x+SquareSize, y+SquareSize); } SelectObject(hdcMem, hOldBrush); SelectObject(hdcMem, hOldPen); SelectObject(hdcMem2, hFont); SetBkMode(hdcMem2, TRANSPARENT); SetTextColor(hdcMem2, 0); } // end of if (first) BitBlt(hdcMem2, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY); for (y = 0; y < 8; y++) { // place pieces for (x = 0; x < 8; x++) { if (!rotated) TextOut(hdcMem2, LeftSide+(SquareSize*x), Border+(SquareSize*y), (BYTE*)&Pieces[Fen[y][x]], 1); else TextOut(hdcMem2, LeftSide+(SquareSize*x), Border+(SquareSize*y), (BYTE*)&Pieces[Fen[7-y][7-x]], 1); } } if (movingPiece) TextOut(hdcMem2, LeftSide+xPos-(SquareSize/2), yPos-(SquareSize/2), (BYTE*)&Pieces[fen], 1); BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem2, 0, 0, SRCCOPY); EndPaint(hwnd, &ps); break; case WM_DESTROY: if (chessengine) WriteFile(IN_Wr, Quit, 7, &dwBytesWritten, NULL); RemoveFontResource("ChessAlpha2.ttf"); DeleteDC(hdcMem); DeleteObject(hMemBitmap); DeleteDC(hdcMem2); DeleteObject(hMem2Bitmap); PostQuitMessage(0); break; } return DefWindowProc(hwnd, message, wParam, lParam); } //SUB-ROUTINES******************************************************* BOOL CheckRook(void) // see if this is a legal move { if ((cX == cX2) || (cY == cY2)) { returned = TRUE; if (cY2 > cY) { for (y = cY+1; y < cY2; y++) { if (Fen[y][cX] != '1') { returned = FALSE; break; } } } else if (cY2 < cY) { for (y = cY-1; y > cY2; y--) { if (Fen[y][cX] != '1') { returned = FALSE; break; } } } else if (cX2 > cX) { for (x = cX+1; x < cX2; x++) { if (Fen[cY][x] != '1') { returned = FALSE; break; } } } else if (cX2 < cX) { for (x = cX-1; x > cX2; x--) { if (Fen[cY][x] != '1') { returned = FALSE; break; } } } if (returned == TRUE) { if (fen == 'r') { if (cX == 0) bqr = TRUE; else if (cX == 7) bkr = TRUE; } else if (fen == 'R') { if (cX == 0) wqr = TRUE; else if (cX == 7) wkr = TRUE; } } return returned; } else return FALSE; } BOOL CheckKnight(void) // is this a legal move? { if ((cX2 == cX-1) && (cY2 == cY+2)) return TRUE; else if ((cX2 == cX+1) && (cY2 == cY+2)) return TRUE; else if ((cX2 == cX-2) && (cY2 == cY+1)) return TRUE; else if ((cX2 == cX+2) && (cY2 == cY+1)) return TRUE; else if ((cX2 == cX-1) && (cY2 == cY-2)) return TRUE; else if ((cX2 == cX+1) && (cY2 == cY-2)) return TRUE; else if ((cX2 == cX-2) && (cY2 == cY-1)) return TRUE; else if ((cX2 == cX+2) && (cY2 == cY-1)) return TRUE; else return FALSE; } BOOL CheckBishop(void) // is this a legal move? { if (abs(cX2-cX) != abs(cY2-cY)) return FALSE; if ((cX2 > cX) && (cY2 > cY)) { for (x = cX+1, y = cY+1; x < cX2; x++, y++) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } else if ((cX2 < cX) && (cY2 > cY)) { for (x = cX-1, y = cY+1; x > cX2; x--, y++) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } else if ((cX2 > cX) && (cY2 < cY)) { for (x = cX+1, y = cY-1; x < cX2; x++, y--) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } else if ((cX2 < cX) && (cY2 < cY)) { for (x = cX-1, y = cY-1; x > cX2; x--, y--) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } return FALSE; } BOOL CheckQueen(void) // is this a legal move? { if (cX2 == cX) { if (cY2 > cY) { for (y = cY+1; y < cY2; y++) if (Fen[y][cX] != '1') return FALSE; } else { // if (cY2 <= cY) { for (y = cY-1; y > cY2; y--) { if (Fen[y][cX] != '1') return FALSE; } } return TRUE; } else if (cY2 == cY) { if (cX2 > cX) { for (x = cX+1; x < cX2; x++) { if (Fen[cY][x] != '1') return FALSE; } } else { // if (cX2 <= cX) { for (x = cX-1; x > cX2; x--) { if (Fen[cY][x] != '1') return FALSE; } } return TRUE; } else if (abs(cX2-cX) != abs(cY2-cY)) return FALSE; else if ((cX2 > cX) && (cY2 > cY)) { for (x = cX+1, y = cY+1; x < cX2; x++, y++) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } else if ((cX2 < cX) && (cY2 > cY)) { for (x = cX-1, y = cY+1; x > cX2; x--, y++) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } else if ((cX2 > cX) && (cY2 < cY)) { for (x = cX+1, y = cY-1; x < cX2; x++, y--) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } else if ((cX2 < cX) && (cY2 < cY)) { for (x = cX-1, y = cY-1; x > cX2; x--, y--) { if (Fen[y][x] != '1') return FALSE; } return TRUE; } return FALSE; } BOOL CheckMove(void) { if ((cX2 == cX) && (cY2 == cY)) return FALSE; switch (MovedPiece) { case 'p': enpassant1 = FALSE; if (cY2 == 7) choosePiece = TRUE; // promote the pawn else choosePiece = FALSE; if ((cY2 == cY+1) && (cX2 == cX) && (ReplacedPiece == '1')) // moving down return TRUE; if (ReplacedPiece >= 98) // can't take a black piece return FALSE; if ((cY2 == cY+1) && (ReplacedPiece != '1') && ((cX2 == cX+1) || (cX2 == cX-1))) // taking something return TRUE; if ((cY == 1) && (cX2 == cX) && (ReplacedPiece == '1') && ((cY2 == 2) || (cY2 == 3))) // first move return TRUE; if ((EnPassant[0] == Letters[cX2]) && (((cX-cX2) == 1) || ((cX2-cX) == 1)) && (EnPassant[1] == (8-cY2)+'0') && ((cY2-cY) == 1)) { // En Passant enpassant1 = TRUE; Fen[cY2-1][cX2] = '1'; return TRUE; } return FALSE; case 'P': enpassant2 = FALSE; if (cY2 == 0) choosePiece = TRUE; // promote the pawn else choosePiece = FALSE; if ((cY2 == cY-1) && (cX2 == cX) && (ReplacedPiece == '1')) // moving up return TRUE; if ((ReplacedPiece != '1') && (ReplacedPiece < 98)) // can't take a white piece return FALSE; if ((cY2 == cY-1) && (ReplacedPiece != '1') && ((cX2 == cX+1) || (cX2 == cX-1))) // taking something return TRUE; if ((cY == 6) && (cX2 == cX) && (ReplacedPiece == '1') && ((cY2 == 5) || (cY2 == 4))) // first move return TRUE; if ((EnPassant[0] == Letters[cX2]) && (((cX-cX2) == 1) || ((cX2-cX) == 1)) && (EnPassant[1] == (8-cY2)+'0') && ((cY-cY2) == 1)) { // En Passant enpassant2 = TRUE; Fen[cY2+1][cX2] = '1'; return TRUE; } return FALSE; case 'n': if (ReplacedPiece >= 98) return FALSE; if (CheckKnight()) return TRUE; else return FALSE; case 'N': if ((ReplacedPiece != '1') && (ReplacedPiece < 98)) return FALSE; if (CheckKnight()) return TRUE; else return FALSE; case 'b': if (ReplacedPiece >= 98) return FALSE; if (CheckBishop()) return TRUE; else return FALSE; case 'B': if ((ReplacedPiece != '1') && (ReplacedPiece < 98)) return FALSE; if (CheckBishop()) return TRUE; else return FALSE; case 'r': if (ReplacedPiece >= 98) { return FALSE; } if (CheckRook()) return TRUE; else return FALSE; case 'R': if ((ReplacedPiece != '1') && (ReplacedPiece < 98)) { return FALSE; } if (CheckRook()) return TRUE; else return FALSE; case 'q': if (ReplacedPiece >= 98) return FALSE; if (CheckQueen()) return TRUE; else return FALSE; case 'Q': if ((ReplacedPiece != '1') && (ReplacedPiece < 98)) return FALSE; if (CheckQueen()) return TRUE; else return FALSE; case 'k': if (ReplacedPiece >= 98) return FALSE; if ((bk == FALSE) && (bkr == FALSE)) { // if neither king nor the king's rook has moved if ((cX == 4) && (cX2 == 6) && (cY == 0)) { // CASTLE ON KING'S SIDE (the King has already moved) if ((ReplacedPiece == '1') && (Fen[0][5] == '1') && (Fen[0][6] == 'k') && (Fen[0][7] == 'r')) { if (CheckKing(4, 0, BlackKing)) return FALSE; if (CheckKing(5, 0, BlackKing)) return FALSE; if (CheckKing(6, 0, BlackKing)) return FALSE; *(DWORD*)&Fen[0][4] = 0x316B7231; // 1rk1 (making 4 moves at once (well, the king was already there)) bk = bkr = TRUE; return TRUE; } } else if ((cX == 4) && (cX2 == 2) && (cY == 0)) { // CASTLE ON QUEEN'S SIDE (the King has already moved) if ((bk == TRUE) && (bqr == TRUE)) return FALSE; // king or rook moved if ((ReplacedPiece == '1') && (Fen[0][3] == '1') && (Fen[0][2] == 'k') && (Fen[0][1] == '1') && (Fen[0][0] == 'r')) { if (CheckKing(2, 0, BlackKing)) return FALSE; if (CheckKing(3, 0, BlackKing)) return FALSE; if (CheckKing(4, 0, BlackKing)) return FALSE; *(DWORD*)&Fen[0][1] = 0x31726B31; // 1kr1 Fen[0][0] = '1'; bk = bqr = TRUE; return TRUE; } } } if (((cX2 == cX+1) || (cX2 == cX-1) || (cX2 == cX)) && ((cY2 == cY+1) || (cY2 == cY-1) || (cY2 == cY))) { bk = TRUE; return TRUE; } else return FALSE; case 'K': if ((ReplacedPiece != '1') && (ReplacedPiece < 98)) return FALSE; if ((wk == FALSE) && (wkr == FALSE)) { if ((cX == 4) && (cX2 == 6) && (cY == 7)) { // king was already moved if ((ReplacedPiece == '1') && (Fen[7][5] == '1') && (Fen[7][6] == 'K') && (Fen[7][7] == 'R')) { if (CheckKing(4, 7, WhiteKing)) return FALSE; if (CheckKing(5, 7, WhiteKing)) return FALSE; if (CheckKing(6, 7, WhiteKing)) return FALSE; *(DWORD*)&Fen[7][4] = 0x314B5231; // 1RK1 wk = wkr = TRUE; return TRUE; } } else if ((cX == 4) && (cX2 == 2) && (cY == 7)) { if ((wk == TRUE) && (wqr == TRUE)) return FALSE; // king or rook moved if ((ReplacedPiece == '1') && (Fen[7][3] == '1') && (Fen[7][2] == 'K') && (Fen[7][1] == '1') && (Fen[7][0] == 'R')) { if (CheckKing(2, 7, WhiteKing)) return FALSE; if (CheckKing(3, 7, WhiteKing)) return FALSE; if (CheckKing(4, 7, WhiteKing)) return FALSE; *(DWORD*)&Fen[7][1] = 0x31524b31; // 1KR1 Fen[7][0] = '1'; wk = wqr = TRUE; return TRUE; } } } if (((cX2 == cX+1) || (cX2 == cX-1) || (cX2 == cX)) && ((cY2 == cY+1) || (cY2 == cY-1) || (cY2 == cY))) { wk = TRUE; return TRUE; } else return FALSE; } return FALSE; } int CheckKing(int KingX, int KingY, int King) { returned = 0; if (KingX) { // check left if (((Fen[KingY][KingX-1] == 'K') && (King == BlackKing)) || ((Fen[KingY][KingX-1] == 'k') && (King == WhiteKing))) return DiscoveredCheck; for (x = KingX-1; x >= 0; x--) { if (Fen[KingY][x] != '1') { if (((Fen[KingY][x] == 'R') && (King == BlackKing)) || ((Fen[KingY][x] == 'r') && (King == WhiteKing))) return EitherOne; if (((Fen[KingY][x] == 'Q') && (King == BlackKing)) || ((Fen[KingY][x] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } if (KingX < 7) { // check right if (((Fen[KingY][KingX+1] == 'K') && (King == BlackKing)) || ((Fen[KingY][KingX+1] == 'k') && (King == WhiteKing))) return DiscoveredCheck; for (x = KingX+1; x < 8; x++) { if (Fen[KingY][x] != '1') { if (((Fen[KingY][x] == 'R') && (King == BlackKing)) || ((Fen[KingY][x] == 'r') && (King == WhiteKing))) return EitherOne; if (((Fen[KingY][x] == 'Q') && (King == BlackKing)) || ((Fen[KingY][x] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } if (KingY < 7) { // check down if (((Fen[KingY+1][KingX] == 'K') && (King == BlackKing)) || ((Fen[KingY+1][KingX] == 'k') && (King == WhiteKing))) return DiscoveredCheck; for (y = KingY+1; y < 8; y++) { // top y is 0 if (Fen[y][KingX] != '1') { if (((Fen[y][KingX] == 'R') && (King == BlackKing)) || ((Fen[y][KingX] == 'r') && (King == WhiteKing))) return EitherOne; if (((Fen[y][KingX] == 'Q') && (King == BlackKing)) || ((Fen[y][KingX] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } if (KingY) { // check up if (((Fen[KingY-1][KingX] == 'K') && (King == BlackKing)) || ((Fen[KingY-1][KingX] == 'k') && (King == WhiteKing))) return DiscoveredCheck; for (y = KingY-1; y >= 0; y--) { // top y is 0 if (Fen[y][KingX] != '1') { if (((Fen[y][KingX] == 'R') && (King == BlackKing)) || ((Fen[y][KingX] == 'r') && (King == WhiteKing))) return EitherOne; if (((Fen[y][KingX] == 'Q') && (King == BlackKing)) || ((Fen[y][KingX] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } ///////// if ((KingX < 7) && (KingY > 0)) { // check up and right if ((King == WhiteKing) && (Fen[KingY-1][KingX+1] == 'p')) return EitherOne; if (((King == WhiteKing) && (Fen[KingY-1][KingX+1] == 'k')) || ((King == BlackKing) && (Fen[KingY-1][KingX+1] == 'K'))) return DiscoveredCheck; for (z = 1; ((KingY-z) >= 0) && ((KingX+z) < 8); z++) { if (Fen[KingY-z][KingX+z] != '1') { if (((Fen[KingY-z][KingX+z] == 'B') && (King == BlackKing)) || ((Fen[KingY-z][KingX+z] == 'b') && (King == WhiteKing))) return EitherOne; if (((Fen[KingY-z][KingX+z] == 'Q') && (King == BlackKing)) || ((Fen[KingY-z][KingX+z] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } if ((KingX > 0) && (KingY > 0)) { // check up and left if ((King == WhiteKing) && (Fen[KingY-1][KingX-1] == 'p')) return EitherOne; if (((King == WhiteKing) && (Fen[KingY-1][KingX-1] == 'k')) || ((King == BlackKing) && (Fen[KingY-1][KingX-1] == 'K'))) return DiscoveredCheck; for (z = 1; ((KingY-z) >= 0) && ((KingX-z) >= 0); z++) { if (Fen[KingY-z][KingX-z] != '1') { if (((Fen[KingY-z][KingX-z] == 'B') && (King == BlackKing)) || ((Fen[KingY-z][KingX-z] == 'b') && (King == WhiteKing))) return EitherOne; if (((Fen[KingY-z][KingX-z] == 'Q') && (King == BlackKing)) || ((Fen[KingY-z][KingX-z] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } if ((KingX > 0) && (KingY < 7)) { // check down and left if ((King == BlackKing) && (Fen[KingY+1][KingX-1] == 'P')) return EitherOne; if ((King == BlackKing) && (Fen[KingY+1][KingX-1] == 'K')) return DiscoveredCheck; for (z = 1; ((KingY+z) < 8) && ((KingX-z) >= 0); z++) { if (Fen[KingY+z][KingX-z] != '1') { if (((Fen[KingY+z][KingX-z] == 'B') && (King == BlackKing)) || ((Fen[KingY+z][KingX-z] == 'b') && (King == WhiteKing))) return EitherOne; if (((Fen[KingY+z][KingX-z] == 'Q') && (King == BlackKing)) || ((Fen[KingY+z][KingX-z] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } if ((KingX < 7) && (KingY < 7)) { // check down and right if ((King == BlackKing) && (Fen[KingY+1][KingX+1] == 'P')) return EitherOne; if ((King == BlackKing) && (Fen[KingY+1][KingX+1] == 'K')) return DiscoveredCheck; for (z = 1; ((KingY+z) < 8) && ((KingX+z) < 8); z++) { if (Fen[KingY+z][KingX+z] != '1') { if (((Fen[KingY+z][KingX+z] == 'B') && (King == BlackKing)) || ((Fen[KingY+z][KingX+z] == 'b') && (King == WhiteKing))) return EitherOne; if (((Fen[KingY+z][KingX+z] == 'Q') && (King == BlackKing)) || ((Fen[KingY+z][KingX+z] == 'q') && (King == WhiteKing))) return EitherOne; break; } } } // check check by a knight if (King == 200) Knight = 'n'; else Knight = 'N'; if (((KingY+2) < 8) && (KingX+1 < 8) && (Fen[KingY+2][KingX+1] == Knight)) returned = EitherOne; else if (((KingY+1) < 8) && (KingX+2 < 8) && (Fen[KingY+1][KingX+2] == Knight)) returned = EitherOne; else if (((KingY-1) >= 0) && (KingX+2 < 8) && (Fen[KingY-1][KingX+2] == Knight)) returned = EitherOne; else if (((KingY-2) >= 0) && (KingX+1 < 8) && (Fen[KingY-2][KingX+1] == Knight)) returned = EitherOne; else if (((KingY-2) >= 0) && (KingX-1 >= 0) && (Fen[KingY-2][KingX-1] == Knight)) returned = EitherOne; else if (((KingY-1) > 0) && (KingX-2 >= 0) && (Fen[KingY-1][KingX-2] == Knight)) returned = EitherOne; else if (((KingY+1) < 8) && (KingX-2 >= 0) && (Fen[KingY+1][KingX-2] == Knight)) returned = EitherOne; else if (((KingY+2) < 8) && (KingX-1 >= 0) && (Fen[KingY+2][KingX-1] == Knight)) returned = EitherOne; return returned; } void UpdateMoves(void) { for (x = 87; Fens[f][x] != ' '; x++) ; for (x++; Fens[f][x] != ' '; x++) ; for (x++, y = 0; Fens[f][x] != ' '; x++, y++) { if (y == 0) HalfMoves = Fens[f][x] - '0'; else if (y == 1) { HalfMoves *= 10; HalfMoves += Fens[f][x] - '0'; } } for (x++; Fens[f][x] != '\r'; x++) { FullMoves = Fens[f][x] - '0'; x++; if (Fens[f][x] == '\r') break; FullMoves *= 10; FullMoves += (Fens[f][x] - '0'); x++; if (Fens[f][x] == '\r') break; FullMoves *= 10; FullMoves += (Fens[f][x] - '0'); } } void ItsDiscoveredCheck(void) { if ((cX != cX2) || (cY != cY2)) { // move it back Fen[cY][cX] = MovedPiece; Fen[cY2][cX2] = ReplacedPiece; if (MovedPiece == 'K') { WhiteKingX = cX; WhiteKingY = cY; } else if (MovedPiece == 'k') { BlackKingX = cX; BlackKingY = cY; } } itscheck = FALSE; itsdiscoveredcheck = TRUE; fen = ReplacedPiece; // for InCommon } void CheckBothKings(KingX, KingY, King) { returned = CheckKing(KingX, KingY, King); if (returned == Check) itscheck = TRUE; if (returned == EitherOne) { if (WhitesMove) { if (King == BlackKing) itscheck = TRUE; else if (!frompromoted) ItsDiscoveredCheck(); else itscheck = TRUE; } else { if (King == WhiteKing) itscheck = TRUE; else if (!frompromoted) ItsDiscoveredCheck(); else itscheck = TRUE; } } else if (returned == DiscoveredCheck) ItsDiscoveredCheck(); } int CALLBACK PromotionProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: CheckRadioButton(hwndDlg, IDC_RADIO1, IDC_RADIO4, IDC_RADIO1); SetFocus(hwndDlg); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO1)) Promoted = 'Q'; else if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO2)) Promoted = 'R'; else if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO3)) Promoted = 'B'; else if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO4)) Promoted = 'N'; if (cY2 == 0) Fen[cY2][cX2] = Promoted; else if (cY2 = 7) Fen[cY2][cX2] = Promoted + 0x20; EndDialog (hwndDlg, TRUE); return TRUE; } } return 0; } int CALLBACK CheckProc(HWND hwndCheck, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_LBUTTONDOWN) DestroyWindow(hwndCheck); else if (message == WM_DESTROY) itscheck = FALSE; return 0; } int CALLBACK CheckMateProc(HWND hwndCheckMate, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_LBUTTONDOWN) DestroyWindow(hwndCheckMate); else if (message == WM_DESTROY) checkmate = FALSE; return 0; } void GetFensData(void) { // if the below are FALSE, they indicate that those pieces can castle! wk = wkr = wqr = bk = bkr = bqr = TRUE; x = 87; if (Fens[f][x] == 'K') { wk = wkr = FALSE; x++; } if (Fens[f][x] == 'Q') { wk = wqr = FALSE; x++; } if (Fens[f][x] == 'k') { bk = bkr = FALSE; x++; } if (Fens[f][x] == 'q') { bk = bqr = FALSE; x++; } x++; // past space if (Fens[f][x] == ' ') // happens with no KQkq x++; if (Fens[f][x] != '-') { EnPassant[0] = Fens[f][x]; EnPassant[1] = Fens[f][x+1]; } } void Enpassant(int x) { Fens[f][x++] = ' '; Fens[f][x++] = EnPassant[0]; if (EnPassant[0] != '-') Fens[f][x++] = EnPassant[1]; Fens[f][x++] = ' '; for (y = 13, z = 0; Fens[f][y] != ' '; y++) { if (Fens[f][y] == '1') z++; } if (z == NumberOfOnes+1) { NumberOfOnes = z; HalfMoves = 0; } else if ((Fen[cY2][cX2] != 'P') && (Fen[cY2][cX2] != 'p')) HalfMoves++; else HalfMoves = 0; if (HalfMoves < 10) Fens[f][x++] = (char)(HalfMoves + '0'); else { Fens[f][x++] = (char)((HalfMoves/10) + '0'); Fens[f][x++] = (char)((HalfMoves%10)+ '0'); } Fens[f][x++] = ' '; if (FullMoves < 10) Fens[f][x++] = (char)(FullMoves + '0'); else if (FullMoves <= 99) { Fens[f][x++] = (char)((FullMoves/10) + '0'); Fens[f][x++] = (char)((FullMoves%10)+ '0'); } else { Fens[f][x++] = (char)((FullMoves/100) + '0'); Fens[f][x++] = (char)(((FullMoves%100)/10) + '0'); Fens[f][x++] = (char)((FullMoves%10)+ '0'); } Fens[f][x++] = '\r'; Fens[f][x++] = '\n'; Fens[f][x++] = 0; endoffens = x; } void PlacePiece(WPARAM wParam) { if (wParam == VK_DELETE) piece = '1'; else { piece = wParam; if (!Shifted) piece += 0x20; // make lower case } cX = xPos / SquareSize; cY = yPos / SquareSize; if (rotated) { cX = 7 - cX; cY = 7 - cY; } Fen[cY][cX] = piece; // xPos & yPos from WM_MOUSEMOVE Fens[f][13+(9*cY)+cX] = piece; for (x = 0; Fens[f][x] != 0; x++) ; endoffens = x+1; OpenClipboard(hwnd); EmptyClipboard(); hGlob = LocalAlloc(GMEM_FIXED, 108); // (divisible by 4) GlobalAlloc strncpy((char*)hGlob, Fens[f], endoffens); // endoffens from Enpassant hClipboard = SetClipboardData(CF_TEXT, hGlob); CloseClipboard(); movingPiece = FALSE; InvalidateRect(hwnd, &rect, FALSE); } void LeftRight(void) { GetFensData(); x = 13; for (z = 0; z < 8; z++) { // update Fen from Fens for (y = 0; y < 8; y++) Fen[z][y] = Fens[f][x++]; x++; } if (Fens[f][85] == 'w') { WhitesMove = TRUE; SetWindowText(hwnd, WhiteMoves); } else if (Fens[f][85] == 'b') { WhitesMove = FALSE; SetWindowText(hwnd, BlackMoves); } DestroyWindow(hwndCheck); if (checkmate) DestroyWindow(hwndCheckMate); leftright = TRUE; if (Fens[f][0] == 'C') hwndCheck = CreateDialog(hInst, TEXT("CHECK"), hwnd, (DLGPROC)CheckProc); else if (hwndCheck) DestroyWindow(hwndCheck); if (Fens[f][1] == 'M') hwndCheckMate = CreateDialog(hInst, TEXT("CHECKMATE"), hwnd, (DLGPROC)CheckMateProc); else if (hwndCheckMate) DestroyWindow(hwndCheckMate); InvalidateRect(hwnd, &rect, FALSE); UpdateWindow(hwnd); } void InCommon(void) { for (BlackKingY = 0; BlackKingY < 8; BlackKingY++) { for (BlackKingX = 0; BlackKingX < 8; BlackKingX++) { if (Fen[BlackKingY][BlackKingX] == 'k') { BlackKingcX = BlackKingX; BlackKingcY = BlackKingY; } } } for (WhiteKingY = 0; WhiteKingY < 8; WhiteKingY++) { for (WhiteKingX = 0; WhiteKingX < 8; WhiteKingX++) { if (Fen[WhiteKingY][WhiteKingX] == 'K') { WhiteKingcX = WhiteKingX; WhiteKingcY = WhiteKingY; } } } CheckBothKings(BlackKingcX, BlackKingcY, BlackKing); // for check or discovered check CheckBothKings(WhiteKingcX, WhiteKingcY, WhiteKing); if (itsdiscoveredcheck) { itsdiscoveredcheck = FALSE; Fen[cY][cX] = MovedPiece; Fen[cY2][cX2] = ReplacedPiece; if (enpassant1) { // put white pawn back Fen[cY2-1][cX2] = 'P'; } else if (enpassant2) { // put black pawn back Fen[cY2+1][cX2] = 'p'; } choosePiece = FALSE; movingPiece = FALSE; InvalidateRect(hwnd, &rect, FALSE); return; } else { WhitesMove ^= 1; if (WhitesMove) SetWindowText(hwnd, WhiteMoves); else SetWindowText(hwnd, BlackMoves); if (choosePiece) { choosePiece = FALSE; promoted = TRUE; DialogBox(hInst, TEXT("PROMOTION"), hwnd, PromotionProc); } } if (Promoted == 'x') // not a promoted pawn Fen[cY2][cX2] = fen; // moved piece else { Promoted = 'x'; frompromoted = TRUE; if (cY2 == 0) CheckBothKings(BlackKingcX, BlackKingcY, BlackKing); // for itscheck else if (cY2 == 7) CheckBothKings(WhiteKingcX, WhiteKingcY, WhiteKing); frompromoted = FALSE; } f++; fBiggest = f; for (x = 0; x < 13; x++) Fens[f][x] = OrigFenString[x]; for (z = 0; z < 8; z++) { // update Fens from Fen for (y = 0; y < 8; y++) Fens[f][x++] = Fen[z][y]; Fens[f][x++] = '/'; } Fens[f][x-1] = ' '; if (WhitesMove) { Fens[f][x++] = 'w'; FullMoves++; } else Fens[f][x++] = 'b'; Fens[f][x++] = ' '; if ((ReplacedPiece == 'r') && (cX2 == 7) && (cY2 == 0)) bkr = TRUE; else if ((ReplacedPiece == 'r') && (cX2 == 0) && (cY2 == 0)) bqr = TRUE; else if ((ReplacedPiece == 'R') && (cX2 == 7) && (cY2 == 7)) wkr = TRUE; else if ((ReplacedPiece == 'R') && (cX2 == 0) && (cY2 == 7)) wqr = TRUE; if (bkr && bqr) bk = TRUE; if (wkr && wqr) wk = TRUE; y = x; // 87 (KQkq or whatever) if ((wk == FALSE) && (wkr == FALSE)) Fens[f][x++] = 'K'; if ((wk == FALSE) && (wqr == FALSE)) Fens[f][x++] = 'Q'; if ((bk == FALSE) && (bkr == FALSE)) Fens[f][x++] = 'k'; if ((bk == FALSE) && (bqr == FALSE)) Fens[f][x++] = 'q'; if (x == y) Fens[f][x++] = '-'; if ((cY == 1) && (cY2 == 3) && (Fen[cY2][cX2] == 'p')) { // show en passant is possible EnPassant[0] = Letters[cX]; EnPassant[1] = '6'; Enpassant(x); } else if ((cY == 6) && (cY2 == 4) && (Fen[cY2][cX2] == 'P')) { // show en passant is possible EnPassant[0] = Letters[cX]; EnPassant[1] = '3'; Enpassant(x); } else { EnPassant[0] = '-'; EnPassant[1] = '-'; Enpassant(x); } OpenClipboard(hwnd); EmptyClipboard(); hGlob = LocalAlloc(GMEM_FIXED, 108); // (divisible by 4) GlobalAlloc strncpy((char*)hGlob, Fens[f], endoffens); // endoffens from Enpassant hClipboard = SetClipboardData(CF_TEXT, hGlob); CloseClipboard(); movingPiece = FALSE; InvalidateRect(hwnd, &rect, FALSE); UpdateWindow(hwnd); //check for CHECKMATE: if (chessengine) { for (x = 0; Fens[f][x] != 0; x++) ; WriteFile(IN_Wr, Fens[f], x, &dwBytesWritten, NULL); WriteFile(IN_Wr, "go depth 1\r\n\0", 12, &dwWritten, NULL); for (fook2 = 0; fook2 < 1000000; fook2++) { fileSize = GetFileSize(OUT_Rd, NULL); if (!fileSize) continue; ReadFile(OUT_Rd, cBuf, fileSize, &dwRead, NULL); done = FALSE; for (x = 0; x < (int)dwRead; x++) { if ((*(DWORD*)&cBuf[x] == 0x31613161) && (*(WORD*)&cBuf[x-3] == 0x7670)) { // "pv a1a1" done = TRUE; break; } if ((0x74736562 == *(DWORD*)&cBuf[x]) && (0x65766F6D == *(DWORD*)&cBuf[x+4])) // bestmove break; } if (done) break; Sleep(5); if ((x < (int)dwRead) && !done) { // if "bestmove" found X = cBuf[x+9] - 'a'; X2 = cBuf[x+11] - 'a'; Y = '8' - cBuf[x+10]; Y2 = '8' - cBuf[x+12]; if (((X == X2) && (Y == Y2)) || (X > 7) || (X < 0) || (PrevBestMove == *(DWORD*)&cBuf[x+9])) done = TRUE; PrevBestMove = *(DWORD*)&cBuf[x+9]; break; } } if (fook2 >= 1000000) MessageBox(hwnd, "This chess engine doesn't indicate checkmate!", "", MB_OK); if (done) { done = FALSE; if (itscheck) { Fens[f][1] = 'M'; checkmate = TRUE; hwndCheckMate = CreateDialog(hInst, TEXT("CHECKMATE"), hwnd, (DLGPROC)CheckMateProc); } } else if (itscheck) { Fens[f][0] = 'C'; hwndCheck = CreateDialog(hInst, TEXT("CHECK"), hwnd, (DLGPROC)CheckProc); } } // end of if (chessengine) else if (itscheck) { Fens[f][0] = 'C'; hwndCheck = CreateDialog(hInst, TEXT("CHECK"), hwnd, (DLGPROC)CheckProc); } Sleep(5); SetFocus(hwnd); // this has to be here for a necessary delay after CHECK or CHECKMATE } void LoadChessEngine(void) { if (INVALID_HANDLE_VALUE != (hFile = CreateFile(CurrentEngine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))) { if (fileSize = GetFileSize(hFile, NULL)) { for (x = 0; x < MAX_PATH; x++) ChessEngine[x] = 0; ReadFile(hFile, ChessEngine, fileSize, &dwBytesRead, NULL); // current engine name CloseHandle(hFile); hFile = NULL; if (INVALID_HANDLE_VALUE != FindFirstFile(ChessEngine, &fd)) { saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; CreatePipe(&OUT_Rd, &OUT_Wr, &saAttr, 0); CreatePipe(&IN_Rd, &IN_Wr, &saAttr, 0); SetHandleInformation(OUT_Rd, HANDLE_FLAG_INHERIT, 0); SetHandleInformation(IN_Wr, HANDLE_FLAG_INHERIT, 0); ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdOutput = OUT_Wr; siStartInfo.hStdInput = IN_Rd; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; if (0 != CreateProcess(ChessEngine, ChessEngine, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo, &piProcInfo)) { CloseHandle(piProcInfo.hProcess); // these are the normal procedures CloseHandle(piProcInfo.hThread); CloseHandle(OUT_Wr); CloseHandle(IN_Rd); } chessengine = TRUE; notfound = FALSE; } } else MessageBox(hwnd, "Filesize is 0", ChessEngine, MB_OK); } else notfound = TRUE; }