- Code: Select all
VOID SolveMinesweeperBoard() {
// “extern” only works if we are attached to the process.
if ( StrICmp( GetCurProcessName(), "winmine.exe" ) != 0 ) {
PrintF( "You must be attached to Minesweeper to solve the board!" );
return;
}
HWND hWnd = FindWindow( "Minesweeper" );
if ( !hWnd ) { return; }
// If the user is holding certain keys it will cause problems when we try to send clicks
// to the Minesweeper board. Release problematic keys. Even if the user is still holding
// them, this forces them to be “released”.
KeyboardEvent( VK_SHIFT, KEYEVENTF_KEYUP );
KeyboardEvent( VK_CONTROL, KEYEVENTF_KEYUP );
KeyboardEvent( VK_MENU, KEYEVENTF_KEYUP );
// Put the Minesweeper board in front if possible.
ShowWindowAsync( hWnd, SW_RESTORE );
while ( GetForegroundWindow() != hWnd ) { SetForegroundWindow( hWnd ); Sleep( 10 ); }
// Get its position.
INT iX;
INT iY;
GetWindowPos( hWnd, &iX, &iY );
PrintF( "Minesweeper board located at %d %d.", iX, iY );
if ( iX < 0 || iY < 0 ) {
PrintF( "Minesweeper board is out of range!" );
return;
}
extern struct BOARDSIZE {
INT iWidth;
INT iHeight;
} e_bwSize = { "winmine.exe", 0x5334 }; // The width and height of the board.
extern BYTE e_pbBoard[32*32] = { "winmine.exe", 0x5361 }; // The board array itself.
// Note that 32*32 here is meaningless,
// except to show us how large the
// array is in the target process (it
// does not actually declare the array
// in the target process; it already
// exists).
PrintF( "Minesweeper size %d %d.", e_bwSize.iWidth, e_bwSize.iHeight );
POINT pClick;
// To calculate the final click positions we need the screen
// resolution.
INT iScreenW = GetPrimScreenWidth();
INT iScreenH = GetPrimScreenHeight();
// System settings change the location of mines on the board, so
// get the settings needed to know where to click.
INT iBorderHeight = GetSystemMetrics( SM_CYEDGE ); // Window border (height).
INT iCaptionHeight = GetSystemMetrics( SM_CYCAPTION ); // Title bar height.
INT iMenuHeight = GetSystemMetrics( SM_CYMENU ); // Menu height.
INT iFinalYOffset = iBorderHeight + iCaptionHeight + iMenuHeight;
INT iFinalXOffset = GetSystemMetrics( SM_CXEDGE ); // Window border (width).
// Save the externs to locals. This makes it faster to scan the
// board.
INT iBoardWidth = e_bwSize.iWidth;
INT iBoardHeight = e_bwSize.iHeight;
// Run through the board and click on each square that has no mine.
for ( INT J = 0; J < iBoardHeight; J++ ) {
for ( INT I = 0; I < iBoardWidth; I++ ) {
if ( (e_pbBoard[(32*J)+I] & 0x80) == 0 ) {
GetClickPos( iFinalXOffset, iFinalYOffset, iX, iY, &pClick, I, J );
// Translate the click position into the actual screen coordinates (Windows®
// forces us to do this).
pClick.x = pClick.x * 65535.0f / iScreenW;
pClick.y = pClick.y * 65535.0f / iScreenH;
// Move there.
MouseEvent( MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
pClick.x, pClick.y,
0 );
// Click there (down and up).
MouseEvent( MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN,
0, 0, // X and Y positions aren’t used.
0 );
MouseEvent( MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP,
0, 0,
0 );
// Optionally sleep for a bit in case you like to see the action unfold.
//Sleep( 1 );
}
}
}
}
// Constants that tell us the dimensions of the board.
const INT iSquareSize = 16; // Size of the actual squares we click.
const INT iXOff = 14; // Offset to the left-most square from the border.
const INT iYOff = 56; // Offset to the top-most square from the bottom of the menu.
const INT iFinalX = iXOff + (iSquareSize / 2);// The final click offset (X).
const INT iFinalY = iYOff + (iSquareSize / 2);// The final click offset (Y).
VOID GetClickPos( INT iScreenOffX, INT iScreenOffY, INT iPosX, INT iPosY, POINT * ppRet, INT iX, INT iY ) {
// The window is at (iPosX, iPosY). From there, go to the corner of the board
// and then offset based on which square we are hitting.
// iScreenOffX and iScreenOffY are derived by using system settings to get the
// border, caption, and menu widths/heights.
ppRet->x = iPosX + iX * iSquareSize + iFinalX + iScreenOffX;
ppRet->y = iPosY + iY * iSquareSize + iFinalY + iScreenOffY;
}
This code sample works in Demo #6 and above.
This little bit will play your Minesweeper game for you.
Follow the code to see how it gets the window position of the game, then scrolls through the board and decides which squares to click, then how it clicks them.
The script also works with keyboard and joystick events, allowing you to make interactive bots for any game.
L. Spiro