近日,微信版本升級,小程序增加新類目「小遊戲」,已上線的「跳一跳」,在朋友圈還是引起不小的圍觀的。向來沒有多少遊戲天分的人,看著圈裡的三位數得分真是望塵莫及。
最近什麼最火?人工智慧啊!之前有關注自動化測試,一琢磨,我可是工程師啊,可以用程序來玩跳一跳。三思1秒鐘,可行,開始行動。
可行性初探:根據我玩「跳一跳」個位數得分的經驗,猜測遊戲的策略是,通過控制觸屏的時間長短,讓玩偶獲得不同的跳躍爆發力和跳躍距離,跳到敦子上。
疑問有二,其一,「跳一跳」遊戲場景是三位空間的,遊戲進行到後續,會不會轉變視角,即屏幕上測量的距離和三維空間的距離是否一致?其二,觸屏的時間長短,和跳躍距離的遠近,之間是什麼關係?
屏幕距離,容易操作,可以用尺子直接量,沒尺子怎麼辦?畫一個!
觸屏時間的控制,如果我能控制的好,得分就不是個位數了,所以還是打算交給程序來代勞。
首先,我們需要一些工具,讓電腦能控制手機,此類工具或框架,在APP開發,自動化測試領域用的很多,我們借鑑一下。
這裡選擇Total Control工具(使用Android系統),可以實現用戶用電腦滑鼠模擬觸屏操控手機。然後選擇Python腳本編程,可以實現用程序模擬滑鼠點擊Total Control界面。
經過一百多次試錯,針對「跳一跳」不同的跳躍距離(屏幕測量),調整觸屏時間(程序參數),得到以下數據:
最後我們來用Python畫圖,直觀展現數據,規律還是很明顯的,線性關係,以上兩個疑問解決。
實現Level2級別「跳一跳」自動玩法:
根據任務分解和智能話程度,設定三個目標Level:
在第三階段,自動識別出玩偶和墩子,在第二階段,採用「人工打卡」方式,指出玩偶和墩子的位置。(在工程師的實際問題解決中,很多事情,尚未完全自動化的情況下,開發一些工具,提高效率,依然是非常可觀的)
解決兩個問題:
自動計算距離,替代直尺
簡化操作流程,提高用戶體驗,「跳一跳」輕鬆玩
指出玩偶和墩子的位置,最直接就是用滑鼠點兩下,程序自動計算兩個點的距離,然後通過線性公式,轉化為觸屏時間參數。
但是我們不能直接在Total Control虛擬屏幕上點擊,因為會直接觸發控制執行跳躍,所以需要再次處理下。首先對虛擬屏幕截圖,然後在新截圖上打點,需要Python程序處理圖像視覺元素(使用Python wxPython庫開發圖形界面GUI程序)。
左邊是Total Control軟體顯示的手機屏幕,右邊是Python圖形程序界面(圖中兩個點是用滑鼠標記的玩偶和墩子距離)
視頻:
代碼:
import wx
from pymouse import PyMouse
import win32api, win32con
import matplotlib.pyplot as plt
import numpy as np
import time
m = PyMouse()
x_dim, y_dim = m.screen_size()
#print x_dim, y_dim
x = int(x_dim/4)
y = int(y_dim*3/4)
#print x, y
t = {
'6':'0.28',#
'7':'0.31',#
'8':'0.33',
'9':'0.40',
'10':'0.43',
'11':'0.46',
'11.5':'0.47',
'12':'0.49',
'13':'0.53',
'14':'0.57',
'15':'0.61',
'16':'0.63',
'17':'0.66',
'18':'0.70',
'19':'0.72',
'20':'0.75',
'20.5':'0.77',
'21':'0.80',
'22':'0.85',
'23':'0.90',
'24':'0.91',
'25':'0.95',
}
X = []
Y = []
for item in t.items():
X.append(float(item[0]))
Y.append(float(item[1]))
#print X,Y
Z1 = np.polyfit(X, Y, 1)
p1 = np.poly1d(Z1)
#print Z1
#print p1
# Z1[0] * X + Z1[1]
# a * (Z1[0] * X + Z1[1])
Y2 = []
for i in range(len(X)):
Y2.append(Z1[0]*X[i]+Z1[1])
#print Y[i], Y2[i], Y2[i]-Y[i]
#plt.plot(X, Y, 'bo', X, Y2, 'g')
#plt.show()
def click(x, y, s):
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x,y,0,0)
time.sleep(s)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x,y,0,0)
win32api.SetCursorPos((1000,100)) #
#
class MyApp(wx.App):
def __init__(self, redirect=False, filename=None):
wx.App.__init__(self, redirect, filename)
self.frame = wx.Frame(None, wx.ID_ANY, title='Hello World')
self.panel = wx.Panel(self.frame, wx.ID_ANY)
self.button1 = wx.Button(self.panel, 1001, "OK")
self.button1.SetPosition((210, 10))
self.button2 = wx.Button(self.panel, 1002, "Refresh")
self.button2.SetPosition((10, 10))
self.pos = [[0,0],[0,0]]
self.pos_n = 0
self.pos_d = 0
screen = wx.ScreenDC()
size = screen.GetSize()
print size
bmp = wx.EmptyBitmap(size[0], size[1])
mem = wx.MemoryDC(bmp)
mem.Blit(0, 0, 515, 800, screen, 200, 180) #
del mem # Release bitmap
#bmp.SaveFile('screenshot.png', wx.BITMAP_TYPE_PNG)
self.cap = wx.StaticBitmap(self.panel, -1, bmp, (10, 40))
# bind an event or two
self.cap.Bind(wx.EVT_LEFT_DOWN, self.OnDrawDot)
self.Bind(wx.EVT_BUTTON, self.OnOK, self.button1)
self.Bind(wx.EVT_BUTTON, self.OnRefresh, self.button2)
self.frame.Show()
def OnOK(self, evt):
if(self.pos_n == 2):
print "OK"
t_press = Z1[0] * self.pos_d + Z1[1]
print t_press
click(x, y, t_press)
else:
print "NOK"
time.sleep(2) #
self.OnRefresh(evt)
def OnRefresh(self, evt):
print "Refresh"
screen = wx.ScreenDC()
size = screen.GetSize()
bmp = wx.EmptyBitmap(size[0], size[1])
mem = wx.MemoryDC(bmp)
mem.Blit(0, 0, 515, 800, screen, 200, 180) #
del mem # Release bitmap
self.cap.SetBitmap(bmp)
self.pos = [[0,0],[0,0]]
self.pos_n = 0
def OnDrawDot(self, evt):
# Draw a dot so the user can see where the hotspot is
dc = wx.ClientDC(self.cap)
dc.SetPen(wx.Pen("RED"))
dc.SetBrush(wx.Brush("RED"))
pos = evt.GetPosition()
dc.DrawCircle(pos.x, pos.y, 4)
#print pos.x, pos.y
if(self.pos_n < 2):
self.pos[0] = self.pos[1]
self.pos[1] = [pos.x, pos.y]
self.pos_n = self.pos_n + 1
print self.pos
d = ((self.pos[0][0] - self.pos[1][0])**2 + (self.pos[0][1]-self.pos[1][1])**2)**0.5
self.pos_d = d / 12.75 #
print d, self.pos_d
#
if __name__ == '__main__':
app = MyApp()
app.MainLoop()
人工智慧,一種新方法:
未完待續,Level3級別「跳一跳」自動玩法稍後更新,人工智慧,是一種新方法,小遊戲純屬娛樂,歡迎關注公共號。