Diamond Dash 的 Python BOT

Posted by TJ Wei on 星期六, 11月 10, 2012 with No comments

Diamond Dash 是 Facebook 以及 iOS 上面常見的社群 Puzzle Game,其實沒有怎麼在玩,所以也只有十幾級而已。玩的時候想起了以前寫的寶石方塊機器人。發現我已經記不太清楚那時候是在什麼平台下面,用什麼語言寫的了。翻了很久硬碟,才找到程式碼。我的收納習慣太糟,如果沒有放在 blog 上,大概就找不到了。 所以改寫了一下,成為 Diamond Dash 版,放在這裡。
功能很簡單,就是抓螢幕的圖,然後用白點在遊戲視窗標出可以消去的方塊。
程式寫得很草率,只是剛好能動。需要 pywin32,只適用於 windows 下的 firefox 。
而且最重要的是,其實對分數沒有什麼幫助。
import win32ui, win32gui, win32con
import time

def find_windows_by_title(title):
    wins=[]
    win32gui.EnumWindows(lambda i,e:e.append(i) ,wins)
    return [w for w in wins if title in win32gui.GetWindowText(w)]

def get_child_windows(w):
    wins=[]    
    try:
        win32gui.EnumChildWindows(w, lambda i,e:e.append(i) ,wins)
    except:
        pass    
    return wins

def find_game_windows():    
    browser_windows=find_windows_by_title("Diamond Dash")    
    child_windows=sum(map(get_child_windows, browser_windows),[])
    cond1=lambda r:(r[2]-r[0],r[3]-r[1])==(760,500)
    cond2=lambda i:win32gui.IsWindowVisible(i)
    cond=lambda i:cond1(win32gui.GetWindowRect(i)) and cond2(i)
    return filter(cond, child_windows)

def get_color(bits):
    return ord(bits[2])|(ord(bits[1])<<8)|(ord(bits[0])<<16)

def do_the_math(m):
    gmap=[[[(j,i)] for i in range(10)] for j in range(9)]    
    for j in range(9):
        for i in range(10):            
            if j>0 and m[j][i]==m[j-1][i]:
                gmap[j-1][i].extend(gmap[j][i])
                gmap[j][i]=gmap[j-1][i]
            if i>0 and m[j][i]==m[j][i-1]:
                gmap[j][i-1].extend(gmap[j][i])
                for j2,i2 in gmap[j][i]:
                    gmap[j2][i2]=gmap[j][i-1]
    for j in range(9):
        for i in range(10):
            gmap[j][i]=len(gmap[j][i])
    return gmap

def main_loop(win):
    dc=win32ui.CreateDCFromHandle(win32gui.GetDC(win))
    mem_dc=dc.CreateCompatibleDC()
    bitmap = win32ui.CreateBitmap()
    # 400 = 40 pixels * 10 diamonds
    # 360 = 40 pixels * 9 diamonds
    bitmap.CreateCompatibleBitmap(dc,400,360)
    mem_dc.SelectObject(bitmap)
    # 160=40 pixels * 4 colors(RGBA).
    # 1600=160 * 10 diamonds
    row=lambda s:[get_color(bits[i:i+3]) for i in range(s,s+1600,160)]
    while 1:
        time.sleep(0.005)
        mem_dc.BitBlt((0, 0), (400, 360), dc, (81+15, 92+15), win32con.SRCCOPY)
        bits = bitmap.GetBitmapBits(True)            
        # 64000 = 1600 * 40 576000=64000 * 9
        matrix=map(row, range(0, 576000, 64000))
        rtn=do_the_math(matrix)
        for j,y in enumerate(range(92,450,40)):
            for i,x in enumerate(range(81,480,40)):
                box=(x+20,y+20,x+30,y+30)
                if rtn[j][i]>=3:
                    dc.FillSolidRect(box, 0xffffff)
                    
wins=find_game_windows()
print "find", wins
if wins:
    main_loop(wins[-1]) # Using the last window works for me.
else:
    print "Unable to find games."
Categories: