zoukankan      html  css  js  c++  java
  • 微信欢乐五子棋辅助

    苦练技术是不可能的,这辈子不可能好好练习。学技术又学不进去,就只有靠辅助才能维持的生活这样子。

    1. 2020.04.17 新添加自动适配分辨率,一般情况下,会根据手机分辨率自动缩放素材图片大小和像素参数,并且上传所有素材到百度网盘。

      链接:https://pan.baidu.com/s/19Oh5irxQkOsP_WNBW2290Q 提取码:grdu

    2. 2020/05/20 注意:该文章停止更新(因为github 太香了~),后续更新请移步 微信五子棋 后面说不定会加一个自动闯关的功能。

    3. 2021/03/25 最近忙着网安方向的学习,所以无论是 github 还是博客园 此小工具都停止更新。。。程序的主要逻辑和代码都在文中。相信有一些 python 基础的话修改应该没有问题。 (。^▽^)

    4. 2021/06/09 为了照顾到不熟悉编程的萌新,以及只想体验一下,不想设置太多的萌新 ~ 特推出尝鲜版。此版本需要设置的东西大大减少,同时可以完成一局完整对局,但相对而言减少了一些功能。例如,无法自动连续对局,无法处理对方悔棋的情况等等。

      使用这个你需要预先掌握的知识:

      1. 会运行python 文件,并且安装文中的库
      2. 安装Adb无线连接成功
      3. 在开发者选项里,打开 USB 调试 和 USB允许模拟点击
      4. 修改 mVars 中除 path 外剩下三个。
      5. 获取一张空棋盘截图,替换 yinxin 文件夹下 None.jpg

    简述

    最近玩微信小程序 - 欢乐五子棋,结果老是被虐。偶然想到了前段时间网上很火爆的跳一跳辅助。简单想了一想辅助实现的思路,发现目前所需的工具已经足够。需要的工具主要分为以下三类:

    1. Yixin 奕心引擎,这个引擎是国人所作,可以说是非商用版里面最强的五子棋AI

      一开始我想使用奕心的界面+引擎那款,因为可定制性足够强,结果发现Python 不好与GUI程序交互,所以就选择了引擎。然而尴尬的一点是,把官方文档翻了个遍都没有找到引擎的使用方法。不过后来在 世界五子棋锦标赛 找到了参加比赛的AI 必备的两种接口。

    2. Python 简单图片处理

    3. Python adb 操作手机

    思路

    image-20200329134722139

    整个思路顺下来程序其实是比较好写的,就是前期需要手动的截取匹配图片,设置查找区域像素点位置比较麻烦,不过新添加自适配功能,这些都不需要做。

    实现

    前期准备

    下面的区域参数以我的手机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%

    image-20200329105705796
    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+'
    ').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('
    ')
    
            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')
    

    主要用系统自带的画图工具,在屏幕左下角查找相应位置的像素坐标

    • 检测己方是黑白棋

      image-20200401170446037

      建议用下面的命令获取

      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. 在弄完之后,最好识别一下检测一下。

    • 胜利的检测,我选的是这个

      image-20200401171752084
    • 空棋盘,就弄张空棋盘的截图,这个图是必要的,如果没有,当己方执白时,对方第一子下的很快还没来得及截图,那么系统就检测不到这个对方落子。

    • 检测对方落子简单起见,我是直接两张图片相减然后直接截图保存。

      image-20200401172652696

      img1 = ac.imread(address+'old.jpg')
      img2 = ac.imread(address+'new.jpg')
      ac.cv2.imwrite(address+'diff.jpg',img1-img2)
      

      需要注意的是,一定要统一顺序,旧减新或新减旧,我的实现是用旧减新,新减旧也可以,只是棋子的图不一样,下面就是新减旧

      image-20200401173039933

    可以将代码打包成 exe 使用更方便,具体请搜索 pyinstaller

    到这,我遇到的问题基本都标注了,此篇博文完结。如果有什么疑问,欢迎留言。

  • 相关阅读:
    让数据更精准,神器标配:热图
    运维监控大数据的提取与分析
    IT运营新世界大会:广通软件开启双态运维大时代
    持续交付的Mesos与Docker导入篇
    运算符
    Django 模型层(2)
    Django模型层
    Django的模板层
    Django的视图层
    Django的路由层(URLconf)
  • 原文地址:https://www.cnblogs.com/starrys/p/12591415.html
Copyright © 2011-2022 走看看