Autoit Bejeweled bot tutorial part 4: switching the gems

AutoIt Bejeweled bot tutorial part 4This article makes part of the Bejeweled bot tutorial series.

This final article on my bejeweled bot is about checking the possible moves, followed by switching the gems. We could say that this is one of the most crucial factors in the bot creation process.


Decision making

There are several ways to decide which gems to move first. You could look at the amount of points to earn for each move, and then move the gem which gives you the maximum of points. Also you could look at the cascade effect your move is possibly going to produce.

This bot is applying a fairly easy and straightforward approach though. We define the possible gem patterns for identical gems and scan the gem play field for gems matching these patterns. The order of the patterns we look for defines the importancy of the move. We start by checking the patterns which will give us more points. The eventual cascade effect is not calculated, but for each pattern we start checking the lowest gems first and continue towards the top.

Now roll up your sleeves and prepare yourself for the coding.

We start by creating the clickDelay definition. Add following key to the configuration file:

moveClickDelay=0
And add this code to the declaration section:

$moveClickDelay=IniRead ( $iniFile, "Common" , "moveClickDelay", 0 )
Next we will implement the first decision making code. The variables firstGem and secondGem will contain the x and y coordinates of both gems to be switched, once we find matching gems. The switched boolean is put to false by default, and will keep track of switched gems during this iteration. If no gems were switched yet, we can continue to check for different patterns, otherwhise start over by checking for the first pattern again.

We start by looping through the gem play field and fetching the gem colors of the gems we need to check against the pattern. Looping happens vertically from bottop to top, and horizontally from right to left. In this first case below we fetch the gem colors of 4 adjacent gems and check whether the first, second and fourth gems match. If they match, we store their x and y coordinates and switch the gems. If not, we check whether the first, third and fourth gems match, and so on.

Add following code to the main section, on the place of the placeholder for the movement of gems:

local $firstGem[2] = [0, 0]
local $secondGem[2] = [0, 0]

if $switched == false then
for $j = ($amountGems - 1) to 0 step -1
for $i = ($amountGems - 4) to 0 step -1

$ColorGem1=$field[$i][$j]
$ColorGem2=$field[$i+1][$j]
$ColorGem3=$field[$i+2][$j]
$ColorGem4=$field[$i+3][$j]

;XXOX
if _ColorsMatch($ColorGem1, $ColorGem2, $ColorGem4)then
$firstGem[0] = $i + 2
$firstGem[1] = $j
$secondGem[0] = $i + 3
$secondGem[1] = $j
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

;XOXX
if _ColorsMatch($ColorGem1, $ColorGem3, $ColorGem4)then
$firstGem[0] = $i
$firstGem[1] = $j
$secondGem[0] = $i + 1
$secondGem[1] = $j
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

next
next

endif
The other patterns are quite similar so I won't comment them. Add this code to the main section as well, right below the code you just added:

if $switched == false then
for $j = ($amountGems - 4) to 0 step -1
for $i = ($amountGems - 1) to 0 step -1

$ColorGem1=$field[$i][$j]
$ColorGem2=$field[$i][$j+1]
$ColorGem3=$field[$i][$j+2]
$ColorGem4=$field[$i][$j+3]

;X
;X
;O
;X
if _ColorsMatch($ColorGem1, $ColorGem2, $ColorGem4)then
$firstGem[0] = $i
$firstGem[1] = $j + 2
$secondGem[0] = $i
$secondGem[1] = $j + 3
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

;X
;O
;X
;X
if _ColorsMatch($ColorGem1, $ColorGem3, $ColorGem4)then
$firstGem[0] = $i
$firstGem[1] = $j
$secondGem[0] = $i
$secondGem[1] = $j + 1
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

next
next
endif

if $switched == false then
for $j = ($amountGems - 2) to 0 step -1
for $i = ($amountGems - 3) to 0 step -1

$ColorGem1=$field[$i][$j]
$ColorGem2=$field[$i+1][$j]
$ColorGem3=$field[$i+2][$j]
$ColorGem4=$field[$i][$j+1]
$ColorGem5=$field[$i+1][$j+1]
$ColorGem6=$field[$i+2][$j+1]

