程序員玩連連看的正確姿勢

too young too simple

一造寝、絕地反擊

最近女票迷上了某平臺的連連看對戰(zhàn)小游戲家妆,于是免不了要找哥哥我 PK 一翻,雖然是被迫卷入戰(zhàn)爭簸呈,但是以朕驚世駭俗的智商榕订,那當然是勝券在握啦~~
沒曾想,幾個回合下來蜕便,竟被啪啪啪打臉劫恒,快把這個月的口糧都輸光了(每把5塊錢啊,肉疼M嫒埂<婷场)
哎,完全拼手速是沒有希望的了吃溅,得想辦法讓連連看自動打

“連連看”都不會打的直男們溶诞,趕緊去懟一局

二、可行性

前段時間跳一跳火起來的時候决侈,有人就通過 adb 截屏并發(fā)送到電腦分析螺垢,再求得距離然后計算出按鍵時長,最后通過 adb shell 自動按鍵赖歌,從而獲得完美跳跳分枉圃,這一招用在連連看是否管用呢?
理論上庐冯,靠譜孽亲,分解如下:

  1. adb 截圖傳到電腦
  2. 將連連看的點擊區(qū)域識別為一個二維矩陣,每一種小動物用一個數(shù)字表示
  3. 對二維矩陣求解展父,計算出每個位置的點擊順序數(shù)組
  4. 通過 adb shell 一把梭返劲,一次性點掉所有

醬紫如果順利的話并且不被女票發(fā)現(xiàn),贏回三個月的口糧都很有希望呀~~

三栖茉、實施步驟

技術(shù)選型

從上一節(jié)的分析來看篮绿,方案的實施涉及到很多圖片的分析處理,Python 可以方便的調(diào)用很多圖片庫吕漂,而且網(wǎng)上也有很多作業(yè)可以抄亲配,所以選擇基于 Python 來做

環(huán)境搭建

沒有很具體的安裝步驟,需要的咨詢谷歌哥

1) 安裝 adb 環(huán)境惶凝。安裝完成后吼虎,用數(shù)據(jù)線連接一臺 android 手機,執(zhí)行一些簡單的 adb 命令預熱下

// 是否連接上
adb devices

// 可否截屏保存
adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png /yourDocuments/screenshot.png

// 可否點擊屏幕
adb shell input tap 100 100

2)安裝 python 和相關(guān)的圖片庫苍鲜,在安裝 openCv 的時候還踩了個大坑思灰,記錄了下,僅供參考

圖片處理

1)截屏保存
在終端坡贺,執(zhí)行如上的兩個 adb 命令就可以截屏保存了官辈,也就是說箱舞,這里需要一個可以調(diào)用終端命令,同時可以等待返回的 Python 方法:

// 執(zhí)行終端命令的方法
def sh(command):
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    print p.stdout.read()

// 截屏保存
sh('adb shell /system/bin/screencap -p /sdcard/screenshot.png')
sh('adb pull /sdcard/screenshot.png /yourDocuments/screenshot.png')

2)裁剪有效區(qū)域拳亿、再等比切出小動物頭像
如果不要求很通用只是對你的手機有效的話晴股,那么只需要將第一步截下來的屏幕用工具來量一量(如 Mark Man),就可以用如下方式裁剪出有效區(qū)域

from PIL import Image
def cut (im, x, y, w, h, name):
  region = im.crop((x, y, x+w, y+h))
  region.save("./screenshot/" + name + ".png")

# 有效點擊區(qū)域裁剪 (不通用的做法是肺魁,把這個矩形的坐標量出來)
gx = 43
gy = 401
gw = 993
gh = 1420
cut(Image.open("./screenshot/screenshot.png"), gx, gy, gw, gh, 'main')
有效區(qū)域

如果要做得通用一些电湘,就需要計算圖片的比例了(只用于打敗女票的,完全沒必要嘛)

然后再按照10行7列切成小塊鹅经,并且根據(jù)二維數(shù)組的下標命名

# -*-coding:utf-8-*-
from PIL import Image
import cutImg
def cut ():
  im = Image.open("./screenshot/main.png")
  # 圖片的寬度和高度
  img_size = im.size
  width = img_size[0]
  height = img_size[1]
  distanceW = width / 7
  distanceH = height / 10
  print(distanceW, distanceH)
  x = 0
  y = 0
  for num in range(0, 10):
    for i in range(0, 7):
      x = distanceW * i
      y = distanceH * num
      name = str(num) + str(i)
      cutImg.cut(im, x + 15, y + 15, distanceW - 20, distanceH - 20, name)
  return [distanceW, distanceH]

小動物頭像

3)解析小動物頭像輸出數(shù)字二維矩陣(第一回合)

這一步著實需要下功夫寂呛,還踩了不少坑~~

