 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Dewi Morgan
Joined: 03 Oct 2005 Posts: 178
|
Posted: Tue Oct 04, 2005 5:17 am Post subject: Bejewelled 2 autoplay. |
|
|
First script, because hello world is passé.
The company "Pop cap games" have a popular Flash game called "Bejewelled".
It's simple: a grid of coloured pieces. Each move, you swap two adjacent pieces to form a line of three or more of the same colour. The line disappears, tetris style, the pieces shift downwards, and the empty grid spaces are filled from the top.
I wanted to try out different strategies in a controlled environment, to see which was best. I decided to make something that would play Pop Cap's Bejewelled or any of the mass of similar clones that have come out, and record scores for different strategies.
The graphics in the latest version, Bejewelled 2 Deluxe 1.0 are significantly "improved" from the earlier version, in ways that I suspected would prevent ImageSearch (animated pieces, with flashy sparkles on) or PixelSearch (pieces are different shapes, have arbitrary photographic backgrounds which could contain any colour). But that version of the game has a really handy-for-testing-strategies "play forever" mode.
So I pick a pixel within each piece, and use the r/g/b proportions to try to guess what colour it's meant to be.
So far, I think I'm successful. It plays on three different versions of the game, though obviously once they use colours it can't differentiate (cream and white), it fails.
The version below is configured for, and the colour guessing function is optimised for, the locally-installed demo version of Bejewelled 2 Deluxe 1.0, though it will with tweaking work with others too.
Now I have to get some RL work done, but if I can be bothered, next I'll: 1) Make it prompt for grid size,
2) Ask for mouseclicks on the top left and bottom right of the grid
3) Ask for mouseclick on a piece in the centre of the board to get the sample pixel position within the gridsquares.
4) Grab the window title from the active window after those clicks
5) Grab the score after a fixed time (probably as an image).
For the moment, I've run it through a large number of moves using two algorithms: bottommost valid move, and topmost valid move. It doesn't rank moves by potential gain at all, and does no planning ahead (for that, I'll throw the board layout at a language that I'm more comfortable in). But already, a pattern is emerging.
Going for the lowest move on the board gives the highest average per-move score, so would be good for timed games.
Going for the highest move on the board gives lower per-move scores, but gives longer games, and hence higher overall scores, since you're less likely to run out of valid moves. Good for versions of the game where running out of moves ends the game.
This strategy difference seems to be the case on every version of the game, though the smaller the board, the less the difference is.
I'd really be interested in whether people can think of a better way of differentiating between different pieces. At the moment, it sometimes has a hard time differentiating between cyan/blue (so I removed cyan, since there were no cyan pieces), and red/orange/yellow.
Mostly, though, it's the white sparkles that cause problems: it thinks they are white pieces. I guess one option there would be to retest "white" pieces at a couple of other points, just in case.
I'd also be interested in any other feedback whatsoever, from code style to optimisation suggestions to telling me to STFU. I'm new to this language, and anything you can say will be muchly appreciated.
| Code: |
; Script to play a board game.
;
; Proof of concept thang to recognise pieces by colour.
;
; Assumes that all pieces are primary (rgb) or secondary (cmy)
; colors, orange, or grey. Doesn't use PixelSearch, as the
; background may be any colour. Instead, checks the color of a
; single pixel offset within each square to build a map of the
; board layout each turn, then operates on that.
;
; Detection of red/orange/yellow and cyan/blue is really a bit dodgy
; and often wrong.
;
; Copyright is explicitly released upon the public domain.
; This means you may do as you wish with it, without credit.
^!r::Reload ; pause/reload the script.
^!d:: toggleDebug()
toggleDebug()
{
global SG_DEBUG
if ( SG_DEBUG == 1)
SG_DEBUG=0
else
SG_DEBUG=1
}
^!z::
; Globals.
; These should be gathered on the fly rather than predefined.
; Offset to measure within the square.
SG_OFFSET_X=6
SG_OFFSET_Y=12
; Coords within the window for the top left of the board.
SG_ORIGIN_X=168
SG_ORIGIN_Y=15
; Size of a single square.
SG_SIZE_X=52
SG_SIZE_Y=52
; Number of squares on board.
SG_SQUARES_X=8
SG_SQUARES_Y=8
; Remember last move so we're less likely to get stuck trying the same wrong move forever.
; But if there are TWO wrong moves, then...
SG_LAST_X=0
SG_LAST_Y=0
; Whether this version allows piece dragging rather than click/click.
SG_DRAG_OK=1
; Debugging level
SG_DEBUG=0
Loop
{
getWindow()
; Loop Y then X: move across every square, down only once per line.
sg_line := ("")
Loop, %SG_SQUARES_Y%
{
sg_y := A_Index
sg_py := yCoordToPixel(A_Index)
sg_line = %sg_line% `n# %A_Index% :
Loop, %SG_SQUARES_X%
{
sg_x := A_Index
sg_px := xCoordToPixel(A_Index)
PixelGetColor, sg_color, %sg_px%, %sg_py%, RGB
sg_c := hex2Color(sg_color)
SG_ARR_%sg_x%_%sg_y% := sg_c
col := SG_ARR_%sg_x%_%sg_y%
;MsgBox, SG_ARR_%sg_x%_%sg_y% = %col%
sg_line = %sg_line% %sg_c% ( %sg_x% , %sg_y% = %sg_px% , %sg_py% )
}
;MsgBox, %sg_line%
}
getMove()
if ( SG_DEBUG == 1 )
{
MsgBox, DEBUG %SG_DEBUG% %sg_line%
}
;return
}
getWindow()
{
; Window management. This shouldn't care about the window name.
WinWait, Bejeweled 2 Deluxe 1.0,
IfWinNotActive, Bejeweled 2 Deluxe 1.0, , WinActivate, Bejeweled 2 Deluxe 1.0,
WinWaitActive, Bejeweled 2 Deluxe 1.0,
}
; Convert a board y square coord to a screen y coord.
; This means our y coords are, internally, all "backwards" - but who cares?
yCoordToPixel(y)
{
global SG_SIZE_Y
global SG_ORIGIN_Y
global SG_OFFSET_Y
global SG_SQUARES_Y
; SG_SQUARES_Y - y as we're working from the bottom for highest scores.
return ( ( SG_SQUARES_Y - y + 1 ) * SG_SIZE_Y ) + SG_ORIGIN_Y + SG_OFFSET_Y
}
; Convert a board square x coord to a screen x coord.
xCoordToPixel(x)
{
global SG_SIZE_X
global SG_ORIGIN_X
global SG_OFFSET_X
return ( x * SG_SIZE_X ) + SG_ORIGIN_X + SG_OFFSET_X
}
; Make the mouse move a piece.
movePiece(x1, y1, x2, y2)
{
global SG_DRAG_OK
global SG_ORIGIN_X
global SG_ORIGIN_Y
global SG_LAST_X
global SG_LAST_Y
SG_LAST_X := x1
SG_LAST_Y := y1
;MsgBox, Moving from %x1% , %y1% to %x2% , %y2%, set last = %SG_LAST_X% , %SG_LAST_Y%
getWindow()
if (SG_DRAG_OK == 1)
{
MouseClickDrag, L, xCoordToPixel(x1), yCoordToPixel(y1), xCoordToPixel(x2), yCoordToPixel(y2), 2
}
else
{
MouseClick, L, xCoordToPixel(x1), yCoordToPixel(y1)
Sleep, 100
MouseClick, L, xCoordToPixel(x2), yCoordToPixel(y2)
Sleep, 100
}
; Move to home point to avoid hilighting pieces.
MouseMove, SG_ORIGIN_X, SG_ORIGIN_Y
; Wait for pieces to fall.
Sleep, 600
}
; Check that the piece in an array coord is not out of bounds,
; and is the same color.
isSameAt(col, x, y)
{
; Generic global to include array.
global
if (x < 1 || x > SG_SQUARES_X || y < 1 || y > SG_SQUARES_Y )
{
;MsgBox, returning false as OOB ( %x% < 1 || %x% > %SG_SQUARES_X% || %y% < 1 || %y% > %SG_SQUARES_Y% )
return false
}
ax := SG_ARR_%x%_%y%
if ( SG_ARR_%x%_%y% == col )
{
;MsgBox, returning true as %ax% == %col% and none of ( %x% < 1 || %x% > %SG_SQUARES_X% || %y% < 1 || %y% > %SG_SQUARES_Y% )
return true
}
;MsgBox, returning false as %ax% != %col% though none of ( %x% < 1 || %x% > %SG_SQUARES_X% || %y% < 1 || %y% > %SG_SQUARES_Y% )
return false
}
; An extremely nasty bruteforcism: tries each possible move in turn.
; If it finds one, it does it.
; Unfortunately, for the SG_ARR stuff, need all globals defined.
getMove()
{
global
Loop, %SG_SQUARES_Y%
{
y = %A_Index%
py := xCoordToPixel(y)
y1 := ( y + 1 )
y2 := ( y + 2 )
y3 := ( y + 3 )
y_1 := ( y - 1 )
y_2 := ( y - 2 )
y_3 := ( y - 3 )
Loop, %SG_SQUARES_X%
{
x = %A_Index%
; Anti-stick: don't play the same piece twice in a row
; If it's the only playable square, we'll get it next time round.
if ( SG_LAST_X == x && SG_LAST_Y == y )
{
; Zero them so we can get this square next time if it's the only one.
SG_LAST_X = 0
SG_LAST_Y = 0
Continue
}
px := xCoordToPixel(px)
x1 := ( x + 1 )
x2 := ( x + 2 )
x3 := ( x + 3 )
x_1 := ( x - 1 )
x_2 := ( x - 2 )
x_3 := ( x - 3 )
col := SG_ARR_%x%_%y%
;MsgBox, At %x%, %y% comparing %col% , %x2% , %y% And %col%, %x3%, %y%
; X_xx
if ( isSameAt(col, x2, y) && isSameAt(col, x3, y) )
{
movePiece( x, y, x1, y)
return
}
; xx_X
else if ( isSameAt(col, x_2, y) && isSameAt(col, x_3, y) )
{
movePiece( x, y, x_1, y)
return
}
; X
; _
; x
; x
else if ( isSameAt(col, x, y2) && isSameAt(col, x, y3) )
{
movePiece( x, y, x, y1)
return
}
; x
; x
; _
; X
else if ( isSameAt(col, x, y_2) && isSameAt(col, x, y_3) )
{
movePiece( x, y, x, y_1)
return
}
; x_
; x_
; _X
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x_1, y_2) )
{
movePiece( x, y, x_1, y)
return
}
; _x
; _x
; X_
else if ( isSameAt(col, x1, y_1) && isSameAt(col, x1, y_2) )
{
movePiece( x, y, x1, y)
return
}
; _X
; x_
; x_
else if ( isSameAt(col, x_1, y1) && isSameAt(col, x_1, y2) )
{
movePiece( x, y, x_1, y)
return
}
; X_
; _x
; _x
else if ( isSameAt(col, x1, y1) && isSameAt(col, x1, y2) )
{
movePiece( x, y, x1, y)
return
}
; X__
; _xx
else if ( isSameAt(col, x1, y1) && isSameAt(col, x2, y1) )
{
movePiece( x, y, x, y1)
return
}
; _xx
; X__
else if ( isSameAt(col, x1, y_1) && isSameAt(col, x2, y_1) )
{
movePiece( x, y, x, y_1)
return
}
; __X
; xx_
else if ( isSameAt(col, x_1, y1) && isSameAt(col, x_2, y1) )
{
movePiece( x, y, x, y1)
return
}
; xx_
; __X
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x_2, y_1) )
{
movePiece( x, y, x, y_1)
return
}
; x_
; _X
; x_
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x_1, y1) )
{
movePiece( x, y, x_1, y)
return
}
; _x
; X_
; _x
else if ( isSameAt(col, x1, y_1) && isSameAt(col, x1, y1) )
{
movePiece( x, y, x1, y)
return
}
; _X_
; x_x
else if ( isSameAt(col, x_1, y1) && isSameAt(col, x1, y1) )
{
movePiece( x, y, x, y1)
return
}
; x_x
; _X_
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x1, y_1) )
{
movePiece( x, y, x, y_1)
return
}
}
}
; MsgBox, Unable to find a move
}
; Convert a hex value to a colour letter, from:
; r(ed)c(yan)g(reen)y(ellow)o(range)b(lue)m(agenta)w(hite).
; Per: r rg=o gr=y g gb=c bg=c b rb=m br=m
hex2Color(color)
{
r := ( ( color >> 16 ) & 0xFF )
g := ( ( color >> 8 ) & 0xFF )
b := ( color & 0xFF )
if (r > g && r > b )
{
col = r
min := ( r * 0.5 )
if (min <= g && min <= b )
col=w
if (min <= g && min > b ) ; dodgy yellow test.
if (r - g > 10)
col=o
else ; numbers too similar, still yellow.
col=y
if (min > g && min <= b )
col=m
}
if (g >= r && g >= b )
{
col = g
min := ( g * 0.6 )
if (min <= r && min <= b )
col=w
if (min <= r && min > b )
col=y
if (min > r && min <= b )
; col=c ; commented since there ARE no cyan pieces in the test game
col=b
}
if (b >= r && b >= g )
{
col = b
min := ( b * 0.6 )
if (min <= r && min <= g )
col=w
if (min <= r && min > g )
col=m
if (min > r && min <= g )
; col=c ; commented since there ARE no cyan pieces in the test game
col=b
}
;MsgBox, Colour %color%=%col% r:%r% g:%g% b:%b%
return col
}
|
_________________ Yet another hotkeyer. |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10467
|
Posted: Tue Oct 04, 2005 11:56 am Post subject: |
|
|
| Even if someone doesn't use it for this particular game, your script is sophisticated enough to be a great example of screen-searching in its own right. Thanks for posting it. |
|
| Back to top |
|
 |
eef Guest
|
Posted: Fri Jan 13, 2006 2:09 pm Post subject: averaging |
|
|
Nice idea, Autoplay!
I really like bejeweled and play it quite often.
As I see this has been posted some time ago.
Nonetheless heres my proposal for a solution of
your "color guessing problem":
The idea is to take average color of a given gem.
In the following pseudocode x=0,y=0 is the upper left
coordinate of the gem. dx/dy its size.
| Code: |
c = 0; // color averaging variable
for x = 0 to dx
{
for y = 0 to dy
{
c += getcolor(x,y);
}
}
c /= dx * dy; // devide by number of pixels in the area
if ( c > somecolor - tolerance && c < somecolor + tolerance)
{
print "gem is most probably of color 'somecolor' ";
// do sth here...
}
else if ( c > someothercolor - tolerance ....
|
One would need to tweak the constants 'somecolor' and 'tolerance'
a littlebit. The algorithm should be quite robust.
Even better would be to take the median of the pixel colors,
this would be immune to isolated color values from the sparkling.
This is classical problem in the field of image processing. If you're interested in the topic just google for "image processing"
Cheers
eef |
|
| Back to top |
|
 |
Guest
|
Posted: Fri Jan 13, 2006 6:08 pm Post subject: |
|
|
Very good point.
Have to average the r, g, and b separately, though. Otherwise, the "average" of 0x030000 ("black, negligible red") and 0x0000ff ("100% blue") is 0x01807f ("50% cyan") - clearly not a sensible average colour: the green value isn't in either of the initial two colours.
Averaging the bytes individually, it's 0x01007f (50% blue, negligible red), which is a more sensible average.
Another thing to take into account is that sparkles and other graphical wossnames will generally be greater than one pixel in size, so you can save processing time (or use the same processing time to scan a larger area) by skipping pixels.
Since stuff tends to be in straight lines, my guess at the best pixel-pattern would be the tightest one in which no pixels are in a straight line for eachother.
For example in an 8x8 array, you could scan only 8 pixels and get a pretty good guess, if you selected them carefully: http://en.wikipedia.org/wiki/Eight_queens_puzzle
o o o X o o o o
o o o o o o X o
o o X o o o o o
o o o o o o o X
o X o o o o o o
o o o o X o o o
X o o o o o o o
o o o o o X o o
This might be moot, though: my gut feeling is that pixel-checking is "expensive", and needs to be minimised, but perhaps it's really fast.
For an 8x8 board, the number of checks at:
1 pixel/boardsquare = 8x8 = 64
8 pixels/boardsquare = 8x8x8 = 512
8*8(=64) pixels/square = 8x8x64 = 4096
Could then use a fn like (untested):
| Code: |
SG_NUM_SCANNED_PIXELS = 8
SG_SCAN_X_0 = 4
SG_SCAN_X_1 = 7
SG_SCAN_X_2 = 3
SG_SCAN_X_3 = 8
SG_SCAN_X_4 = 2
SG_SCAN_X_5 = 5
SG_SCAN_X_6 = 1
SG_SCAN_X_7 = 6
; Like pixelGetColor, but for board squares.
; Finds the average color for an 8x8 area in the given board square.
boardSquareGetColor(sg_x, sg_y)
{
global SG_NUM_SCANNED_PIXELS
; I think the following includes the whole array, not sure.
global SG_SCAN_X_
sg_px := xCoordToPixel(sg_x)
sg_py := yCoordToPixel(sg_y)
r = 0
g = 0
b = 0
; Get the pixel values
Loop %SG_NUM_SCANNED_PIXELS%
{
new_px := sg_px + SG_SCAN_X_%A_Index%
new_py := sg_py + %A_Index%
PixelGetColor, sg_color, %new_px%, %new_py%, RGB
r := r + ( ( sg_color >> 16 ) & 0xFF )
g := g + ( ( sg_color >> 8 ) & 0xFF )
b := b + ( sg_color & 0xFF )
}
; Average the values.
r := ( r / SG_NUM_SCANNED_PIXELS ) & 0xFF
g := ( g / SG_NUM_SCANNED_PIXELS ) & 0xFF
b := ( b / SG_NUM_SCANNED_PIXELS ) & 0xFF
; return the colour vaue for the square.
ret_val = ( r << 16 ) + ( g << 8 ) + b
return %ret_val%
}
|
|
|
| Back to top |
|
 |
Vixay Xavier Guest
|
Posted: Thu Jun 12, 2008 10:27 am Post subject: Adaptation for Puzzle Quest |
|
|
I've adapted the above script for use with Puzzle Quest!
Great Script Btw!!
Now I am just hunting for a good algorithm to match 4 of a kind
set priorities and some basic GUI
Try it out, and let me know!
| Code: | ; ==UserScript==
; @name AutoPuzzleQuest
; @namespace http://userscripts.org/users/49912
; @description Script to play a board game (Puzzle Quest)
; @source http://www.autohotkey.com/forum/topic5663.html
; @identifier http://www.autohotkey.com/forum/topic5663.html&highlight=bejeweled
; @version 1.0
; @date 2008-06-12
; @creator ViXaY XaVieR
; @include Puzzle Quest
; ==/UserScript==
; Original Source: see @source
;
; Proof of concept thang to recognise pieces by colour.
;
; Assumes that all pieces are primary (rgb) or secondary (cmy)
; colors, orange, or grey. Doesn't use PixelSearch, as the
; background may be any colour. Instead, checks the color of a
; single pixel offset within each square to build a map of the
; board layout each turn, then operates on that.
;
; Detection of red/orange/yellow and cyan/blue is really a bit dodgy
; and often wrong.
;
; Copyright is explicitly released upon the public domain.
; This means you may do as you wish with it, without credit.
; ==TO DO==
; trigger to start combat
; autodetection of end
; preferences for 4 in ones and skulls, and for scrolls, or anvils depending on game mode (BATTLE, TRAIN MOUNT, RESEARCH SPELL, FORGE ITEM)
; GUI for options (type of combat, delay, wait for AI turn ...etc)
;DONE (need to test) check for defeat banner (save it)
; check colors for wild cards and black skulls, scrolls & anvils
; disable wait for my turn in different game modes
; detect game modes by checking on screen
; output grid (in memory) in a neat way
; fix color detection (sometimes it still makes illegal moves)
; scan grid only after our turn indicator has come
^!r::Reload ; pause/reload the script. stop scripts execution
^!t::toggleDelay()
^!d::toggleDebug()
toggleDelay()
{
global SG_PAUSE
if ( SG_PAUSE == 1)
SG_PAUSE=0
else
SG_PAUSE=1
}
toggleDebug()
{
global SG_DEBUG
if ( SG_DEBUG == 1)
SG_DEBUG=0
else
SG_DEBUG=1
}
^!z::
; Globals.
; These should be gathered on the fly rather than predefined.
; Offset to measure within the square.
SG_OFFSET_X=37
SG_OFFSET_Y=37
; Coords within the window for the top left of the board.
SG_ORIGIN_X=218
SG_ORIGIN_Y=156
; Size of a single square.
SG_SIZE_X=74
SG_SIZE_Y=74
; Number of squares on board.
SG_SQUARES_X=8
SG_SQUARES_Y=8
; Remember last move so we're less likely to get stuck trying the same wrong move forever.
; But if there are TWO wrong moves, then...
SG_LAST_X=0
SG_LAST_Y=0
; Whether this version allows piece dragging rather than click/click.
SG_DRAG_OK=1
; Debugging level
SG_DEBUG=1
; Whether to Pause (for AI turn) or not
SG_PAUSE=1
; Start at top of board or bottom
SG_TOP=1
Loop
{
getWindow()
; Loop Y then X: move across every square, down only once per line.
sg_line := ("")
Loop, %SG_SQUARES_Y%
{
sg_y := A_Index
sg_py := yCoordToPixel(A_Index)
sg_line = %sg_line% `n# %A_Index% :
Loop, %SG_SQUARES_X%
{
sg_x := A_Index
sg_px := xCoordToPixel(A_Index)
PixelGetColor, sg_color, %sg_px%, %sg_py%, RGB
sg_c := hex2Color(sg_color)
SG_ARR_%sg_x%_%sg_y% := sg_c
col := SG_ARR_%sg_x%_%sg_y%
;MsgBox, SG_ARR_%sg_x%_%sg_y% = %col%
sg_line = %sg_line% %sg_c% ( %sg_x% , %sg_y% = %sg_px% , %sg_py% )
}
;MsgBox, %sg_line%
}
getMove()
if ( SG_PAUSE == 1 ) sleep, 1000
if ( SG_DEBUG == 1 )
{
MsgBox, DEBUG %SG_DEBUG% %sg_line%
clipboard = %sg_line%
return
}
if (gameOver() == true) {
return
}
waitForMyTurn()
}
getWindow()
{
; Window management. This shouldn't care about the window name.
WinWait, Puzzle Quest,
IfWinNotActive, Puzzle Quest, , WinActivate, Puzzle Quest,
WinWaitActive, Puzzle Quest,
}
; Convert a board y square coord to a screen y coord.
; This means our y coords are, internally, all "backwards" - but who cares?
yCoordToPixel(y)
{
global SG_SIZE_Y
global SG_ORIGIN_Y
global SG_OFFSET_Y
global SG_SQUARES_Y
; SG_SQUARES_Y - y as we're working from the bottom for highest scores.
;return ( ( SG_SQUARES_Y - y + 1 ) * SG_SIZE_Y ) + SG_ORIGIN_Y - SG_OFFSET_Y
; normal screen pixels - to conserve moves (lower risk of no moves)
if ( SG_TOP == 1 )
return ( y * SG_SIZE_Y ) + SG_ORIGIN_Y - SG_OFFSET_Y
else
return ( ( SG_SQUARES_Y - y + 1 ) * SG_SIZE_Y ) + SG_ORIGIN_Y - SG_OFFSET_Y
}
; Convert a board square x coord to a screen x coord.
xCoordToPixel(x)
{
global SG_SIZE_X
global SG_ORIGIN_X
global SG_OFFSET_X
return ( x * SG_SIZE_X ) + SG_ORIGIN_X - SG_OFFSET_X
}
; Make the mouse move a piece.
movePiece(x1, y1, x2, y2)
{
global SG_DRAG_OK
global SG_ORIGIN_X
global SG_ORIGIN_Y
global SG_LAST_X
global SG_LAST_Y
SG_LAST_X := x1
SG_LAST_Y := y1
;MsgBox, Moving from %x1% , %y1% to %x2% , %y2%, set last = %SG_LAST_X% , %SG_LAST_Y%
getWindow()
if (SG_DRAG_OK == 1)
{
MouseClickDrag, L, xCoordToPixel(x1), yCoordToPixel(y1), xCoordToPixel(x2), yCoordToPixel(y2), 2
}
else
{
MouseClick, L, xCoordToPixel(x1), yCoordToPixel(y1)
Sleep, 100
MouseClick, L, xCoordToPixel(x2), yCoordToPixel(y2)
Sleep, 100
}
; Move to home point to avoid hilighting pieces.
MouseMove, SG_ORIGIN_X, SG_ORIGIN_Y
; Wait for pieces to fall.
Sleep, 1000
}
; Check that the piece in an array coord is not out of bounds,
; and is the same color.
isSameAt(col, x, y)
{
; Generic global to include array.
global
if (x < 1 || x > SG_SQUARES_X || y < 1 || y > SG_SQUARES_Y )
{
;MsgBox, returning false as OOB ( %x% < 1 || %x% > %SG_SQUARES_X% || %y% < 1 || %y% > %SG_SQUARES_Y% )
return false
}
ax := SG_ARR_%x%_%y%
if ( SG_ARR_%x%_%y% == col )
{
;MsgBox, returning true as %ax% == %col% and none of ( %x% < 1 || %x% > %SG_SQUARES_X% || %y% < 1 || %y% > %SG_SQUARES_Y% )
return true
}
;MsgBox, returning false as %ax% != %col% though none of ( %x% < 1 || %x% > %SG_SQUARES_X% || %y% < 1 || %y% > %SG_SQUARES_Y% )
return false
}
; An extremely nasty bruteforcism: tries each possible move in turn.
; If it finds one, it does it.
; Unfortunately, for the SG_ARR stuff, need all globals defined.
getMove()
{
global
Loop, %SG_SQUARES_Y%
{
y = %A_Index%
py := xCoordToPixel(y)
y1 := ( y + 1 )
y2 := ( y + 2 )
y3 := ( y + 3 )
y_1 := ( y - 1 )
y_2 := ( y - 2 )
y_3 := ( y - 3 )
Loop, %SG_SQUARES_X%
{
x = %A_Index%
; Anti-stick: don't play the same piece twice in a row
; If it's the only playable square, we'll get it next time round.
if ( SG_LAST_X == x && SG_LAST_Y == y )
{
; Zero them so we can get this square next time if it's the only one.
SG_LAST_X = 0
SG_LAST_Y = 0
Continue
}
px := xCoordToPixel(px)
x1 := ( x + 1 )
x2 := ( x + 2 )
x3 := ( x + 3 )
x_1 := ( x - 1 )
x_2 := ( x - 2 )
x_3 := ( x - 3 )
col := SG_ARR_%x%_%y%
;MsgBox, At %x%, %y% comparing %col% , %x2% , %y% And %col%, %x3%, %y%
; X_xx
if ( isSameAt(col, x2, y) && isSameAt(col, x3, y) )
{
movePiece( x, y, x1, y)
return
}
; xx_X
else if ( isSameAt(col, x_2, y) && isSameAt(col, x_3, y) )
{
movePiece( x, y, x_1, y)
return
}
; X
; _
; x
; x
else if ( isSameAt(col, x, y2) && isSameAt(col, x, y3) )
{
movePiece( x, y, x, y1)
return
}
; x
; x
; _
; X
else if ( isSameAt(col, x, y_2) && isSameAt(col, x, y_3) )
{
movePiece( x, y, x, y_1)
return
}
; x_
; x_
; _X
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x_1, y_2) )
{
movePiece( x, y, x_1, y)
return
}
; _x
; _x
; X_
else if ( isSameAt(col, x1, y_1) && isSameAt(col, x1, y_2) )
{
movePiece( x, y, x1, y)
return
}
; _X
; x_
; x_
else if ( isSameAt(col, x_1, y1) && isSameAt(col, x_1, y2) )
{
movePiece( x, y, x_1, y)
return
}
; X_
; _x
; _x
else if ( isSameAt(col, x1, y1) && isSameAt(col, x1, y2) )
{
movePiece( x, y, x1, y)
return
}
; X__
; _xx
else if ( isSameAt(col, x1, y1) && isSameAt(col, x2, y1) )
{
movePiece( x, y, x, y1)
return
}
; _xx
; X__
else if ( isSameAt(col, x1, y_1) && isSameAt(col, x2, y_1) )
{
movePiece( x, y, x, y_1)
return
}
; __X
; xx_
else if ( isSameAt(col, x_1, y1) && isSameAt(col, x_2, y1) )
{
movePiece( x, y, x, y1)
return
}
; xx_
; __X
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x_2, y_1) )
{
movePiece( x, y, x, y_1)
return
}
; x_
; _X
; x_
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x_1, y1) )
{
movePiece( x, y, x_1, y)
return
}
; _x
; X_
; _x
else if ( isSameAt(col, x1, y_1) && isSameAt(col, x1, y1) )
{
movePiece( x, y, x1, y)
return
}
; _X_
; x_x
else if ( isSameAt(col, x_1, y1) && isSameAt(col, x1, y1) )
{
movePiece( x, y, x, y1)
return
}
; x_x
; _X_
else if ( isSameAt(col, x_1, y_1) && isSameAt(col, x1, y_1) )
{
movePiece( x, y, x, y_1)
return
}
}
}
; MsgBox, Unable to find a move
}
; Convert a hex value to a colour letter, from:
; r(ed)c(yan)g(reen)y(ellow)o(range)b(lue)m(agenta)w(hite).
; Per: r rg=o gr=y g gb=c bg=c b rb=m br=m
hex2Color(color)
{
r := ( ( color >> 16 ) & 0xFF )
g := ( ( color >> 8 ) & 0xFF )
b := ( color & 0xFF )
if (r > g && r > b )
{
col = r
min := ( r * 0.5 )
if (min <= g && min <= b )
col=w
if (min <= g && min > b ) ; dodgy yellow test.
if (r - g > 10)
col=o
else ; numbers too similar, still yellow.
col=y
if (min > g && min <= b )
col=m
}
if (g >= r && g >= b )
{
col = g
min := ( g * 0.6 )
if (min <= r && min <= b )
col=w
if (min <= r && min > b )
col=y
if (min > r && min <= b )
; col=c ; commented since there ARE no cyan pieces in the test game
col=b
}
if (b >= r && b >= g )
{
col = b
min := ( b * 0.6 )
if (min <= r && min <= g )
col=w
if (min <= r && min > g )
col=m
if (min > r && min <= g )
; col=c ; commented since there ARE no cyan pieces in the test game
col=b
}
if ( SG_DEBUG == 1 ) {
MsgBox, Colour %color%=%col% r:%r% g:%g% b:%b%
}
return col
}
; Search if combat is over
gameOver()
{
ImageSearch, FoundX, FoundY, 270, 190, A_ScreenWidth, A_ScreenHeight, victory.bmp
if (ErrorLevel = 2) {
;MsgBox Could not conduct the search.
;return false
}
else if (ErrorLevel = 1) {
;MsgBox Icon could not be found on the screen.
;return false
}
else {
MsgBox The victory image was found at %FoundX%x%FoundY%.
return true
}
ImageSearch, FoundX, FoundY, 270, 190, A_ScreenWidth, A_ScreenHeight, defeat.bmp
if (ErrorLevel = 2) {
;MsgBox Could not conduct the search.
;return false
}
else if (ErrorLevel = 1) {
;MsgBox Icon could not be found on the screen.
;return false
}
else {
MsgBox The defeat image was found at %FoundX%x%FoundY%.
return true
}
return false
}
;Return true if indicator is over our head
myTurn()
{
PixelGetColor, turn_color, 101, 107, RGB
turn_c := hex2Color(turn_color)
;MsgBox %turn_color% %turn_c%
if (turn_c == "o") ;orange = my turn, white = not my turn
return true
sleep 100
return false
}
; To reduce illegal moves
waitForMyTurn()
{
Loop
{
if ((a_index > 100) || (myTurn()))
break ; Terminate the loop
;MsgBox, a_index = %a_index% ; This will display only the numbers 20 through 25
}
} |
|
|
| Back to top |
|
 |
vixay
Joined: 12 Jun 2008 Posts: 15
|
Posted: Thu Jun 12, 2008 10:33 am Post subject: Attachments |
|
|
I can't attach the bitmaps here, but basically they are the copped screen cap of the word Victory/Defeat after you play the game.
Wrote this primarily to beat the easy opponents/boring puzzles. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|