;XXO or ;OOX
;OOX ;XXO
if _ColorsMatch($ColorGem1, $ColorGem2, $ColorGem6) or _ColorsMatch($ColorGem4, $ColorGem5, $ColorGem3) then
$firstGem[0] = $i + 2
$firstGem[1] = $j
$secondGem[0] = $i + 2
$secondGem[1] = $j + 1
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

;XOX or ;OXO
;OXO ;XOX
if _ColorsMatch($ColorGem1, $ColorGem3, $ColorGem5) or _ColorsMatch($ColorGem4, $ColorGem6, $ColorGem2) then
$firstGem[0] = $i + 1
$firstGem[1] = $j
$secondGem[0] = $i + 1
$secondGem[1] = $j + 1
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

;OXX or ;XOO
;XOO ;OXX
if _ColorsMatch($ColorGem2, $ColorGem3, $ColorGem4) or _ColorsMatch($ColorGem1, $ColorGem5, $ColorGem6) then
$firstGem[0] = $i
$firstGem[1] = $j
$secondGem[0] = $i
$secondGem[1] = $j + 1
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

next
next
endif


if $switched == false then
for $j = ($amountGems - 3) to 0 step -1
for $i = ($amountGems - 2) to 0 step -1

$ColorGem1=$field[$i][$j]
$ColorGem2=$field[$i][$j+1]
$ColorGem3=$field[$i][$j+2]
$ColorGem4=$field[$i+1][$j]
$ColorGem5=$field[$i+1][$j+1]
$ColorGem6=$field[$i+1][$j+2]

;XO or ;OX
;XO ;OX
;OX ;XO
if _ColorsMatch($ColorGem1, $ColorGem2, $ColorGem6) or _ColorsMatch($ColorGem3, $ColorGem4, $ColorGem5) then
$firstGem[0] = $i
$firstGem[1] = $j + 2
$secondGem[0] = $i + 1
$secondGem[1] = $j + 2
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

;XO or ;OX
;OX ;XO
;XO ;OX
if _ColorsMatch($ColorGem1, $ColorGem3, $ColorGem5) or _ColorsMatch($ColorGem4, $ColorGem6, $ColorGem2) then
$firstGem[0] = $i
$firstGem[1] = $j + 1
$secondGem[0] = $i + 1
$secondGem[1] = $j + 1
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif

;OX or ;XO
;XO ;OX
;XO ;OX
if _ColorsMatch($ColorGem2, $ColorGem3, $ColorGem4) or _ColorsMatch($ColorGem1, $ColorGem5, $ColorGem6) then
$firstGem[0] = $i
$firstGem[1] = $j
$secondGem[0] = $i + 1
$secondGem[1] = $j
$switched = _Switch($firstGem, $secondGem)
exitLoop 2
endif


next
next

endif

Checking gem colors

Identical gems are recognized based on their color. This bot doesn't apply any safety margin. Only when the color dots have exactly the same code we consider them as matching.

Add following code to the function section:

Func _ColorsMatch($color1, $color2, $color3)
$colorsEqual = false

if $color1 = $color2 and $color1 = $color3 then
_Log("The colors matched exactly: " & hex($color1))
$colorsEqual = true
return $colorsEqual
endif

EndFunc
It's important to know that this approach is not error proof and only suitable for Bejeweled I. Therefore I have upgraded this approach in my Bejeweled Blitz bot by applying color ranges, which also works for Bejeweled 2. In the future I will discuss this so called "color range approach". Meanwhile I'll give you something to chew on by showing an extract of the configuration file of my Bejeweled Blitz bot.

[colors]
red=0xFE9191:0xFE4141
orange=0xF8B84E:0xEF7422
white=0xFEFEFE:0x909090

Switching the gems

Actually switching the gems is the last part of the chain and is not complicated at all. The bot clicks two times: once on the first gem and once on the second gem. Add following code to the function section:

