Jump to content

Minesweeper UDF


jvanegmond
 Share

Recommended Posts

I felt I needed a break from all the serious programming and went back to botting in AutoIt. This time botting a simple game, minesweeper.

The UDF could probably be used in a programming/AI class. The bot shows how fast and how simple you can beat minesweeper.

Pay attention: Only tested on XP SP3, doesn't work on Vista because the game looks very different (pixel wise).

examplebot.au3

#include "minesweeper.au3"

Opt("WinTitleMatchMode", 4)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)

HotKeySet("{ESC}","_Exit") ;; Emergency exit

Local $mGW = 16 ; My grid width
Local $mGH = 16 ; My grid heigth

Local $mStuck = 0

_WinMine_Initialize()

_WinMine_SetupGame("Intermediate")

_WinMine_SetSpeed(0)

While _WinMine_Loop()
    If ( _WinMine_HasDied() ) Then
        
        _WinMine_NewGame()
        
    EndIf
    
    If ( _WinMine_HasWon() ) Then
        
        MsgBox(0x40, "Minesweeper bot", "Hey, I won! :D")
        Exit
        
    EndIf

    _WinMine_ReadMines()
    
    If (_WinMine_CountMines($MINE_UNKNOWN) <= (($mGW*$mGH)-100)) Then
        
        $mStuck += 1 ; pretends to be stuck at the moment, until something is done
        
        For $x = 0 to $mGW-1
            For $y = 0 to $mGH-1
                
                _CheckMine($x,$y)
                
            Next
        Next
        
        If ( $mStuck == 5 ) Then
            ;If ( MsgBox(0x4,"Minesweeper bot", "I appear to be stuck! Should I make a gamble?") == 0x6 ) Then
                
                _RandomClickMine()
                $mStuck = 0
                
            ;EndIf
        EndIf
    Else
        ;; Randomly open up mines
        
        _WinMine_ClickMine(Random(1,$mGW-1,1),Random(1,$mGH-1,1))
        
    EndIf
WEnd

Func _RandomClickMine()
    Local $a = 1
    While 1
        
        For $x = 0 to $mGW-1
            For $y = 0 to $mGH-1
                If (_WinMine_GetMine($x,$y) == $MINE_UNKNOWN) Then
                    $surrounding = _WinMine_CountSurroundingMines($x, $y, $MINE_UNKNOWN)
                    
                    If $surrounding < $a Then
                        _WinMine_ClickMine($x,$y)
                        
                        _WinMine_ReadMines()
                        Return
                    EndIf
                EndIf
            Next
        Next
        
        $a += 1
        
        If ( $a == 20 ) Then
            Return
        EndIf
    WEnd
EndFunc

Func _CheckMine($x,$y)
    $thisMine = _WinMine_GetMine($x,$y)
    
    Switch $thisMine
        Case $MINE_BOMB, $MINE_EMPTY, $MINE_UNKNOWN
            
            Return
            
        Case $MINE_ONE
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ( $mines_nearby == 1 AND $flags_nearby == 0 ) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
        Case $MINE_TWO
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ($mines_nearby == 1 AND $flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby = 2 AND $flags_nearby == 0) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 2) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
        Case $MINE_THREE
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ($mines_nearby == 1 AND $flags_nearby == 2) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 2 AND $flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 3 AND $flags_nearby == 0) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 3) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
        Case $MINE_FOUR
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ($mines_nearby == 1 AND $flags_nearby == 3) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 2 AND $flags_nearby == 2) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 3 AND $flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 4 AND $flags_nearby == 0) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 4) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
    EndSwitch
EndFunc

;; A function for emergency exit
Func _Exit()
    Exit
EndFunc
Edited by Manadar
Link to comment
Share on other sites

And a bot that automatically does expert level, I have a feeling people are going to ask for this.

#include "minesweeper.au3"

Opt("WinTitleMatchMode", 4)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)

HotKeySet("{ESC}","_Exit") ;; Emergency exit

Local $mGW = 30 ; My grid width
Local $mGH = 16 ; My grid heigth

Local $mStuck = 0

_WinMine_Initialize()

_WinMine_SetupGame("Expert")

_WinMine_SetSpeed(0)

While _WinMine_Loop()
    If ( _WinMine_HasDied() ) Then
        
        _WinMine_NewGame()
        
    EndIf
    
    If ( _WinMine_HasWon() ) Then
        
        MsgBox(0x40, "Minesweeper bot", "Hey, I won! :D")
        Exit
        
    EndIf

    _WinMine_ReadMines()
    
    If (_WinMine_CountMines($MINE_UNKNOWN) <= (($mGW*$mGH)-100)) Then
        
        $mStuck += 1 ; pretends to be stuck at the moment, until something is done
        
        For $x = 0 to $mGW-1
            For $y = 0 to $mGH-1
                
                _CheckMine($x,$y)
                
            Next
        Next
        
        If ( $mStuck == 5 ) Then
            ;If ( MsgBox(0x4,"Minesweeper bot", "I appear to be stuck! Should I make a gamble?") == 0x6 ) Then
                
                _RandomClickMine()
                $mStuck = 0
                
            ;EndIf
        EndIf
    Else
        ;; Randomly open up mines
        
        _WinMine_ClickMine(Random(1,$mGW-1,1),Random(1,$mGH-1,1))
        
    EndIf
