A Clean Sweep on Minesweeper (Botting)

Share Your Own Code Samples With the World

Moderators: g3nuin3, SpeedWing, WhiteHat, mezzo

A Clean Sweep on Minesweeper (Botting)

Postby L. Spiro » Fri Dec 01, 2006 3:55 am

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
Last edited by L. Spiro on Tue Oct 07, 2008 7:18 pm, edited 2 times in total.
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby gibxam » Tue Oct 07, 2008 10:02 am

L. Spiro, This post is exactly what I was looking for in my other post. However my minesweeper is version 5.1, is this why the script does not solve my minesweeper? How would I edit the script to solve the current one I have?

-Max
User avatar
gibxam
Acker
 
Posts: 51
Joined: Mon Oct 06, 2008 3:19 am

Postby L. Spiro » Tue Oct 07, 2008 11:34 am

It has no problem solving 5.1.

Be sure you have done everything correctly.


L. Spiro
Our songs remind you of songs you’ve never heard.
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby gibxam » Tue Oct 07, 2008 1:00 pm

I have double checked my own code and the problem did not go away so I copied and pasted your code and the problem still persists. The mouse moves and clicks however it clicks on the wrong squares so I lose. Here is the script for the hot key I am using although I'm not sure if this is where the problem lies.

Code: Select all
VOID On_HK_WINMINE_EXE_0( DWORD dw1, DWORD dw2 ) {

SolveMinesweeperBoard();   
}


The only thing I changed in your code was I turned the sleep on to see if the mouse was in fact working and this test confirmed that the mouse is working however it is clicking on the wrong squares. One observation I made was that it appeared like the mouse is moving along the lines of the squares rather than the squares themselves. Would this be a problem?

Thank you for the quick replies so far,

-Max
User avatar
gibxam
Acker
 
Posts: 51
Joined: Mon Oct 06, 2008 3:19 am

Postby L. Spiro » Tue Oct 07, 2008 7:19 pm

The code above has been updated.


L. Spiro
Our songs remind you of songs you’ve never heard.
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby gibxam » Wed Oct 08, 2008 11:06 am

Cool, Thank you L. Spiro everything works great now :),

I have some questions on your script pertaining to this part of your code

Code: Select all
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 );


1. I see that you defined e_bwSize to be a struct of the type BOARDSIZE then you set e_bwSize.iWidth = "winmine.exe"? and e_bwSize.iHeight = 0x5334. Is this correct?

2. If I am correct in question 1 what is "winmine.exe" and 0x5334? They would both have to be integers. Is this correct?

3. What are 0x5334 and 0x5361? Are they addresses?

4. Why is e_pbBoard[] an extern byte instead of an int? and again why do you pass "winmine.exe" and 0x5361 to create the 2d array?

Thank you very much for taking the time to read this L. Spiro (or anyone else) and thank you for updating the code I am very thankful,

-Max
User avatar
gibxam
Acker
 
Posts: 51
Joined: Mon Oct 06, 2008 3:19 am

Postby L. Spiro » Wed Oct 08, 2008 12:04 pm

#1: No. Read about extern variables in the help file.
#2: Help file.
#3: Offsets, as covered in the help file.
#4: Because it is an array of bytes inside Minesweeper.


L. Spiro
Our songs remind you of songs you’ve never heard.
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby gibxam » Tue Oct 14, 2008 11:03 am

Thank you very much for your help L. Sprio for anyone who is reading this I have the answers to my questions (I am sure I will be corrected if I am mistaken :) ).

1. My assumption is obviously not correct. e_bowSize is an external structure that is created in memory at the location [winmine.exe + 0x5334].

2. I am also wrong here. As stated above winmine.exe and 0x5334 together represent an address in memory. Winmine.exe may be loaded in memory at different locations locations as it is run and rerun, however the distance from the "base" of winmine.exe to the location of the address that points to the width and height of the minesweeper board will remain the same. Because of this we can say [base + offset] in this case [winmine.exe + 0x5334].

3. Same explanation as above, 0x5334 and 0x5361 are offsets A.K.A distances from the base of winmine.exe.

4. L. Sprio answered this. e_pbBoard[32*32] is an external 2darray of bytes in memory. You can look up what 2d arrays are I know if you have learned anything about C++ they are bound to come up.

I hope everything in this is accurate and I hope this helps some people with perhaps the same questions I had. :)

Now for some more questions :D :

1. Does StrICmp return 0 if parameter 1 is not equal to parameter 2?

2. Does ShowWindowAsync only unminimize/ display the minesweeper window while SetForegroundWindow allows you to click or send keyboard input to the window? It seems like SetForegroundWindow could do the job that ShowWindowAsync does plus more thus not even needing ShowWindowAsync.

3. How do you know that [winmine.exe + 0x5334] is where to put the struct you declare? I looked at this in MHS and it looks like it holds the width rather than both. How can you tell it is a struct?

Thats all for now, I am very grateful for all your help L. Spiro. My dad is helping me set up a paypal account soon. And I am going to donate for sure. JW what is a helpful realistic donation that a member should make?

-Max
User avatar
gibxam
Acker
 
Posts: 51
Joined: Mon Oct 06, 2008 3:19 am

Postby L. Spiro » Tue Oct 14, 2008 11:57 am

#1: StrICmp returns 0 if the strings are the same. It works the same way as the C library functions.

#2: ShowWindowAsync() can be researched in more detail online. It can be used to minimize, maximize, etc., windows.

#3: It was my decision to make it a struct. It could have been mapped with 2 separate extern DWORD values, but since a single structure can map both DWORD values together and requires only one declaration, it is easier to use.

#4: Donations go to help me pay my student loan, which is $125 per month. Donations of this size or more are the most helpful. Some have donated $200.
If this seems too huge, $50 still helps. Everything helps.


L. Spiro
Our songs remind you of songs you’ve never heard.
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby toffey » Sat Oct 18, 2008 5:11 pm

I'm quite new to all this, but I am very interested in how I would actually implement this? What exactly do I do with the code?
User avatar
toffey
Hack-Master Hex
 
Posts: 689
Joined: Fri Sep 05, 2008 5:39 pm
Location: California, USA

Postby L. Spiro » Sat Oct 18, 2008 6:18 pm

Creating and running scripts is fully explained in the help file.


L. Spiro
Our songs remind you of songs you’ve never heard.
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Re: A Clean Sweep on Minesweeper (Botting)

Postby Mysticalp » Thu May 28, 2009 2:22 am

L. Spiro wrote:
The script also works with keyboard and joystick events, allowing you to make interactive bots for any game.


L. Spiro


How do you send joystick events?
Mysticalp
I Have A Few Questions
 
Posts: 7
Joined: Wed May 27, 2009 10:54 pm

Postby L. Spiro » Thu May 28, 2009 6:57 am

Research SendInput().
If the description in the help file is insufficient, use Google for examples, or refer to the MSDN. It is all the same as in L. Spiro Script.


L. Spiro
Our songs remind you of songs you’ve never heard.
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby Mysticalp » Thu May 28, 2009 10:13 pm

OK, sorry, it was just that in the help file for this function said keyboard and mouse. I didn't think it was the same standard function. Some investigation work to do now...
Mysticalp
I Have A Few Questions
 
Posts: 7
Joined: Wed May 27, 2009 10:54 pm


Return to Code Submissions

Who is online

Users browsing this forum: No registered users and 0 guests