Func _Switch($firstGem, $secondGem)
mouseclick("left",$Field1[0] + ($BlockWidth * $firstGem[0]) ,$Field1[1] + ($BlockWidth * $firstGem[1]),1,$MoveClickDelay)
mouseclick("left",$Field1[0] + ($BlockWidth * $secondGem[0]) ,$Field1[1] + ($BlockWidth * $secondGem[1]),1,$MoveClickDelay)
return True
EndFunc

Proof running the code

At this point you should again be able to run you script and see the bot working. Save your script and configuration file, and run the bot script by pressing F5 in your ScITE editor. If you correctly followed all steps, the bejeweled bot should be performing all steps from previous parts, and the bot should perform correct moves. If you find the bot clicking faster than the gem play field replenishes after switching gems, you can increase the searchDelay timeout in the configuration file.

If you encounter difficulties with the execution of these steps and you don't succeed in fixing the problem yourself, then leave a message in the comment section. Don't forget to include the error message shown in the ScITE output window. I will answer to your question as soon as possible.

This was the last article in the Bejeweled bot tutorial series. Though, you can expect an article on the implementation of the color range approach for the Bejeweled Blitz Bot. Check out testingminded regularly for updates or subscribe to our RSS feed.

Related Posts by Categories

Comments

43 Responses to "Autoit Bejeweled bot tutorial part 4: switching the gems"

Kris said... October 23, 2009 at 1:02 AM

This is great. I've waited up to this point to see how you accomplished this task. Now I have a few ideas of my own on how to make this bot just a little better. Thanks for this.

Steven Machtelinckx said... October 23, 2009 at 7:46 AM

Hello Kris,

There are many things which can be improved, like the gem recognition or movements. You can even create a gui displaying the gem colors as recognized by the bot and more.

Feel free to share any improvements with us.

David said... October 29, 2009 at 4:19 PM

One way to improve gem recognition for the newer versions with shifting colors, is to look at the jewel shape by identifying unique points for each shape, that either are or are not the background color. If necessary, grab two points per square.

Anonymous said... October 29, 2009 at 7:12 PM

how can i adapt this to make it work for bilging in game called puzzle pirates? ty.

Steven Machtelinckx said... October 30, 2009 at 8:58 AM

@David: That's a good idea. So you would be checking for the background colors instead of the gem colors at certain points?
How would you cope with the different shades in the background? Bejeweled blitz has a background image instead if I'm right.

@Anynymous: I'm not familiar with the puzzle pirates game. Some principles of this bot can be reused, though I think there's much more color checking and logic to implement.

The_Blode said... November 12, 2009 at 11:26 AM

Hello,

I have followed the guide but all my bot does is read the pixel colours of gems and outputs a message "checked whole field, no moves were done". Where am I going wrong?

Many thanks,

The Blode

Steven Machtelinckx said... November 12, 2009 at 12:22 PM

- When the bot finds the upper left and lower right corner, does the mouse pointer move to the correct place on the screen?

- Can you have a look at the log file? The bot prints the color codes it reads when checking the gem colors. Do you find similar color codes in the log which should result in a move by the bot? Please post the result of the _logpixels() function.

The_Blode said... November 12, 2009 at 1:05 PM

Hello Steven,

First of, thanks for the quick response!

- When it find the corners, it hovers over each gem in sequence from left to right and reads their colour. When it gets to the last gem in the grid, it goes back to the first one.

- I do see matching colour codes but no moves are performed.

The trouble is...I'm using the bot on Bejeweled 2 which may present a problem. The specific pixels change colour often.

Any advice would be appreciated. Thanks.

The Blode.

Steven Machtelinckx said... November 12, 2009 at 1:17 PM

This bot was primarily designed for Bejeweled 1, so running it on Bejeweled 2 without the proper modifications will probably not work. Did you read my note on the implementation of color ranges in this article? I think that change is absolutely needed before running it on blitz or bejeweled 2.

Anyhow, If you find equal color codes in the log file which should result in a match and the Bejeweled bot doesn't perform any move, then there could be something wrong with the decision making code. Did you copy the code like described above?