WEnd

Func _RandomClickMine()
    Local $a = 1
    While 1
        
        For $x = 0 to $mGW-1
            For $y = 0 to $mGH-1
                If (_WinMine_GetMine($x,$y) == $MINE_UNKNOWN) Then
                    $surrounding = _WinMine_CountSurroundingMines($x, $y, $MINE_UNKNOWN)
                    
                    If $surrounding < $a Then
                        _WinMine_ClickMine($x,$y)
                        
                        _WinMine_ReadMines()
                        Return
                    EndIf
                EndIf
            Next
        Next
        
        $a += 1
        
        If ( $a == 20 ) Then
            Return
        EndIf
    WEnd
EndFunc

Func _CheckMine($x,$y)
    $thisMine = _WinMine_GetMine($x,$y)
    
    Switch $thisMine
        Case $MINE_BOMB, $MINE_EMPTY, $MINE_UNKNOWN
            
            Return
            
        Case $MINE_ONE
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ( $mines_nearby == 1 AND $flags_nearby == 0 ) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
        Case $MINE_TWO
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ($mines_nearby == 1 AND $flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby = 2 AND $flags_nearby == 0) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 2) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
        Case $MINE_THREE
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ($mines_nearby == 1 AND $flags_nearby == 2) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 2 AND $flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 3 AND $flags_nearby == 0) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 3) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
        Case $MINE_FOUR
            
            $mines_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_UNKNOWN)
            $flags_nearby = _WinMine_CountSurroundingMines($x,$y,$MINE_FLAG)
            
            If ( $mines_nearby == 0) Then Return ;; Some speed improvement
            
            If ($mines_nearby == 1 AND $flags_nearby == 3) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 2 AND $flags_nearby == 2) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 3 AND $flags_nearby == 1) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($mines_nearby == 4 AND $flags_nearby == 0) Then
                $mStuck = 0
                _WinMine_FlagSurroundingMines($x,$y)
            ElseIf ($flags_nearby == 4) Then
                $mStuck = 0
                _WinMine_OpenSurroundingMines($x,$y)
            EndIf
            
    EndSwitch
EndFunc

;; A function for emergency exit
Func _Exit()
    Exit
EndFunc
Edited by Manadar
Link to comment
Share on other sites

As soon as it sees the minesweeper window, it crashes with the following error message...

---------------------------
AutoIt Error
---------------------------
Line 257  (File "C:\Users\Draygoes\Desktop\minesweeper.au3"):

