最近春節,qq上出了一個叫穿越福城的小游戲。游戲的玩法類似挑一挑,也是通過一個個木樁。只不過把跳的過程變成了搭梯子。按的時間越長,梯子越長。梯子過長或者過短小企鵝都會掉下去,游戲失敗。我的目的是用python來實現自動玩游戲。(主要原因是我手殘。。沒辦法,只好另辟蹊徑,技術開掛)。在剛開始構思的時候,我其實是覺得挺簡單的一個小腳本就能搞定。但是在實際編碼和測試的過程中,我越發覺得想要完成一個簡陋版本,勉強能用的版本非常容易。但是想要做到穩定性好,准確率高實在是不容易。下面我就把我這兩天的編碼和完善過程記錄下來。
先說說我的總體思路。通過adb的截圖功能獲得截圖,然后根據獲得的截圖計算出應該按壓多少毫秒,再通過adb shell input swipe來按壓指定毫秒數。循環往復,理論上可以一直刷到無限分。
這里面的難點顯然是在第二步,即怎樣根據截圖計算毫秒數呢?
那我們首先要思考毫秒數和什么變量有關,再從圖片中提取或者計算出變量即可。梯子是按得時間越長就越長,所以可以認為按得時間t應該和木樁之間的距離成線性關系。那我們怎樣從圖片上計算起始木樁和目標木樁之間的距離呢?第一想法肯定是在圖片中找到起始點x0,y0,再找到目的點x1,y1.計算這兩個點的歐氏距離。但是玩這個游戲會發現,如果木樁之間的距離很長,游戲中會拉高視角。所以要想獲得木樁之間的實際距離,不能光考慮像素之間的距離,還要考慮視角高度。視角越高,一個像素點代表的實際距離就越長。所以綜上,時間和兩個因素有關,一是像素距離,而是視角高度。
第一個因素像素距離,想要獲取這個參數的關鍵在於怎樣確定起點和終點。一個圖片在計算機中就是一個矩陣,在矩陣中怎樣找到起點和終點?這就需要明確起點和終點的特征。根據特征找到滿足特征的像素,進而就可以找到起點和終點。從截圖可以發現,起點的明顯特征就是深色的小企鵝,在明艷的背景中,只有小企鵝是深色的。所以找圖片中rgb均小於50的像素點,就可以定位小企鵝所在的位置。終點就更好確定了,每個木樁的中心都有一塊紅色菱形。這些紅色菱形的rgb都是一樣的。找這個rgb值就可以找到這些菱形,那么怎么知道哪個菱形是目標點呢?觀察可知,在小企鵝上方的,且滿足紅色菱形的是目標點。找到了起點和終點,我們就可以算出來dis(distance)
第二個因素是視角高度。這個就比較抽象了,改用什么表示呢?視角高度不好直接計算,但是有辦法體現出來。視角高度越高,相同面積的東西所占的像素數量就越少,也就是近大遠小。而觀察游戲可知,每個木樁上的紅色菱形的面積是一定的。所以我們可以用目標點紅色菱形的像素數(size)來表示視角高度。像素數越多,視角高度越低;像素數越少,視角高度越高。
現在找到了計算dis和size的方法,那么按壓時間t怎么計算呢?首先設置一個參數a,用於調整系數。
t = a*dis/sqrt(size)
dis越大,顯然按壓時間應該越長。size越大,說明視角越低,顯然按壓時間應該越短。那么為什么size要開一個平方根呢?這是因為dis是一次的長度,而size是二次的面積。所以要開一個平方根,保證量綱一致。a由實驗測得。經過實驗我發現a=30左右的時候,程序運行良好,雖然做不到每次都非常精准,但是大部分時候都是可以通過的。
到這里為止,我的小程序已經基本可以大部分時候100+了。運氣比較好的時候我還拿到了273分。但是在一次次測試中也暴露出了很多問題。接下來開始我的調試之路。
1、廣告干擾
觀察上圖,本來我的起始點是根據顏色判斷的。結果廣告中也出現了相同的色彩,從顏色來確定起始點的路子走不通了,怎么辦?那只好找其他特征。什么特征呢?那就是
1、企鵝是實心的
2、企鵝是近似圓形的
我之前都是用PIL的,現在不根據顏色了,就需要用更加高級和復雜的python-opencv了。先二值化,只保留深色部分,然后用findContours找邊緣,然后篩選出滿足條件的contour即可。這樣一來找對起點的准確率就極高啦。
第二個問題:准確率不高。顯然我建立的模型和游戲的內部邏輯還是有一定的差距。
怎么解決?從數學上來說,就是要確定一個二元函數time=f(dis,size).為了找到這個函數到底是啥,我首先得采集足夠多的樣本點。
采集了300個樣本點后,繪制出dis-size函數,發現如下圖所示
這說明和我原先想的不一樣,這不是一個連續函數,而是一個離散的函數。(dis,size)一共只有十六中組合。
既然這樣就好辦了。先kmeans聚類,划分成16類,找到每一類的dis,size,time,作為table記錄到程序中。每次獲得一個dis和size,查找table,找到最先進的dis和size所對應的time,然后用adb按相應的time即可。
經過這么已改進,准確率極高。幾乎每一次都是三分。當然其中的time參數由於是取得平均數,和真正的准確值還有一定的差距,在偶爾不是三分的情況下還要對time進行改進。
經過這些改進這個程序可以說已經基本可以跑了。我寫了兩個版本的代碼,一個是aaa.py,這個是使用t=dis/sqrt(size)方法的;另一個是bbb.py,這個是使用table版本的。table版本的正確率更加高。
代碼放在github上:https://github.com/blacksungrass/pythons/tree/master/qq%E6%96%B0%E5%B9%B4%E5%B0%8F%E6%B8%B8%E6%88%8F%E8%87%AA%E5%8A%A8%E5%8C%96
即使經過了改進,還是有一些問題,不過出現的次數很少
1、這個小企鵝有時候會跳起來轉個圈,截圖如果截取的是小企鵝挑起來的圖會造成誤判斷
2、有時候游戲中的一些背景建築,尤其是塔之類的,會把小企鵝擋住一小塊,導致findContours函數無法將小企鵝識別為一個整體。
,
