Today it's time to create our main loop and integrate a function to read the gem colors. We already located the gem play field and we know each gem its position. With this information we should be fine to complete today's part.
Reading the gem colors
The difficultiesIn the previous article we calculated the center of the three gems on the corners. The easiest way to continue, would be to read the pixel color at each gem center. Unfortunately that's not sufficient as the gem center we have calculated is not always the exact gem center. When writing the bot code originally, I found out that Bejeweled often seemed to randomly add an additional horizontal and vertical row of pixels to the gem field. If the gem field would contain only yellow gems for instance, our pixel reading function would not always return exactly the same color. Sometimes the function would return the color of the pixel beside the actual center of the gem, because of the additional row or column somewhere in the field.
The possible solutionsI found two potential solutions for this problem:
- Reading the color code at each calculated gem center and applying a margin to the color code when determining whether gems are equal afterwards
- Reading the gem color on locations close to the center and using exact color codes to determine equal gems afterwards
The pixel reading offsetNow, a few years later, I discovered the real problem of the additional rows and columns. Bejeweled namely draws one additional horizontal and vertical row in the center of the gem field. Next image shows this row and column in white. Because of these lines, our gem center calculations are not correct anymore in part 2, 3 and 4
With this new information I can update the pixel reading mechanism by calculating the exact center for part 2, 3 and 4 separately, but I won't change it at this moment. The pixel reading offset functionality which I implemented as workaround covers this case and still proves to work fine anyway.
The pixel reading offset or pixel shift method lets the bot read pixel colors on locations other than the calculated center. Each gem type (color) has an area with multiple pixels of the same color which we could call the safe area. If we read the pixel color within the borders of that area, we always get back the same color code for that gem, even if the gem shifts 1 pixel horizontally or vertically.
Following images show the safe zone for the white and purple gem. They both benefit from the pixel shift set -4 (x coordinate), -2 (y coordinate). The dot in black is the pixel of which the color code is read.
After having investigated all gems, I found out that three pixel shift sets would be sufficient to cover all gem types: 10,10 / 5,5 and -4,-2
Note that the pixel shift set values relate somehow to the bejeweled game proportions. I configured the pixel shift set values when playing on http://www.spelspelen.com. If a site other than http://www.spelspelen.com displays the bejeweled game with a different size, these pixel shift sets need to be revised. For instance, if the bejeweled game has only half the size of the one on http://www.spelspelen.com, then the pixel shift sets need to divided by two as well.
Implementing the pixel reading offsetFirst add following key to the configuration file:
Next add this code to the declaration section:
The pixel shift sets need to be split into array for easier processing. Add this code to the main section:
$pixelShift=IniRead ( $iniFile, "Common" , "pixelShift", 0 )
In order to loop through the different pixel shift sets when reading the gem field, add following code to the function section:
;Read pixel shift sets into an array
Global $pixelShiftSetCounter = 0
Global $pixelShiftSet = StringSplit($PixelShift,"/")
;For each pixel shift set, create an array storing the x and y coordinates
for $i = 1 to Ubound($pixelShiftSet) - 1
$pixelShiftSet[$i] = stringSplit($pixelShiftSet[$i],",")
Once we have the pixel shift sets ready, we can add the pixel reading function. Add following code to the function section:
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
Reading the pixels is one thing, but being able to see which colors were recorded is even better. Add following code to the function section:
_log("Start reading pixels")
$pixelShift = _getNextPixelShiftSet()
$shiftHorizontal = $pixelShift
$shiftVertical = $pixelShift
ToolTip('Reading pixels playfield', 0, 0)
for $j = $field1 to $field3 step $blockWidth
for $i = $field1 to $field2 step $blockWidth
$field[$k][$l] = pixelgetColor($i + $shiftHorizontal,$j + $shiftVertical)
;mousemove($i + $shiftHorizontal,$j + $shiftVertical,40)
$k = $k + 1
$l = $l + 1
$k = 0
$i = 0
$j = 0
for $j = 0 to 7
$line = ""
for $i = 0 to 7
$temp = $field[$i][$j]
$line = $line & " " & hex($temp)
The main loopNow all pixel reading functions have been implemented, we can set up the main loop of our bot. This loop will read the color code of each gem's center, log the color codes which have been recorded, and later on implement the logic to decide upon which move to make.
Add following code to the main section:
All above function calls and variables which the loop is referencing to should exist, except for the delay of searching new gems after having performed a move. Add following key to the configuration file:
$switched = false
$field = _ReadPixels()
ToolTip('Start checking if gems can be moved', 0, 0)
;PLACEHOLDER for the movement of gems
ToolTip('Stop checking if gems can be moved', 0, 0)
if $switched = true then
_log("a move was performed")
_log("checked whole field, no moves were done")
First add following key to the configuration file:
And add following code to the declaration section:
$searchDelay=IniRead ( $iniFile, "Common" , "searchDelay", 1200 )
Proof running the codeAt this point you should be able to run you script and see more results. 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 read the pixel colors of the gems. You can verify this by uncommenting the 2 comment lines in the _readPixels function. This will move the mouse to each gem and will give you an idea of what is happening exactly.
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.
Continue to the fourth part of the bejeweled bot tutorial: switching the gems