$b += PixelGetColor($a[0],$a[1]+$i,$hWnd)
$b += PixelGetColor($a^ ERROR

Error: Subscript used with non-Array variable.
---------------------------
OK   
---------------------------

EDIT

This is in Vista btw.

If you want a copy of the Vista version of mine sweeper, just let me know and I can send it to you via pm...

Edited by Draygoes
Spoiler

 

"If a vegetarian eats vegetables,What the heck does a humanitarian eat?"

"I hear voices in my head, but I ignore them and continue on killing."

"You have forced me to raise the indifference warning to beige, it's a beige alert people. As with all beige alerts please prepare to think about the possibility of caring."

An optimist says that giving someone power DOESN'T immediately turn them into a sadist. A pessimist says that giving someone power doesn't IMMEDIATELY turn them into a sadist.

 

 
Link to comment
Share on other sites

If you want a copy of the Vista version of mine sweeper, just let me know and I can send it to you via pm...

I just got a Vista machine yesterday, so I'm happy to try it on that. It's probably a slight difference in the color or box sizes. That can be adjusted.

Works Great for me this is awesome.

Edit: It hasn't beat expert yet most it got down to is 23 Mines.

Thank you. The detection rules for the example bot aren't really fit for Expert. I've written the bot for intermediate mostly, but you can try yours for expert using the UDF. It's quite simple to use as you can see. :mellow:
Link to comment
Share on other sites

I just got a Vista machine yesterday, so I'm happy to try it on that. It's probably a slight difference in the color or box sizes. That can be adjusted.

Thank you. The detection rules for the example bot aren't really fit for Expert. I've written the bot for intermediate mostly, but you can try yours for expert using the UDF. It's quite simple to use as you can see. :mellow:

I think i will i might edit it to be able to choose the level at run time and even choose a custom level.

Using your version it got down to 3 mines and then clicked on a mine and lost the game.

Link to comment
Share on other sites

I think i will i might edit it to be able to choose the level at run time and even choose a custom level.

Using your version it got down to 3 mines and then clicked on a mine and lost the game.

It has a random function that kicks in when it gets stuck. I should be using probability calculations, but once I had all this I thought it was time to let someone else play with the UDF.

If you are going to work with this, please don't modify the UDF, if you need any other functions write them in your own script. I also rather wouldn't have you edit the examplebot with a simple GUI.

The idea of this is to let programmers / students play with this as an introduction to AI: Not to finish minesweeper.

Link to comment
Share on other sites

It has a random function that kicks in when it gets stuck. I should be using probability calculations, but once I had all this I thought it was time to let someone else play with the UDF.

If you are going to work with this, please don't modify the UDF, if you need any other functions write them in your own script. I also rather wouldn't have you edit the examplebot with a simple GUI.

The idea of this is to let programmers / students play with this as an introduction to AI: Not to finish minesweeper.

No wukkas buddy I would keep any changes to the udf to myself anyway. I am I guess you could say a "student" of AutoIT and at the same time my own teacher. So thank you for this great script it is helping me learn pixel related things I wanted to learn.

Daniel.

Link to comment
Share on other sites

No wukkas buddy I would keep any changes to the udf to myself anyway. I am I guess you could say a "student" of AutoIT and at the same time my own teacher. So thank you for this great script it is helping me learn pixel related things I wanted to learn.

Daniel.

Thank you. I am glad it's found its purpose already. :mellow:
Link to comment
Share on other sites

i tested it worked great!

only problem was that i needed to change the word minesweeper into my own language.

i dont know if this is correct, but when your bot finished the game and all the mines were flagged it started clicking and found a mine.. possible?

Link to comment
Share on other sites

Using your version it got down to 3 mines and then clicked on a mine and lost the game.

Random function was bugged and therefore it lost on Expert quite a lot. Now I've fixed it it actually finishes Expert quite a lot.

Update:

× Added _WinMine_SetSpeed ( 0 value for fast, 1 for normal, 2 for snail)

× Added more speed

× Fixed _RandomClickMine which was causing it to lose on expert.

i dont know if this is correct, but when your bot finished the game and all the mines were flagged it started clicking and found a mine.. possible?

Probably also because of the _RandomClickMine described above. Please see if it works correctly for you now. Edited by Manadar
Link to comment
Share on other sites

This could probably be a better random function. Just not sure yet..

Func _RandomClickMine()
    Local $mChance[$mGW][$mGH]
    Local $lowestChance = 1000
    Local $lowestX, $lowestY
    
    For $x = 0 to $mGW-1
        For $y = 0 to $mGH-1
            $mChance[$x][$y] = _CalculateChanceBomb($x,$y)
            If ($mChance[$x][$y] <> -1 AND $mChance[$x][$y] < $lowestChance) Then
                $lowestChance = $mChance[$x][$y]
                $lowestX = $x
                $lowestY = $y
            EndIf
        Next
    Next
    
    _WinMine_ClickMine($lowestX, $lowestY)
    
    Sleep(500)
EndFunc

Func _CalculateChanceBomb($x,$y)
    $thisMine = _WinMine_GetMine($x,$y)
    If $thisMine <> $MINE_UNKNOWN Then
        Return -1
    EndIf
    
    $lOne = _WinMine_CountSurroundingMines($x,$y,$MINE_ONE)
    $lTwo = _WinMine_CountSurroundingMines($x,$y,$MINE_TWO)
    $lThree = _WinMine_CountSurroundingMines($x,$y,$MINE_THREE)
    $lFour = _WinMine_CountSurroundingMines($x,$y,$MINE_FOUR)
    $lFive = _WinMine_CountSurroundingMines($x,$y,$MINE_FIVE)
    $lSix = _WinMine_CountSurroundingMines($x,$y,$MINE_SIX)
    
    $lTotal = $lOne + ($lTwo * 2) + ($lThree * 3) + ($lFour * 4) + ($lFive * 5) + ($lSix * 6)
    
    If ($lTotal <= 1) Then
        Return -1
    Else
        Return $lTotal
    EndIf
EndFunc

Also, I wanted to let you Vista users know that a Vista compatible version is on it's way. :mellow:

Link to comment
Share on other sites

  • 11 months later...

Hi Manadar, I know this is an old post but I'm interested in logical solutions (no cheating) to minesweeper and found your post.

The problem is that I cannot see the link to "minesweeper.au3" file. Is it that I am sleepy today or it was removed?

If the code is after examplebot.au3, I get strange characters at the end of the codebox...

I'll be glad if someone can upload minesweeper.au3 (or tell me where it is), thanks.

By the way, did you coninue developing of Vista version?

Bye.

Link to comment
Share on other sites

I found it. Uploaded in first post.

Thankyou very much!

By the way, did you make progress with the Vista version?. Due to the changing background I think using PixelChecksum to search for numbers and mines is no longer useful, maybe that task has to be made using some calls to PixelGetColor...

But PixelGetColor is so slow in Vista...

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...