首先想到的是通過求解圖片的 hash 值,利用 hash 值來比對圖片的相似度(例如感知 hash 算法)瘾晃。網(wǎng)上有各種求 hash 值的算法贷痪,實現(xiàn)起來倒也簡單,但是蹦误,比較的正確率只能達到百分之七劫拢、八十(這樣我們分析出的點擊路徑,肯定打不過啦G恳取舱沧!),主要是這些小動物頭像在 hash 算法下顯得都太相似了偶洋,拿感知哈希算法來說:
a) 縮小圖片尺寸
b) 轉(zhuǎn)為灰度圖片
c) 計算灰度平均值
d) 比較像素的灰度
e) 計算哈希值
f) 對比圖片指紋

小豬頭

小猴頭

想象一下熟吏,上面的小豬頭和小猴頭經(jīng)過如上的變換后,還有多少差異呢玄窝?

轉(zhuǎn)念一想牵寺,這個問題在機器學習領(lǐng)域,不過是那種最最簡單的分類問題哆料,so缸剪,完全可以先訓練一個模型出來

4)解析小動物頭像輸出數(shù)字二維矩陣(第一回合)
Turicreate 是蘋果開源的基于 python 機器學習框架吗铐,特點是輕量(只是分類相似的圖片而已东亦,當然是越簡單越好),先安裝之

然后將上面寫好的截屏裁剪代碼多執(zhí)行幾次唬渗,手工分類典阵,準備好訓練數(shù)據(jù):


分類存儲

0

給每種小動物創(chuàng)建一個文件夾,再將所有該種類的動物裝進去

開始訓練镊逝,并保存模型:

#!/usr/bin/env python
#encoding=utf-8
import turicreate as tc
img_folder = 'data'
// 導入數(shù)據(jù)
data = tc.image_analysis.load_images(img_folder, with_path=True)
// 使用文件名來做標簽
data['label'] = data['path'].apply(lambda path: path.split('/')[len(path.split('/')) - 2])
data.save('doraemon-walle.sframe')
// 百分之八十的數(shù)據(jù)用于訓練壮啊,百分之二十用于測試
train_data, test_data = data.random_split(0.8, seed=2)
// 開始訓練模型
model = tc.image_classifier.create(train_data, target='label')
// 測試模型
predictions = model.predict(test_data)
metrics = model.evaluate(test_data)
// 輸出測試結(jié)果
print(metrics['accuracy'])
model.save('my_model_file')

執(zhí)行到倒數(shù)第二行的時候,順利輸出1.0(百分百的正確率有木有):


正確率100%

使用訓練好的模型撑蒜,輸出二維矩陣:

import turicreate as tc
loaded_model = tc.load_model('my_model_file')
def getDataset():
  data = tc.image_analysis.load_images('screenshot', with_path=True)
  arr = loaded_model.predict(data)
  result = []
  temp = []
  for index in range(len(arr)):
    if (index % 7 == 0):
      temp = []
    if ((index + 1) % 7 == 0):
      result.append(temp)
    // f 為 0歹啼,標記為未刪除
    temp.append({'v': int(arr[index]), 'f': 0})
  return result

路徑求解

1)判斷兩個動物圖標可連
需要滿足如下條件:
a) 相同的圖標
b) 兩種直接存在一條通路玄渗,它是一條只經(jīng)過沒有圖案的地方、且轉(zhuǎn)折點不超過2個的折線
具體代碼實現(xiàn)可以看看這篇博文的分析(雖然是 C 版)狸眼,這里我就不貼了藤树,繁瑣占篇幅

2) 搜索路徑,最簡單粗暴的一種做法
(1)從矩陣中挑出一個未被標記為刪除的元素拓萌,(2)再從矩陣中余下的不被標記刪除的元素尋找一個跟它一樣的元素岁钓,判斷是否可以相連,是則將兩個元素標記為刪除微王,并將點擊坐標壓入坐標數(shù)組屡限,否則重復(2),(3)重復(1)炕倘,知道找到所有的點擊坐標點
但是這種做法是 O(nXn)钧大,很遺憾,暫時也沒有想到更好的辦法罩旋,只是想到了一個小小的優(yōu)化策略拓型,開始先遍歷一輪,將所有挨著的相同圖標消掉(顯而易見的事情當然要先辦啦)瘸恼,減小 N劣挫,節(jié)省一下算法的時間

然后在“盲狙”的過程中,因為循環(huán)停止的條件是找到所有的坐標點东帅,假如游戲給了個無解的矩陣压固,或者咱們圖片識別錯了導致無解,就會陷入死循環(huán)(雖然這樣的概率極低靠闭,沒遇到過)帐我,所以要做一下循環(huán)保護

