美文网首页
Python部落冲突自动搜索对手

Python部落冲突自动搜索对手

作者: Zincox | 来源:发表于2018-07-08 18:59 被阅读0次

    每次在部落冲突搜索对手,都要花上不少时间。尤其是在发展中期的时候,特别难搜索到肥猪。像我本身的十本大号,在十本中期发展。前期还好,搜到的基本上是十本初的死鱼,随随便便就是五六十万。后来把兵营什么的升级上来,杯一冲到大师杯后,搜索到的基本上是各种十几万,打一把亏一把。搜个几十分钟都不一定碰到一个肥的。作为一个时间就是生命的码农,这肯定是难以接受的,所以就抽空写了这个脚本。

    思路

    首先要保证的一点是:一定不能封号。好不容易玩了两年发展到十本,封号了岂不是凉凉?所以从原理上,坚决不能读取内存数据。读内存数据相当容易翻车。
    所以只能另辟蹊径,走文字识别这条路。原理大概是:

    • 获取游戏中的截图
    • 模拟点击进行搜索对手
    • 图像识别对手的资源
    • 判断资源,发现肥猪提醒

    平台选择

    由于获取截图需要一定的系统权限,因此平台只能选定安卓平台。在安卓平台下允许使用adb命令连接Android系统截图,并将截图发送到Mac或Windows上来,进行其他的逻辑判断。

    截图获取

    获取截图可以使用安卓的虚拟机、模拟器,在Windows和Mac下均有相应的Android虚拟机。但如果使用模拟器运行部落冲突,意味着搜索到对手也必须在模拟器下发动进攻。而模拟器下对多指操控很不友好。而且模拟器运行占用资源也会比较大,毕竟码农,还是不希望电脑卡顿的,因此最后选定使用实体机来跑。

    好在我有一个闲置下来的小米5,因此可以通过获取小米5的截图,来判断对手资源,发现合适的肥猪再进行提醒。这样也能在手机上操控,最大限度保证能够榨干肥猪。

    前期准备

    Python

    首先你得有一个Python,毕竟这是一个Python脚本。同时还要选择一个好的IDE,这里我选择的是Pycharm。这样在写代码的时候能够省下不少功夫。
    Python和Pycharm的安装我就不啰嗦了,百度上一大把。需要注意的是Python最好选择Python3版本,这里我选择的是Python3.6版本,2.7版本在库和语法上与3.6略有不同。

    pip

    因为需要使用一些Python库,使用pip的安装必不可少。同理,百度一大把。不过安装完成后记得换为国内源,这样下载速度会快很多很多。

    • 传送门

    https://www.jianshu.com/p/9d986bc8ba69

    注册百度的AI文字识别服务

    注册完成后开通相应的服务,拿到AppID、API Key和Secret Key就行。后续需要使用到百度的文字识别服务来识别资源。

    _apikey_1530979649_2147066274.png

    图形处理库Pillow

    获取到的屏幕截图还包含有其他文字,这些文字不是所需要的,所以需要使用图形处理库将资源数据裁剪出来,再通过文字识别转换为数字,这样大大提高了识别的精度和效率。

    pip install Pillow
    

    我在Mac下安装提示各种缺失,根据缺失将缺失的模块(MySQL-python)补上即可。


    _图片中还含有其他文字_1531030593_729756971.png

    安卓手机

    理论上只要是安卓手机基本都OK,版本在4.4以上的、能够启用开发者选项的就行。因为adb工具需要使用开发者选项来操控手机,所以需要启动开发者选项。不同手机有不同启用方法,具体就不详细赘述了,百度手机型号+启用开发者选项基本都能够搜索到。启用开发者选项后,在开发者选项中启用USB调试即可。

    注意:开启前务必关闭关闭(最好卸载)360、毒霸等各种国产安卓软件,关闭其他不必要的优化软件,否则这些软件有权限在你手机上乱搞,比如安装各种乱七八糟的软件,所以开启前务必关闭!!!

    _启用usb调试_1531044449_422037486.png

    adb工具环境配置

    • 检测adb环境是否配置完毕

    在Mac的终端或Windows的命令提示符下输入

    adb --version
    

    如果能过显示相应的adb版本号,如

    Android Debug Bridge version 1.0.40
    Version 4797878
    Installed as /Users/zinc/Library/Android/sdk/platform-tools/adb
    

    则说明adb环境已经配置完毕。否则需要配置环境

    Windows系统下比较方便,百度adb工具箱下载即可,大小10mb左右,再根据教程配置adb环境即可

    • Windows下的adb环境配置

    https://jingyan.baidu.com/article/17bd8e52f514d985ab2bb800.html

    • Mac下的adb环境配置

    在Mac下的配置相对比较麻烦,我个人倾向于安装Android Studio,这样能够集成adb工具,也会自动配置好adb环境。如果安装完成后仍未配置好,参照:

    https://blog.csdn.net/wwf0123/article/details/52497885

    代码实战

    首先需要弄清楚总一个流程:

    • 获取手机分辨率
    • 知道相应的按钮的x、y位置
    • 模拟点击左下角进攻按钮
    • 点击搜索对手按钮
    • 手机截图
    • 将手机截图发送至电脑端
    • 将资源信息裁剪出来
    • 用百度AI识别信息
    • 根据信息提醒或继续搜索下一个对手

    因此分出三个类,ScreenCapturer类负责获取屏幕截图、以及模拟点击操作,PicScanner类负责图片处理、以及上传识别,而autoFind则进行逻辑处理,控制整个流程

    ScreenCapturer.py

    from os import *
    from time import sleep
    
    # adb shell screencap -p /sdcard/1.png(保存到SDCard)
    # adb pull /sdcard/screenshot.png d:/screenshot.png(保存到电脑)
    
    class ScreenCapturer:
    
        # 获取的截图文件在手机中的保存位置(默认保存在内置存储根目录下)
        ANDRIOD_PIC_PATH = "/sdcard/screenshot.png"
        # 文件保存在电脑中的目录
        TRANS_PIC_PATH = "/Users/zinc/Documents/autoFind/screenshot.png"
        # 获取截图的adb命令
        SCREEN_CAP_CMD = "adb shell screencap -p "
        # 传输文件至电脑adb命令
        TRANS_FILE_CMD = "adb pull "
        # 获取Android手机分辨率命令
        GET_RESOLUTION_CMD = "adb shell dumpsys window displays"
        # 模拟点击命令
        POINT_SCREEN_CMD = "adb shell input tap"
        # 手机分辨率
        phoneResolution = []
    
        def __init__(self,andriod="",trans=""):
            if andriod!="" and trans != "":
                # 判断是否为默认参数
                self.ANDRIOD_PIC_PATH = andriod
                self.TRANS_PIC_PATH = trans
    
        def getPhoneScreen(self):
            # 获取屏幕截图
            command = self.SCREEN_CAP_CMD + self.ANDRIOD_PIC_PATH
            system(command)
    
        def transPhoneScreen(self):
            # 将截图传输至电脑
            command = self.TRANS_FILE_CMD + self.ANDRIOD_PIC_PATH + " " +self.TRANS_PIC_PATH
            system(command)
            print("截图已获取")
    
        # 模拟点击某一位置
        def pointOnPhone(self,x=0.0,y=0.0):
            strX = str(x)
            strY = str(y)
            command = self.POINT_SCREEN_CMD + " " + strX + " " + strY
            system(command)
            pass
        
        # 获取屏幕分辨率
        def getPhoneResolution(self):
            # 获取命令行的打印值
            r = popen(self.GET_RESOLUTION_CMD)
            text = str(r.read())
            # 查找init=字符串,其后为手机分辨率情况
            beginC = text.find("init=")
            # 获取其后的10个字符
            line = text[beginC+5:beginC+15]
            resolution = line.split("x")
            self.phoneResolution.append(float(resolution[0]))
            self.phoneResolution.append(float(resolution[1]))
            print("weight =",self.phoneResolution[0],"\nheight =",self.phoneResolution[1])
            r.close()
            pass
        
        # 点击进攻按钮
        def pointAttackBtn(self):
            # 保留两位小数
            x = 0.07 * self.phoneResolution[1]
            y = 0.9 * self.phoneResolution[0]
            self.pointOnPhone(x,y)
            print("点击进攻按钮")
        
        # 点击搜索对手按钮
        def pointSearchAttacker(self):
            # 保留两位小数
            x = 0.23 * self.phoneResolution[1]
            y = 0.72 * self.phoneResolution[0]
            self.pointOnPhone(x, y)
            print("点击搜索对手按钮")
    
        # 点击搜索下一个按钮
        def pointNextAttacker(self):
            # 保留两位小数
            x = 0.925 * self.phoneResolution[1]
            y = 0.732 * self.phoneResolution[0]
            self.pointOnPhone(x, y)
            print("点击搜索下一个按钮")
    
        # 点击结束战斗按钮
        def pointEndAttack(self):
            # 保留两位小数
            x = 0.075 * self.phoneResolution[1]
            y = 0.745 * self.phoneResolution[0]
            self.pointOnPhone(x, y)
            print("点击结束战斗按钮")
    
    
    # 测试代码,完成类的测试后注释
    
    # capture = ScreenCapturer()
    #
    # capture.getPhoneScreen()
    # capture.transPhoneScreen()
    
    # capture.getPhoneResolution()
    # capture.pointAttackBtn()
    # capture.pointSearchAttacker()
    # for i in range(0,5):
    #     sleep(5)
    #     capture.pointNextAttacker()
    # sleep(5)
    # capture.pointEndAttack()
    

    去掉最底部的测试注释,直接运行ScreenCapturer.py,测试功能是否正常

    一些常量的注释

    • 默认的截图保存地址,截图将会保存在这个位置下,/sdcard/位置默认为安卓手机的内置储存,即此时保存在内置储存根目录下
    ANDRIOD_PIC_PATH = "/sdcard/screenshot.png"
    
    • 截图传输到电脑后的保存位置
    TRANS_PIC_PATH = "/Users/zinc/Documents/autoFind/screenshot.png"
    

    PicScanner.py

    from aip import AipOcr
    from PIL import Image
    
    class PicScanner:
    
        """ 你的 APPID AK SK """
        APP_ID = '这里填写百度AI的APPID'
        API_KEY = "百度AI的API_KEY"
        SECRET_KEY = "百度AI的SECRET_KEY"
    
        # 初始化AipFace对象
        # aipOcr = AipOcr(APP_ID, API_KEY, SECRET_KEY)
    
        # 定义参数变量
        options = {
            'detect_direction': 'true',
            'language_type': 'CHN_ENG',
        }
    
        # 读取图片
        # 文件保存在电脑中的目录
        filePath = "/Users/zinc/Documents/autoFind/screenshot.png"
    
        def __init__(self,path=""):
            if path!="":
                self.filePath = path
    
        def get_file_content(self,filePath):
            with open(filePath, 'rb') as fp:
                return fp.read()
    
        def readPicNum(self,path=""):
            if path != "":
                self.filePath = path
            aipOcr = AipOcr(self.APP_ID, self.API_KEY, self.SECRET_KEY)
            # 调用通用文字识别接口
            result = aipOcr.basicAccurate(self.get_file_content(self.filePath), self.options) # 高精度
            #result = aipOcr.basicGeneral(self.get_file_content(self.filePath), self.options) # 高速
            return result
    
            # 将截图裁剪至仅剩资源的部分,方便于图片识别
        def cutPicToSource(self):
            im = Image.open(self.filePath, 'r')
            if im:
                width, height = im.size
                cropedIm = im.crop((0.046 * width, 0.125 * height, 0.135 * width, 0.268 * height))
                cropedIm.save(self.filePath)
            else:
                print("图片文件打开失败")
    
    # scanner = PicScanner()
    # # scanner.cutPicToSource()
    # scanner.readPicNum()
    
    • 根据百度控制台的提示填写相应的APP_ID、API_KEY、SECRET_KEY,用来请求百度AI服务器。
        APP_ID = '这里填写百度AI的APPID'
        API_KEY = "百度AI的API_KEY"
        SECRET_KEY = "百度AI的SECRET_KEY"
    
    • 精度查找
      百度提供了两种识别精度,一种为高速低精度的识别,50000次/日。还有一种是较低速和高精度的识别,500次/日。个人使用下来感觉两种识别速度接近,但识别精度却是天差地别,低精度识别几乎没有正确识别所有信息的情况。所以务必使用高精度的识别,可能对图像处理后识别率可能会提升(比如提高对比度),但我没试过,500次/日我觉得完全够我一天的使用了。
    result = aipOcr.basicAccurate(self.get_file_content(self.filePath), self.options) # 高精度
    #result = aipOcr.basicGeneral(self.get_file_content(self.filePath), self.options) # 高速
    
    • 裁切信息位置
      crop命令的裁剪位置是由(信息位置/屏幕分辨率)得到的,不同分辨率下信息在屏幕中的占比是不一样的,需要注意一下。
    # 将截图裁剪至仅剩资源的部分,方便于图片识别
    def cutPicToSource(self):
    im = Image.open(self.filePath, 'r')
    # 检测是否打开成功
    if im:
        width, height = im.size
        cropedIm = im.crop((0.046 * width, 0.125 * height, 0.135 * width, 0.268 * height))
        cropedIm.save(self.filePath)
    else:
        print("图片文件打开失败")
    

    autoFind.py

    from PicScanner import PicScanner
    from ScreenCapturer import ScreenCapturer
    from time import sleep
    import tkinter
    import tkinter.messagebox
    
    class autoFind:
    
        # 对象实例
        scanner = PicScanner()
        capture = ScreenCapturer()
        # 设置的搜索资源值
        source = {}
        # 获取到的资源值
        int_gold = 0
        int_water = 0
        int_black = 0
    
        def setSourceValue(self,gold,water,black_w):
            self.source['gold'] = gold
            self.source['water'] = water
            self.source['black_w'] = black_w
            print(self.source)
    
        def beginFind(self):
            self.showAdvice()
            # 获取屏幕分辨率
            self.capture.getPhoneResolution()
            # 点击进攻按钮
            self.capture.pointAttackBtn()
            # 点击搜索对手按钮
            self.capture.pointSearchAttacker()
            # 延时5s
            sleep(6)
            while(1):
                # 获取屏幕截图并判断资源
                self.capture.getPhoneScreen()
                self.capture.transPhoneScreen()
                self.scanner.cutPicToSource()
                words = self.scanner.readPicNum()
                words_result = words['words_result']
                # 尝试获取资源,如果抛出异常则说明获取失败
                try:
                    gold = words_result[0]['words']
                    water = words_result[1]['words']
                    black_w = words_result[2]['words']
                except:
                    print("获取资源失败,开始搜索下一个对手")
                    sleep(2)
                    continue
                # 尝试将其转换为整数,转换失败则说明识别失败
                try:
                    print("当前搜索到的对手资源为",gold, water, black_w)
                    self.int_gold = int(gold)
                    print(self.int_gold)
                    self.int_water = int(water)
                    print(self.int_water)
                    self.int_black = int(black_w)
                    print(self.int_black)
                except:
                    print("资源识别失败,搜索下一个对手")
                    self.capture.pointNextAttacker()
                    sleep(6)
                    continue
                # 如果能够成功转化,则判断资源值是否满足设定值
                if self.int_gold > self.source['gold'] and self.int_water > self.source['water'] and self.int_black > self.source['black_w']:
                    self.findVictim(str(self.int_gold), str(self.int_water), str(self.int_black))
                    # 发现肥猪跳出循环
                    break
                else:
                    # 如果不满足设定值,则继续搜索下一个对手
                    print("这个人是个穷b,懒得打他了")
                    self.capture.pointNextAttacker()
                    sleep(6)
    
        # 找到合适对手后进行提醒
        def findVictim(self,gold,water,black_w):
            tkinter.messagebox.showinfo('发现肥猪', '找到一个肥猪,他有'+gold+"金币,"+water+"圣水和"+black_w+"重油,搜索程序已暂停.")
    
        def showAdvice(self):
            tkinter.messagebox.showinfo('使用前准备', "使用前先回到大本营界面,搜索过程中不要点击其他按钮,搜索到对手后会自动暂停。点击确定开始进行搜索")
    
    find = autoFind()
    try:
        find.setSourceValue(300000,300000,1000)
        find.beginFind()
    except:
        tkinter.messagebox.showinfo('程序出错!', "程序出错!已暂停搜索,请返回大本营重新运行程序!")
    
    • 当搜索到肥猪时用thinter来弹出对话框
    • 多使用try语句
      因为多个地方无法确定是否能够获取到相应信息,比如识别信息的时候容易识别错误,识别成了字母或其他字符,因此就需要异常处理来保证程序能够继续运行下去

    运行效果

    • 完成后基本只用运行就行了,挂着Python程序在那,搜到肥猪会自动弹出对话框提示。不过开始之前,必须回到大本营界面。
    _搜索到的肥猪_1531047047_1147857544.png _搜索到对手_1531046946_1261457288.png

    Just Enjoy!

    所以以后就不需要不停地盯着屏幕看了,虽然可能会漏鱼,不过也大大节省了时间,以后只要边看视频别挂着搜肥猪,遇到肥猪就打就行。

    相关文章

      网友评论

          本文标题:Python部落冲突自动搜索对手

          本文链接:https://www.haomeiwen.com/subject/byoouftx.html