Jump to content

Ever Play A Game Called Collapse?


Recommended Posts

Hello all,

I'm trying to come up with a bot that will play a game called Collapse. I'm doing this as a challenge for myself because I figured it would be pretty difficult to come up with an app with the logic needed to play it and also to be very fast.

What I've done so far:

Figured out a way to find the game on the screen.

Decipher the different color boxes and bombs for the game. *

Store the position and color of each box for later usage.

Destroy bombs before boxes.

* I'm currently using pixelchecksum() for simplicity, but I'll most likely change that to a 4 or 5 point pixelgetcolor().

What I need help/suggestions to do:

Come up with a way to find all boxes of the same color that are connected (3 or more).

Come up with a faster screen searching method for boxes/bombs.

Here's my code so far:

#include <Array.au3>

#region Globals
Const $Title = "Collapse - Microsoft Internet Explorer"
Global $FirstRun = 1
Global $StartX = 337
Global $StartY = 393
Const $BoxRed   = 3183926199
Const $BoxGreen     = 426970639
Const $BoxBlue  = 1410215416
Const $BoxWhite     = 3294800457
Const $BoxGrey  = 3059036688
Const $BoxEmpty     = 50331649
Const $BombRed  = 1990514232
Const $BombGreen    = 1332283690
Const $BombBlue     = 904996846
Const $BombBlack    = 3050855186
Const $BombWhite    = 3039844320
Global $Boxes[1]
Global $PosX[1]
Global $PosY[1]
#endregion Globals

#region Main Loop
While 1
    If (WinActive($Title)) Then
        If ($FirstRun) Then
            $FirstRun = _FindFirstBox()
            MouseMove($StartX,$StartY,0)
        Else
            $time = TimerInit()
            _FindBomb()
            _UpdateBoxes()
        EndIf
    EndIf
    Sleep(10)
WEnd
#endregion Main Loop

Func _GetBoxColor($X,$Y = -1)
    Local $Checksum = 0
    If ($X > -1 And $Y > -1) Then
;Each box/bomb is 15x15 pixels (well, what we want anyways)
        $Checksum = PixelChecksum($X,$Y,$X+15,$Y+15)
        
        Select
            Case ($Checksum == $BoxRed)
                Return "Red Box"
            Case ($Checksum == $BoxGreen)
                Return "Green Box"
            Case ($Checksum == $BoxBlue)
                Return "Blue Box"
            Case ($Checksum == $BoxWhite)
                Return "White Box"
            Case ($Checksum == $BoxGrey)
                Return "Grey Box"
            Case ($Checksum == $BoxEmpty)
                Return "Empty Box"
            Case ($Checksum == $BombRed)
                Return "Red Bomb"
            Case ($Checksum == $BombGreen)
                Return "Green Bomb"
            Case ($Checksum == $BombBlue)
                Return "Blue Bomb"
            Case ($Checksum == $BombBlack)
                Return "Black Bomb"
            Case ($Checksum == $BombWhite)
                Return "White Bomb"
            Case Else
                MouseMove($X,$Y,0)
                MsgBox(0,"GetBoxColor","Unknown Color: " & $Checksum)
                Return "Unknown Color: " & $Checksum
        EndSelect
    ElseIf ($X > -1 And $Y == -1) Then
        Return $Boxes[$X]
    Else
        Return 0
    EndIf
EndFunc;==>_GetBoxColor(X,Y)

Func _UpdateBoxes()
    Local $iterX = 0
    Local $iterY = 0
    
    For $iterX = $StartX To ($StartX-264) Step -24
        For $iterY = $StartY to ($StartY-336) Step -24
            _ArrayAdd($Boxes,_GetBoxColor($iterX,$iterY));Store the color of the box
            _ArrayAdd($PosX,$iterX)             ;Store the X position of the box
            _ArrayAdd($PosY,$iterY)             ;Store the Y position of the box
        Next
    Next
EndFunc;==>_UpdateBoxes()

Func _FindAdjacentBox($X,$Y,$Color)
    Local $Information[3]
    Local $Found
;Find a box that is next to the current position (X,Y) and is
;the same color (color checksum) and return it as an array
    If ($Found) Then
        $Information[0] = $X
        $Information[1] = $Y
        $Information[2] = $Color
    Else
        $Information[0] = -1
        $Information[1] = -1
        $Information[2] = -1
    EndIf
    Return $Information
EndFunc;==>_FindAdjacentBox(X,Y)

Func _FindFirstBox()
    $WinInfo = WinGetPos($Title)
    If (Not @error) Then
        $pos = PixelSearch($WinInfo[0],$WinInfo[1],($WinInfo[0] + $WinInfo[2]),($WinInfo[1] + $WinInfo[3]),0xCC962C)
        If (Not @error) Then
            $StartX = $pos[0] - 26
            $StartY = $pos[1] - 42
            Return 1
        EndIf
    EndIf
EndFunc;==>_FindFirstBox()

Func _FindBomb()
    Local $iter = 1
    For $iter = 1 to UBound($Boxes)
        If (StringInStr($Boxes[$iter],"Bomb")) Then
            MouseClick("left",$PosX[$iter],$PosY[$iter])
            Sleep(1000)
            ExitLoop
        EndIf
    Next
EndFunc;==>_FindBomb()

Note that _GetBoxColor() will poll the storage array or the current screen position depending on the agruments supplied (so I can use the same function for simplicity). The unfinished function _FindAdjacentBox() is going to be the logic heavy portion of the code. The _FindFirstBox() function finds a single unique pixel on the screen and calculates the position of the bottom-right box. The update function reads all boxes from the bottom up and right to left.

