苦練技術是不可能的,這輩子不可能好好練習。學技術又學不進去,就只有靠輔助才能維持的生活這樣子。
2020.04.17 新添加自動適配分辨率,一般情況下,會根據手機分辨率自動縮放素材圖片大小和像素參數,並且上傳所有素材到百度網盤。
鏈接:https://pan.baidu.com/s/19Oh5irxQkOsP_WNBW2290Q 提取碼:grdu
2020/05/20 注意:該文章停止更新(因為github 太香了~),后續更新請移步 微信五子棋 后面說不定會加一個自動闖關的功能。
2021/03/25 最近忙着網安方向的學習,所以無論是 github 還是博客園 此小工具都停止更新。。。程序的主要邏輯和代碼都在文中。相信有一些 python 基礎的話修改應該沒有問題。 (。^▽^)
2021/06/09 為了照顧到不熟悉編程的萌新,以及只想體驗一下,不想設置太多的萌新 ~ 特推出嘗鮮版。此版本需要設置的東西大大減少,同時可以完成一局完整對局,但相對而言減少了一些功能。例如,無法自動連續對局,無法處理對方悔棋的情況等等。
使用這個你需要預先掌握的知識:
簡述
最近玩微信小程序 - 歡樂五子棋,結果老是被虐。偶然想到了前段時間網上很火爆的跳一跳輔助。簡單想了一想輔助實現的思路,發現目前所需的工具已經足夠。需要的工具主要分為以下三類:
-
Yixin 奕心引擎,這個引擎是國人所作,可以說是非商用版里面最強的五子棋AI
一開始我想使用奕心的界面+引擎那款,因為可定制性足夠強,結果發現Python 不好與GUI程序交互,所以就選擇了引擎。然而尷尬的一點是,把官方文檔翻了個遍都沒有找到引擎的使用方法。不過后來在 世界五子棋錦標賽 找到了參加比賽的AI 必備的兩種接口。
-
http://petr.lastovicka.sweb.cz/protocl2en.htm 使用輸入輸出流,本文選擇的就是這種方式
-
-
Python 簡單圖片處理
-
Python adb 操作手機
思路
整個思路順下來程序其實是比較好寫的,就是前期需要手動的截取匹配圖片,設置查找區域像素點位置比較麻煩,不過新添加自適配功能,這些都不需要做。
實現
前期准備
下面的區域參數以我的手機1920*1080為例,由於最新版已經添加自適配分辨率功能,所以一般不需要修改
class mVars:
address='C:/Users/EA/Desktop/yixin/' # 使用到的文件所存放地址
boradOne = 67 #一個相鄰落子點的像素間隔
borad = (65,480) #用來將圖片像素坐標和棋盤坐標互轉
confirmBW = (820,1590,820+45,1590+60)#用來確定己方是黑棋還是白棋的區域
confirmWin = (660,1780,660+46,1780+46)#用來確定是否勝利的區域
這些是前期需要准備好的圖片,至於怎么獲取這些圖片,等后面有時間會在補充在文末,事實上,做好這些准備工作,整個進度就完成了30%
Yixin 引擎
從官網上可以下載Yixin 引擎,結合 協議 可以知道如何與引擎交互
我使用 subprocess 這個模塊讓python 與 引擎交互
import subprocess as sub
class YiXin:
mYixin = sub.Popen(mVars.address+"Yixin.exe", stdin=sub.PIPE, stdout=sub.PIPE, stderr=sub.PIPE)
def __init__(self):
self.input('START 15')
self.input('INFO timeout_match 300000')
self.input('INFO timeout_turn 10000')
self.output()
print("YiXin ready!!")
def input(self,str): #向Yixin 輸入對手落子指令
print('Human: '+str)
self.mYixin.stdin.write((str+'\n').encode())
self.mYixin.stdin.flush()
def output(self): #獲取Yixin 的輸出
#一直獲取Yixin 輸出,直到落子的指令或其它
while True:
str = bytes.decode(self.mYixin.stdout.readline())
print('YiXin: '+ str,end='')
if ((',' in str) or ('OK' in str)):
break;
self.mYixin.stdout.flush()
if(',' in str):
return str
def restart(self):
self.input('RESTART 15')
self.output()
圖片處理
這個模塊需要做的事就是處理跟圖片相關的,包括比較圖片,轉換坐標等
起初有兩種實現思路,1. 每隔一段時間獲取截一張圖,對比兩張圖不同的地方,從而獲取對手落點位置。2. 每隔一段時間截一張圖,識別圖上的所有有棋的位置並保存,然后通過比較,得到對手落子位置。出於效率考慮,我選擇了第一種方法。
class ImageProcess:
#如果匹配成功,則返回中心像素點
def matchImg(self,imgsrc,imgobj,confidence=0.8):
coord = None
res = ac.find_template(imgsrc,imgobj,confidence)
if res != None:
coord = (int(res['result'][0]),int(res['result'][1]))
return coord
#將像素坐標轉化為棋盤坐標
def transformBoard(self,coord):
x = coord[0]
y = coord[1]
xcoord = ycoord = 0
while x>=mVars.borad[0]:
x-=mVars.boradOne
xcoord+=1
while y>=mVars.borad[1]:
y-=mVars.boradOne
ycoord+=1
return xcoord-1,ycoord-1
#將棋盤坐標轉化為像素坐標
def transfromScreen(self,coord):
return (coord[0]*mVars.boradOne+mVars.borad[0],coord[1]*mVars.boradOne+mVars.borad[1])
#對比兩張圖片的差異
def difference(self,img1,img2):
return img1-img2
ADB 模塊
這個模塊與手機交互,這塊我用的是無線ADB連接,見 ADB連接教程
import os
import time
class Adb:
#無線連接手機
def __init__(self):
os.system('adb connect 1.1.1.1:5555')#ip 示例
os.system('adb devices')
#捕獲截圖
def capture(self):
os.system('adb exec-out screencap -p > '+mVars.address+'sc.jpg')
return ac.imread(mVars.address+'sc.jpg')
#點擊特定位置
def click(self,piexl):
os.system('adb shell input tap %d %d'%(piexl[0],piexl[1]))
time.sleep(0.1)
os.system('adb shell input tap %d %d'%(piexl[0],piexl[1]))
游戲系統模塊
class System:
Yixin = YiXin()
ImageP = ImageProcess()
Adb = Adb()
imgobj = None #用來檢測對手落子的圖片
certain = 0 #1表示己方為白,2表示己方為黑
#確認是否勝利
def confirmWin(self,imgsrc):
x0,y0,x1,y1 = mVars.confirmWin
imgsrc = imgsrc[y0:y1,x0:x1]
imgobj = ac.imread(mVars.address+'confirmwin.jpg')
return self.ImageP.matchImg(imgsrc,imgobj,0.9)
#確認己方是黑棋還是白棋
def confirmBW(self,imgsrc):
x0,y0,x1,y1 = mVars.confirmBW
imgsrc = imgsrc[y0:y1,x0:x1]
imgobjw = ac.imread(mVars.address+'confirmw.jpg')
imgobjb = ac.imread(mVars.address+'confirmb.jpg')
if (self.ImageP.matchImg(imgsrc,imgobjw,0.8) != None):
self.certain = 1
self.imgobj=ac.imread(mVars.address+'objb.jpg')
elif (self.ImageP.matchImg(imgsrc,imgobjb,0.8)!= None):
self.certain = 2
self.imgobj=ac.imread(mVars.address+'objw.jpg')
#做好比賽前准備,
def ready(self):
while True:
imgsrc = self.Adb.capture()
self.confirmBW(imgsrc)
if(self.certain != 0):
break;
print('UnCertain')
time.sleep(1)
if self.certain == 2:
self.runCommand('BEGIN')
return imgsrc
elif self.certain == 1:
return ac.imread(mVars.address+'None.jpg')
#向Yixin 輸入對方落點,獲得Yixin 落點並點擊屏幕
def runCommand(self,COMMAND):
self.Yixin.input(COMMAND)
str = self.Yixin.output()
a = str.find(',')
b = str.find('\r')
piexl = self.ImageP.transfromScreen((int(str[0:a]),int(str[a+1:b])))
# print(piexl)
self.Adb.click(piexl)
#開始游戲
def play(self,imgsrc):
flag=False
imagep = self.ImageP
oldimg = newimg = imgsrc
while self.confirmWin(newimg) == None:
imgdif = imagep.difference(oldimg,newimg)
ac.cv2.imwrite(mVars.address+'diff.jpg',imgdif)
coord = imagep.matchImg(imgdif,self.imgobj)
# print(coord)
if(coord != None):
x, y = imagep.transformBoard(coord)
COMMAND = "TURN %d,%d"%(x,y)
self.runCommand(COMMAND)
oldimg,newimg = newimg,self.Adb.capture()
time.sleep(0.8)
#新一輪游戲
def newGame(self):
os.system('cls')
os.system('adb shell input tap %d %d'%(100,1820))
time.sleep(0.5)
os.system('adb shell input tap %d %d'%(540,940))
self.Yixin.restart()
self.certain = 0
self.imgobj = None
主函數
msys = System()
# n = input("請輸入你想玩的局數:")
# for i in range(1,int(n)+1):
while True:
imgBegin = msys.ready()
msys.play(imgBegin)
print("You Win !! Next Game Will Begin After 4sec")
time.sleep(4)
msys.newGame()
后記
所有代碼到這里就結束了,后面將用到的資源整理一下再上傳
如何獲取那些圖片
在已連接adb 的情況下,可以通過下面這條語句快速截圖
import os address='C:/Users/EA/Desktop/yixin/' os.system('adb exec-out screencap -p > '+address+'sc.jpg')
主要用系統自帶的畫圖工具,在屏幕左下角查找相應位置的像素坐標
-
檢測己方是黑白棋
建議用下面的命令獲取
import aircv as ac address='C:/Users/EA/Desktop/yixin/' imgsrc = ac.imread(address+'sc.jpg') x0,y0,x1,y1 = (820,1590,820+45,1590+60) #這個坐標以用畫圖工具量取為准 imgsrc = imgsrc[y0:y1,x0:x1] #分別在這個位置保存己方黑白棋識別標志 ac.cv2.imwrite(address+'confirmw.jpg',imgsrc) #ac.cv2.imwrite(address+'confirmb.jpg',imgsrc) #檢測所選的圖片是否正常識別 imgw = ac.imread(address+'confirmw.jpg') print(ac.find_template(imgsrc,imgw,0.01))注意,1. 不要把整個棋子都截取,因為右邊不時有綠色關環影響識別。2. 與電腦對戰時這個標志的位置偏右,所以在mVars.confirmBW 的范圍應該稍大一點。3. 在弄完之后,最好識別一下檢測一下。
-
勝利的檢測,我選的是這個
-
空棋盤,就弄張空棋盤的截圖,這個圖是必要的,如果沒有,當己方執白時,對方第一子下的很快還沒來得及截圖,那么系統就檢測不到這個對方落子。
-
檢測對方落子簡單起見,我是直接兩張圖片相減然后直接截圖保存。

img1 = ac.imread(address+'old.jpg') img2 = ac.imread(address+'new.jpg') ac.cv2.imwrite(address+'diff.jpg',img1-img2)需要注意的是,一定要統一順序,舊減新或新減舊,我的實現是用舊減新,新減舊也可以,只是棋子的圖不一樣,下面就是新減舊
可以將代碼打包成 exe 使用更方便,具體請搜索 pyinstaller
到這,我遇到的問題基本都標注了,此篇博文完結。如果有什么疑問,歡迎留言。