The_Blode said... November 12, 2009 at 1:27 PM

Hi Steven,

Yes I did read the note but I am little confused about it. I copied and pasted the code and and everything worked perfectly until decision making. Might try debugging to see what the decision code does when running. I also read through the decision making code and made sense of it but it simply doesn't work for me. I can paste the ouput but it's a fair few lines of code...don't want to spam.

Thanks,

The Blode.

The_Blode said... November 12, 2009 at 2:56 PM

How did you discover your colour ranges for your Bejeweled Blitz bot? I can't think of a way other than manually scanning each gem and recording colour codes on a sheet of paper.

Any faster way of doing this?

Steven Machtelinckx said... November 12, 2009 at 4:37 PM

I used autoit window info (C:\Program Files\AutoIt3\Au3Info.exe) which can give you much information about any window. Open this tool and move your mouse to the color you would to know the code from and hit ctrl+alt+f. This will freeze the autoit window info tool, so you can read the color code from the Mouse or Summary tab.

For each gem color, I picked two colors: one bright color and one dark color, preferrably shades which don't appear in other gems.

Hope this helps :-)

Anonymous said... December 8, 2009 at 9:34 AM

Hi, good work on the bot,

just tried this for bejewelled blitz and it logs out the colours similar but not the same,

I have added a colors section to my config for each color and the min;max but how would you code it in.

I have an idea how it works but coding it is slightly more difficult for me.

Obviously the software would take the hex as say 00B5B5B5 but how would you then get it to say hey this is a green (Not sure if that was a green)

After getting it to recognise colors after that its the same i assume.

Thanks

James

Steven Machtelinckx said... December 8, 2009 at 11:36 AM

Hi James,

This is the "colors" section in my configuration file:
red=0xFE9191:0xFE4141
orange=0xF8B84E:0xEF7422
white=0xFEFEFE:0x909090
purple=0xFE7AFE:0x970097
blue=0x59DAFE:0x0A56BA
green=0x35F735:0x009700
yellow=0xF9F190:0xCCCB31
yellow=0xF0E833:0xAEAD28

This is the command to read the color section in the ini file:
$colorRanges = IniReadSection( $iniFile, "colors")

This is the code to read the ranges into arrays:
;Initialize color ranges
for $i = 1 to $colorRanges[0][0]
$newColorRanges = stringsplit($colorRanges[$i][1],":")
$newColorRanges[1] = _arrayCreate(_ColorGetRed($newColorRanges[1]),_ColorGetGreen($newColorRanges[1]), _ColorGetBlue($newColorRanges[1]))
$newColorRanges[2] = _arrayCreate(_ColorGetRed($newColorRanges[2]),_ColorGetGreen($newColorRanges[2]), _ColorGetBlue($newColorRanges[2]))

$colorRanges[$i][1] = $newColorRanges
next

And this is the code to check whether a color is in the range or not:

Func _ColorInRange($color)
;$colorRanges

$colorR = _ColorGetRed($color)
$colorG = _ColorGetGreen($color)
$colorB = _ColorGetBlue($color)

for $i = 1 to $colorRanges[0][0]

$ranges = $colorRanges[$i][1]

$rangeStart = $ranges[1]
$rangeStartR = $rangeStart[0]
$rangeStartG = $rangeStart[1]
$rangeStartB = $rangeStart[2]
$rangeEnd = $ranges[2]
$rangeEndR = $rangeEnd[0]
$rangeEndG = $rangeEnd[1]
$rangeEndB = $rangeEnd[2]

if _InRange($colorR, $rangeStartR, $rangeEndR) and _InRange($colorG, $rangeStartG, $rangeEndG) and _InRange($colorB, $rangeStartB, $rangeEndB) then
;_log("color with hex " & $color & " is in range: " & @crlf & "Red: " & _ColorGetRed($color) & " " & _ColorGetRed($rangeStart) & " " & _ColorGetRed($rangeEnd) & @crlf & "Green: " & _ColorGetGreen($color) & " " & _ColorGetGreen($rangeStart) & " " & _ColorGetGreen($rangeEnd) & @crlf & "Blue: " & _ColorGetBlue($color) & " " & _ColorGetBlue($rangeStart) & " " & _ColorGetBlue($rangeEnd) )
return $colorRanges[$i][0]
EndIf