I'm having a real mental block trying to come up with a way to find connected boxes efficiently. I will also need to decide if/when to click bombs. Black bombs destroy everything within 5-6 boxes of itself. Every other color bomb destroys all boxes of that color currently on the screen (I.E. A Red bomb destroys all red boxes).

Here is a screenshot of the game with some highlighting I've included to show how the logic should work for finding connected boxes (3 or more). Once it finds a set of boxes, it needs to click on it and then refresh the list of boxes.

Posted Image

So, the basic loop rundown of this bot is:

1.) Search for a bomb, click on it, go to step 1

2.) Update the list of boxes

3.) Find a set of 3 or more same colored boxes that are connected and click on it

4.) Repeat

Any suggestions would be greatly appreciated,

CMR

Edited by CodeMaster Rapture
Link to comment
Share on other sites

I think it might be easier (but not as bottish) to just have it click really fast nonstop and let you move around to wherever you want it to click.

A little unrelated - what's your high score? I just played for the first time and got to level 9 with a score of 210,436.

Link to comment
Share on other sites

Hello again,

I've been working on the logic part of my bot and I think I've got it down, I'm just not too sure where I should call it. Here's the code I've got:

Global $Tracked[1]

Func _FindAdjacentBox($X,$Y,$Color)
    Local $Found
    Local $iter
;Find a box that is next to the current position (X,Y) and is the same color (color checksum)
    While ($Found)
        For $iter = 1 To (UBound($Boxes)-1) Step 1
            If ($Boxes[$iter] == $Color) Then
                If   ($PosX[$iter] == ($X-15) And $PosY[$iter] == $Y) Then
                    _ArrayAdd($Tracked,$iter)
                    $X -= 15
                    ExitLoop
                ElseIf ($PosX[$iter] == ($X-15) And $PosY[$iter] == ($Y-15)) Then
                    _ArrayAdd($Tracked,$iter)
                    $X -= 15
                    $Y -= 15
                    ExitLoop
                ElseIf ($PosX[$iter] == ($X-15) And $PosY[$iter] == ($Y+15)) Then
                    _ArrayAdd($Tracked,$iter)
                    $X -= 15
                    $Y += 15
                    ExitLoop
                ElseIf ($PosX[$iter] == $X And $PosY[$iter] == ($Y-15)) Then
                    _ArrayAdd($Tracked,$iter)
                    $Y -= 15
                    ExitLoop
                ElseIf ($PosX[$iter] == $X And $PosY[$iter] == ($Y+15)) Then
                    _ArrayAdd($Tracked,$iter)
                    $Y += 15
                    ExitLoop
                ElseIf ($PosX[$iter] == ($X+15) And $PosY[$iter] == $Y) Then
                    _ArrayAdd($Tracked,$iter)
                    $X += 15
                    ExitLoop
                ElseIf ($PosX[$iter] == ($X+15) And $PosY[$iter] == ($Y+15)) Then
                    _ArrayAdd($Tracked,$iter)
                    $X += 15
                    $Y += 15
                    ExitLoop
                ElseIf ($PosX[$iter] == ($X+15) And $PosY[$iter] == ($Y-15)) Then
                    _ArrayAdd($Tracked,$iter)
                    $X += 15
                    $Y -= 15
                    ExitLoop
                Else
                    $Found = Not $Found
                EndIf
            EndIf
        Next
    WEnd

;Ok, we found 3 or more adjacent boxes, let's destroy them.
    If ((UBound($Tracked)-1) > 2) Then
        MouseClick("left",$PosX[$Tracked[1]],$PosY[$Tracked[1]])
        ReDim $Tracked[1]
        Return
    EndIf
EndFunc ;==>_FindAdjacentBox(X,Y)

I figure this is the best method to find connected boxes (8 points around the current box), but I need a little help to exclude the previos box(es) I've tracked. Any ideas on how to go about that? I also am unsure of where to call this function for the best performance.

Thanx,

CMR

Edited by CodeMaster Rapture
Link to comment
Share on other sites

I was thinking a little about this, and I decided on a very few things.

1. You don't actually need to check all 8 spaces around a block - only the vertical and horizontal 4 (up, right, down, left, not diagonal). Since blocks aren't considered connected if they are attached diagonally, there's no point in checking.

2. Since the blocks shift when you click a group, you shouldn't check all of the blocks for possible groups - just go through each row checking for neighbors, and if there is a group, click it and start over. Otherwise, you'll be checking stuff that doesn't exist. Although, now that I think about it, checking for neighbors as you go will take care of shifts in blocks....

This is a fun challenge... hopefully the code will be quick enough.

Link to comment
Share on other sites

I was thinking a little about this, and I decided on a very few things.

1. You don't actually need to check all 8 spaces around a block - only the vertical and horizontal 4 (up, right, down, left, not diagonal). Since blocks aren't considered connected if they are attached diagonally, there's no point in checking.

2. Since the blocks shift when you click a group, you shouldn't check all of the blocks for possible groups - just go through each row checking for neighbors, and if there is a group, click it and start over. Otherwise, you'll be checking stuff that doesn't exist. Although, now that I think about it, checking for neighbors as you go will take care of shifts in blocks....

This is a fun challenge... hopefully the code will be quick enough.

Ya know... that's a good point. I didn't even think of the diagonals. Thank you. As for the "shifting", that won't really be a problem. Since it would take far too much code to track how the blocks "shift", I decided to just click and then update my list of boxes. Well, there goes 4 less boxes to check per cycle!

Thanx so much,

CMR

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