# 遍歷消除(盲狙)
def commonBuild():
  global data
  global pos
  for num in range(0, 10):
      for i in range(0, 7):
        item = data[num][i]
        if (item['f'] == 1):
          continue
        for ix in range(0, 10):
          if (item['f'] == 1):
            break
          for iy in range(0, 7):
            item1 = data[ix][iy]
            if (item1['f'] == 1 or item1['v'] != item['v'] or (ix == num and iy == i)):
              continue
            if (remove.canRemove(num, i, ix, iy, data) == 1):
              item['f'] = 1
              item1['f'] = 1
              pos.append(getPos(i, num))
              pos.append(getPos(iy, ix))
              break
// 達到 70 也即所有的坐標都找到即停止
// 否則也最多循環(huán)十次
count = 0
while (len(pos) < 70 and count < 10):
  count = count + 1
  commonBuild()
print(count)

很幸運,經(jīng)過優(yōu)化后的算法愧膀,基本上每次 count 都輸出為 1拦键,不需要遍歷太多次。假如真的出現(xiàn)了無解矩陣檩淋,循環(huán)了 10 次退出了芬为,那該如何是好呢?這個時候自己將機器沒有打完的點掉也應該沒有難度了

adb 一把梭

克服艱難險阻把坐標數(shù)組計算出來之后蟀悦,后面的事情就簡單了媚朦,執(zhí)行 adb 命令一把梭

for index in range(len(pos)):
  command = 'adb shell input tap ' + str(pos[index][0]) + ' ' + str(pos[index][1])
  print(command)
  os.system(command)

四、后來日戈,我贏了么?

然而并沒有Q拧!浙炼!
因為每條 adb 命令的執(zhí)行間隔基本差不多要到 1 秒份氧,逐條執(zhí)行完之后黃花菜都涼了唯袄,要知道正常人打完一局也就 30、40 秒蜗帜,作為機器人越妈,這打完居然要 1 分多鐘,真是弱智機器人

嘗試將命令寫入一個 sh 文件钮糖,然后通過 adb shell 執(zhí)行批處理文件梅掠,稍微快了一點點,但是依然還需要幾十秒(在此之前還嘗試寫一個堡壘 app 來一次性接收坐標店归,然后再 android 系統(tǒng)中執(zhí)行命令阎抒,都木有用)。然后優(yōu)化分析算法的動力都木有了

不過話說回來消痛,跟女票打游戲且叁,還要用贏的么?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秩伞,一起剝皮案震驚了整個濱河市逞带,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纱新,老刑警劉巖展氓,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脸爱,居然都是意外死亡遇汞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門簿废,熙熙樓的掌柜王于貴愁眉苦臉地迎上來空入,“玉大人,你說我怎么就攤上這事族檬⊥嵊” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵单料,是天一觀的道長埋凯。 經(jīng)常有香客問我,道長看尼,這世上最難降的妖魔是什么递鹉? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任盟步,我火速辦了婚禮藏斩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘却盘。我一直安慰自己狰域,他們只是感情好媳拴,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著兆览,像睡著了一般屈溉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抬探,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天子巾,我揣著相機與錄音,去河邊找鬼小压。 笑死线梗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的怠益。 我是一名探鬼主播仪搔,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蜻牢!你這毒婦竟也來了烤咧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤抢呆,失蹤者是張志新(化名)和其女友劉穎煮嫌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抱虐,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡立膛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了梯码。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宝泵。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖轩娶,靈堂內(nèi)的尸體忽然破棺而出儿奶,到底是詐尸還是另有隱情,我是刑警寧澤鳄抒,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布闯捎,位于F島的核電站,受9級特大地震影響许溅,放射性物質(zhì)發(fā)生泄漏瓤鼻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一贤重、第九天 我趴在偏房一處隱蔽的房頂上張望茬祷。 院中可真熱鬧,春花似錦并蝗、人聲如沸祭犯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沃粗。三九已至粥惧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間最盅,已是汗流浹背突雪。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涡贱,地道東北人挂签。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像盼产,于是被迫代替她去往敵國和親饵婆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,789評論 25 707
  • 在小島最愛的就是海戏售。 在小島的第三個夏天侨核,海邊的短袖短褲短裙,商場出租車猛開的空調(diào)灌灾,下午六點的白晝搓译。 夏天是從擦...
    一只溫柔鬼啊閱讀 377評論 0 1
  • 這是什么地方呢,是一個沒有沙塵的地方锋喜,是我去過只去了機場的地方些己,是我從飛機上往下看的時候,我就在思考嘿般,可能從那以后...
    麻木木閱讀 267評論 1 0
  • 在知乎炉奴、簡書逼庞、豆瓣等平臺常看到《要成功先自律》瞻赶、《有些獎勵只有自律之后才得到》赛糟、《自律后我的人生就像開掛一樣精彩》...
    是舒格閱讀 495評論 0 3
  • ①鵝媽媽磨耳朵30分鐘 ②海尼曼兩本。 ③《神奇的色彩女王》5遍 ④繪本《鄰居》2遍 ⑤磁力片一個小時砸逊。 ⑥拼圖1...
    韋鈺閱讀 168評論 0 0