next

return False

EndFunc


Good luck with it :-)

Anonymous said... December 9, 2009 at 4:57 AM

Hi thanks for the quick response!

Ok so i placed the color ranges into me config, placed the $colorranges to call the ini into the Declaration section.

I then put the code to read the arrays into main, and finally added the range finding code into the functions.

Im getting: ERROR: _ColorGetRed(): undefined function.

ive uploaded my script to

http://bugsy.pwp.blueyonder.co.uk/bot.zip

feel free to edit the link out after and any help would be appreciated :)

James

Anonymous said... December 9, 2009 at 5:05 AM

And the other issue ive been trying to solve is in my log file its only logging the top 7 lines! Im sure with a bit of tinkering i could get it working but the colour ranges have thrown me,

thanks for your help though and nice work

Anonymous said... December 9, 2009 at 7:48 AM

James again... If its easier my msn is shr3k@live.co.uk

Steven Machtelinckx said... December 9, 2009 at 3:57 PM

Hi James,

I'm sorry, I forgot to tell to add the include statement... :-)

Add this line to the list of include statements at the top of your bot file:

#include <Math.au3>

This should definately fix your problem :-)

Tim said... January 7, 2010 at 9:26 AM

Hi James,

did you fix the colourrange problem?
I´m trying out, but autoit tells me newColorRanges[1] = _arrayCreate(^ ERROR

Perhaps you can help me a little bit, I think we both do have the same target.

Greetings from Germany

Steven Machtelinckx said... January 7, 2010 at 9:40 AM

Tim,

Do you have more details about the error?
Are all your color ranges correctly specified in the configuration file, seperated by a ":"?

Tim said... January 8, 2010 at 2:44 PM

Hi Steven,

all color ranges are correctly specified with a ":".
Autoit tells me:

$newColorRanges[1] = _arrayCreate(_ColorGetRed($newColorRanges[1]),_ColorGetGreen($newColorRanges[1]), _ColorGetBlue($newColorRanges[1]))
$newColorRanges[1] = _arrayCreate(^ ERROR
>Exit code: 1 Time: 1.645

Can you tell me what is wrong? i´m not able to find the mistake!

Steven Machtelinckx said... January 9, 2010 at 11:31 AM

Hi Tim,

Did you include the color library?

These are my include statements:

#include <Array.au3>
#include <File.au3>
#include <Math.au3>
#include

Steven Machtelinckx said... January 9, 2010 at 11:32 AM

My last include is not correctly displayed in my previous reply.

It should be this:

#include <Color.au3>

Tim said... January 9, 2010 at 6:20 PM

Just that easy,...thanks a lot!

fixed it and it worked great!!
But:
Latest error:Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
$temp = $field[$i][$j]
$temp = ^ ERROR

Don´t have much time today, my first thougt was to set i und j = 9, but it is not that easy!

The pointer moves over the field, but only over the first seven rows and stops then.

Also the colours are not been saved in the output.txt

I will try to fix this tomorrow. There is no poibility to go out because of all the snow. So it´s autoit-Time tomorrow.

Thanks for your help!!!

Steven Machtelinckx said... January 13, 2010 at 12:38 PM

Hello Tim,

Did you manage to fix the problem?

dimelo said... February 4, 2010 at 3:41 AM

Hello running into a problem.
With:

;loop through different pixel shifts
Func _getNextPixelShiftSet()
If $PixelShiftSetcounter < (Ubound($PixelShiftSet) - 1)
Then $PixelShiftSetcounter = $PixelShiftSetcounter + 1
else $PixelShiftSetcounter = 1
endif _log("Using Pixelshiftset with number " & $PixelShiftSetcounter & " and content " & _ArrayToString($PixelShiftSet[$PixelShiftSetcounter],",",1))
return $PixelShiftSet[$PixelShiftSetcounter]
EndFunc



It gives me this error:

bjbot.au3 (184) : ==> "If" statements must have a "Then" keyword.:
If $PixelShiftSetcounter < (Ubound($PixelShiftSet) - 1)

dimelo said... February 4, 2010 at 4:07 AM

I got it to work, but all it does is move the mouse to the upper left hand corner and leaves the point there and doesnt do anymoves. I copied all the code in the right place and everything?

Dcyli said... February 4, 2010 at 8:01 AM

Why set up an array for the range when you can change your getpixelcolor output to decimal and then see if the rgb values are in range using some evaluations?

Is the array faster?

Btw, great tutorial. Got me started on my bot. I'm at the point where I'm trying to get it faster by optimizing everything that I can. :D

Steven Machtelinckx said... February 4, 2010 at 1:30 PM

@Dimelo: did you set the correct pixel color for the right lower corner to search for? The bot quits if it doesn't find the color on the screen.

Steven Machtelinckx said... February 4, 2010 at 1:33 PM

@Dycli: I'm not sure which range you mean. Could you specify? :-)

Christian said... February 17, 2010 at 1:36 AM

Hi Steven.

I become the following Error:

bj_test.au3(439,46) : ERROR: _InRange(): undefined function.
if _InRange($colorR, $rangeStartR, $rangeEndR)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

Can you help me please?

Dcyli said... February 22, 2010 at 9:21 PM

@Steven
What I meant by range is from your code snippet. The color range approach.

I might have misread it. Now that I re-read it.

Dcyli said... February 22, 2010 at 9:22 PM

@Steven
Ah, I see. I was referring to your Dec 8 2009 post.

Anonymous said... March 24, 2010 at 11:08 PM

Thanks for this tutorial. Your explainations of the programming parts are very clear.

I wanted to type the code but things went wrong from the first declation lines :s


#include
#include



The compiler doesn't pass the 3rd line (syntax error). What's wrong with this line ?

Thanks for your help

Bruno

Steven Machtelinckx said... March 25, 2010 at 12:12 AM

Bruno,

Can you please resubmit the code and error. In order to have it displayed correctly, you can try out pastie on http://pastie.org/ and copy the generated link back here.

Anonymous said... March 25, 2010 at 8:30 PM

Hi,

The third line gives an error :
http://pastie.org/886572

The error :
http://pastie.org/887115

I'll put this line in comments and continue ...

Bruno

Steven Machtelinckx said... March 25, 2010 at 9:03 PM

Indeed, those closing tags for the array and file include should not be there. The code formatter is adding them for an unknown reason. You can completely delete them.

Anonymous said... March 25, 2010 at 10:48 PM

OK, thank you for your response. I learned a lot with this tutorial, thanks again.

Bruno

Ikra said... April 18, 2010 at 5:28 PM

cool tutorial ... I was able to learn more basic functions on AutoIt at the same time such as file writing, arrays and color comparison. A fun way to learn AutoIt haha...

help said... September 17, 2010 at 10:07 PM

Error: Error parsing function call.

can you please help me and find out the problem?

Chris said... November 5, 2010 at 4:07 AM

Great bot, it worked up until the second to last tutorial and this it the error I get;

BJ3.au3 (320) : ==> "Func" statement has no matching "EndFunc".:
Func _readPixels()

Software Testing Class said... June 19, 2012 at 8:49 PM

I never used the Autoit before but after reading this article get some basic knowledge of it. Here you will also get good articles on Software Testing as well with some guidelines with different way of thinking.

TestWithUs said... May 7, 2013 at 5:57 AM

SWIFT Interview questions on

http://testwithus.blogspot.in/p/swift.htm

For selenium solution visit
http://testwithus.blogspot.in/p/blog-page.html


For QTP interview questions

http://testwithus.blogspot.in/p/qtp-questions.html


www.searchyourpolicy.com




Post a Comment

Recent Articles

Top Commenters

Recent Comments