Jump to content
Sign in to follow this  
jvanegmond

Minesweeper UDF

Recommended Posts

jvanegmond

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

Share this post


Link to post
Share on other sites
jvanegmond

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

Share this post


Link to post
Share on other sites
Draygoes

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.

 

 

Share this post


Link to post
Share on other sites
TehWhale

Same error as draygoes. Vista too. :mellow:

Share this post


Link to post
Share on other sites
dansxmods

Works Great for me this is awesome.

Edit:

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

Edited by dansxmods

Share this post


Link to post
Share on other sites
jvanegmond

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:

Share this post


Link to post
Share on other sites
dansxmods

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.

Share this post


Link to post
Share on other sites
jvanegmond

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.

Share this post


Link to post
Share on other sites
dansxmods

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.

Share this post


Link to post
Share on other sites
Andreik

Not working for me. :mellow:


When the words fail... music speaks

Share this post


Link to post
Share on other sites
jvanegmond

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:

Share this post


Link to post
Share on other sites
cageman

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?

Share this post


Link to post
Share on other sites
jvanegmond

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

Share this post


Link to post
Share on other sites
jvanegmond

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:

Share this post


Link to post
Share on other sites
Ximorro

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.

Share this post


Link to post
Share on other sites
jvanegmond

Forum conversion messed the code tags up. I will try to find minesweeper.au3 in my personal folders, I will update here tonight.

Share this post


Link to post
Share on other sites
Ximorro

Uau! That's a quick reply!

I'll look for it tomorrow, thanks.

Share this post


Link to post
Share on other sites
jvanegmond

Uau! That's a quick reply!

I'll look for it tomorrow, thanks.

I found it. Uploaded in first post.

Share this post


Link to post
Share on other sites
Ximorro

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...

Share this post


Link to post
Share on other sites
jvanegmond

No, I never got around to it then and I probably will never do it.

PixelGetColor can be a lot faster on Vista if you specify a window handle.

Share this post


Link to post
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
Sign in to follow this  

×