qweasdzxb 发表于 2019-9-8 01:18

云顶之弈辅助技术交流

本帖最后由 qweasdzxb 于 2019-9-8 09:07 编辑

经过深思熟虑以后还是决定把自己编写的云顶之弈辅助进行开源和大家进行技术交流整个软件分为很多部分由于时间关系,这次我只拿出头一部分代码和大家交流一下项目的思路。
当年 AlphaGo 打败世界围棋冠军李世石,直接引爆第三次 AI 浪潮。但与现实世界相比,它解决的问题只是九牛一毛。更为复杂的即时策略游戏(RTS)正成为研究人员们新的挑战项目。业界普遍认为,从这些策略游戏中有望诞生下一个 AI 里程碑。
其中最受欢迎的分支是 MOBA 游戏。像谷歌 DeepMind(星际争霸2)、Facebook(星际争霸2) 及 Open AI(Dota 2)等 AI 界明星团队都在推进此类研究。
腾讯也早在两年前就透露在做 AI 打王者荣耀方面的研究。去年12月,5个相互的独立的 AI 在学会开黑技能后,5v5对阵王者荣耀中王者段位的人类玩家。大战 250 个回合后,AI 拿下 48% 的胜率,几乎与人类打成平手。
我们利用机器学习技术同样也可以增加在云顶之弈中对局的胜率
下面引入基础的概念:回归问题和分类问题。

在李航《统计学习方法》的解释为:
输入变量与输出变量均为连续变量的预测问题是回归问题
输出变量为有限个离散变量的预测问题为分类问题
输入变量与输出变量均为变量序列的预测问题为标注问题

举个例子:
预测明天的气温是多少度,这是一个回归任务;
预测明天是阴、晴还是雨,就是一个分类任务。

有三种主要类型的机器学习:监督学习、非监督学习和强化学习。
https://img-blog.csdn.net/20180522165348550
广义上来说,机器学习是一种能够赋予机器学习的能力以此让它完成直接编程无法完成的功能的方法。但从实践的意义上来说,机器学习是一种通过利用数据,训练出模型,然后使用模型预测的一种方法。
召唤师峡谷机器学习自动对战例图:

同理我们可以通过收集大量的游戏数据让程序进行分析之后可以推出在哪个时间段用哪个阵容会让你存活的时间更久 通俗来说就是让你吃鸡

比如阶段1 用骑士搭配枪手更容易过渡

先来解决第一个问题 :游戏过程中自动挂机买棋子
我们使用python来编写先引用pyautogui库:

库介绍:The purpose of PyAutoGUI is to provide a cross-platform Python module for GUI automation for human beings. The API is designed to be as simple as possible with sensible defaults.
For example, here is the complete code to move the mouse to the middle of the screen on Windows, OS X, and Linux:
>>> import pyautogui
>>> screenWidth, screenHeight = pyautogui.size()
>>> pyautogui.moveTo(screenWidth / 2, screenHeight / 2)


调用模块:
import pyautogui as auto
1)识别棋子 (先截图棋子然后保存在程序目录下)
picture = auto.locateOnScreen('盖伦.png')# 识别棋子图片是否出现如果图片出现就会传出图片的位置信息

The Locate Functions
NOTE: As of version 0.9.41, if the locate functions can’t find the provided image, they’ll raise ImageNotFoundException instead of returning None.
2)移动到棋子上
auto.moveTo(picture)#鼠标会自动移动到图片位置
3)鼠标点击获取棋子
pyautogui.click(clicks=2)# double-click the left mouse button
pyautogui.click(clicks=2, interval=0.25)# double-click the left mouse button, but with a quarter second pause in between clicks
pyautogui.click(button='right', clicks=3, interval=0.25)## triple-click the right mouse button with a quarter second pause in between clicks
翻译:
#双击鼠标左键
#双击鼠标左键,但点击之间有四分之一秒的暂停
#三次单击鼠标右键,在两次点击之间暂停四分之一秒

4)在合适的位置添加一个死循环
var = 1
while var == 1 :# 表达式永远为 true 无限循环

总结:通过死循环不断扫描我们需要的旗子然后一发现棋子 鼠标直接移动到指定位置点击购买棋子子一气呵成 实现自动挂机买棋子

好了 下面介绍一种更聪明的办法 利用文字识别技术(提供者百度AI开放平台)
由于河蟹原因我只会讲述原理不会提供非常清晰地明码
百度文字识别代码示例:
""" 读取图片 """
def get_file_content(filePath):
    with open(filePath, 'rb') as fp:
      return fp.read()

image = get_file_content('example.jpg')

""" 调用通用文字识别, 图片参数为本地图片 """
client.basicGeneral(image);

""" 如果有可选参数 """
options = {}
options["language_type"] = "CHN_ENG"
options["detect_direction"] = "true"
options["detect_language"] = "true"
options["probability"] = "true"

""" 带参数调用通用文字识别, 图片参数为本地图片 """
client.basicGeneral(image, options)

url = "http//www.x.com/sample.jpg"

""" 调用通用文字识别, 图片参数为远程url图片 """
client.basicGeneralUrl(url);

""" 如果有可选参数 """
options = {}
options["language_type"] = "CHN_ENG"
options["detect_direction"] = "true"
options["detect_language"] = "true"
options["probability"] = "true"

""" 带参数调用通用文字识别, 图片参数为远程url图片 """
client.basicGeneralUrl(url, options)


百度的文字识别用在云顶上足够了,我试过了。
利用文字识别获取指定区域的指定数据实现 数据读取
比如下图 : 用文字识别可以直接提取英雄名字 种族 职业 还有费用等等信息




还可以提取你当前金币值用来判读是消费还是屯着钱 。
然后 我们通过让鼠标自动在小地图中移动到不同的格子可以快速获得提取所有参战者的实时数据 通过程序分析提示你最有威胁的对手 根据预先训练好的数据实时调整阵容
有了文字识别技术我们以后通过利用OpenCV包可以干更多的事情
附上类似的代码给大家参考:
from PyQt5.QtCore import QThread,pyqtSlot,pyqtSignal
from pyautogui import screenshot
import numpy as np
import cv2
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

comps = {"Assassin":["Kha'Zix","Pyke","Zed","Katarina","Evelynn","Rengar","Akali"],
         "Demon":["Varus","Elise","Morgana","Evelynn","Aatrox","Brand","Swain"],
         "Blademaster":["Fiora","Shen","Aatrox","Gangplank","Draven","Yasuo","Camille"],
         "Glacial":["Braum","Lissandra","Ashe","Volibear","Sejuani","Anivia"],
         "Noble":["Fiora","Garen","Vayne","Lucian","Leona","Kayle"],
         "Sorcerer":["Kassadin","Ahri","Lulu","Veigar","Morgana","Aurelion Sol","Karthus","Twisted Fate"],
         "Yordle":["Tristana","Lulu","Poppy","Veigar","Kennen","Gnar"],
         "Knight":["Darius","Garen","Mordekaiser","Poppy","Sejuani","Kayle"],
         "Shapeshifter":["Nidalee","Elise","Shyvana","Gnar","Swain","Jayce"],
         "Brawler":["Warwick","Rek'Sai","Blitzcrank","Volibear","Cho'Gath","Vi"],
         "Gunslinger":["Tristana","Lucian","Graves","Gangplank","Miss Fortune","Jinx"],
         
         "Hextech":["Camille","Jayce","Vi","Jinx"],
         "Imperial":["Darius","Katarina","Draven","Swain"],
         "Ranger":["Ashe","Vayne","Kindred","Varus"],
         "Ninja":["Shen","Zed","Kennen","Akali"],
         "Wild":["Warwick","Ahri","Nidalee","Rengar","Gnar"],
         
         "Elementalist":["Lissandra","Brand","Kennen","Anivia"],
         "Pirate":["Graves","Pyke","Gangplank","Miss Fortune","Twisted Fate"],
         "Void":["Kha'Zix","Kassadin","Rek'Sai","Cho'Gath"],
         
         "Dragon":["Aurelion Sol","Shyvana"],
         "Guardian":["Leona","Braum"],
         "Phantom":["Mordekaiser","Kindred","Karthus"],
         "Exile":["Yasuo"],
         "Robot":["Blitzcrank"]
         }

from difflib import SequenceMatcher

def similar(a, b):
    """Return similarity ratio of a and b"""
    if a=="Zed" and (b=="Zea" or b=="Ted"):
      return 1
    if a=="Lulu" and (b=="Low" or b=="Lute"):
      return 1
    if a=="Evelynn" and (b=="Cyelynn" or b=="Cyelyan" or b=="Cvelyan"):
      return 1
    if a=="Ahri" and b=="Abri":
      return 1
    return SequenceMatcher(None, a, b).ratio()

def crop(imgArray,box):
    """Crop image"""
    return imgArray:box, box:box]

def isbox1inbox2(box1,box2):
    """box1 in box2?"""
    if (box2 <= box1 and box1 <= box2) and (box2 <= box1 and box1 <= box2):
      return True
   
def screenshot_to_text():
    ss = np.array(screenshot())
   
    #boxes of 5 champs
    xi,yi,xs,ys = int(ss.shape*25/100),int(ss.shape*96/100),int(ss.shape*33/100),int(ss.shape*99/100)
    xi2,yi2,xs2,ys2 = int(ss.shape*35/100),int(ss.shape*96/100),int(ss.shape*43/100),int(ss.shape*99/100)
    xi3,yi3,xs3,ys3 = int(ss.shape*46/100),int(ss.shape*96/100),int(ss.shape*53/100),int(ss.shape*99/100)
    xi4,yi4,xs4,ys4 = int(ss.shape*56/100),int(ss.shape*96/100),int(ss.shape*64/100),int(ss.shape*99/100)
    xi5,yi5,xs5,ys5 = int(ss.shape*67/100),int(ss.shape*96/100),int(ss.shape*75/100),int(ss.shape*99/100)
   
    img = crop(ss,)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
   
# =============================================================================
#   cv2.imshow("",img)
#   k = cv2.waitKey(1) & 0xFF
#   if k == 27:
#         return
# =============================================================================
    boxes = [,
             ,
             ,
             ,
             ]
   
   
    lower_red = np.array()
    upper_red = np.array()
   
    mask = cv2.inRange(img, lower_red, upper_red)
    res = cv2.bitwise_and(img, img, mask= mask)
   
    gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
    ret,thresh1 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    mask = cv2.inRange(thresh1, 0, 0)
    text = pytesseract.image_to_boxes(mask)
    textList = text.split("\n")
   
    texts = [["",boxes],["",boxes],["",boxes],["",boxes],["",boxes]]
   
    if textList == ['']:
      return None
    for i in textList:
      i = i.split()
      box1 = ),
                ss.shape-int(i),
                xi+int(i),
                ss.shape-int(i)]
      
      for boxIndex,box2 in enumerate(boxes):
            if isbox1inbox2(box1,box2):
                texts+=i
   
    return texts

class Worker(QThread):
    active = pyqtSignal(list)

    def __init__(self):
      super(Worker, self).__init__()
      self.selectedComps = list()
      self._sleep = False
      
    def reload_comps(self,selectedComps):
      self.selectedComps = selectedComps
      
    @pyqtSlot()
    def run(self):
      self.running = True
      while self.running:
            texts = screenshot_to_text()
            if texts == None:continue
            maskChamps = list()
            for champFromText in texts:
                for comp in self.selectedComps:
                  #if read champ in selected comps emit maskChamps
                  similarRates = ) for champ in comps]
                  maxRate = similarRates
                  if maxRate > .801:
                        if champFromText not in maskChamps:
                            maskChamps.append(champFromText)
                            print(champFromText,comps)
            self.active.emit(maskChamps)
            
    def stop(self):
      self.running = False



如有不足请指出谢谢,今天先到这 明天我们继续!
ok关于大家提出的如何 收集数据 其实云顶之弈每个版本 强势的就这几个阵容 下次我会专门介绍如何利用爬虫爬取各种网站获得数据






Emmm苏 发表于 2019-11-16 09:54

是不是可以把这个添加上鼠标宏,窗口化运行lol界面,通过对游戏窗口的识别来判断以什么棋子起手,选择什么装备,个人认为可以分步骤进行尝试,
第一步,先给予软件指定阵容,测试写出来的界面控制插件能否通过逻辑购买出指定的英雄阵容以及站位,
第二部,加强优化,让插件可以在轮选界面选择合适的装备,以及根据现有装备来实现指定英雄的指定装备的合成
第三部,让插件学会棋子运营和根据局内情况选择阵容,
第四部,给插件监控功能,实时监控地图上所有其他玩家的阵容,分析其他玩家的走向,预测其他玩家的成型阵容,从而选择出最优阵容,
毕竟如果直接集合在LOL本界面,容易被检测为病毒吧,以鼠标宏配合插件的模式,对桌面上的窗口化进行控制,应该会好一些吧

kingblues 发表于 2020-10-29 17:02

我也秉持着游戏决策,机器学习或者深度学习也是能做的,所以写脚本辅助来上分是具备可行性的。

这类辅助,实现思路大抵是三个步骤:

1.获取信息(找图、找色、OCR 文字识别 等等)
2.游戏决策(机器学习、深度学习 等等)
3.模拟操作(鼠标点击、鼠标滑动、键盘输入 等等)

「获取信息」和「模拟操作」是相对固定的实现,实现之后游戏不做重大更新变动会非常小。
而「游戏决策」则不然,它是一个没有天花板需要持续改进的模块,直接影响辅助好不好用。

如何进行「游戏决策」即为:利用哪些信息、从哪些维度、做出什么样子的决策。
除了实现「游戏决策」外,还有决策的评价体系,为的是知道这么做好不好,根据游戏的抽卡概率和敌我局势,算出自己决策的正确性概率(期望赢面),以及实际胜负率。
再就是,根据每次的比赛流程数据和比赛结果数据,来调整决策判别的倾向。

如果让我来写这个辅助,我大概是会这么做的,不过很遗憾,我对机器学习和深度学习了解很有限,没办法给你实操上的建议。

最近我也在写手游辅助,自己摸黑过河,挺想找人交流的,看到你的帖子,给我感觉你发帖子的时候,可能也有和我一样的感觉吧,哈哈。

jianai 发表于 2019-9-8 01:25

感觉很牛逼的样子~~

6718522 发表于 2019-9-8 01:40

我反正是看不懂。

alos 发表于 2019-9-8 01:42

这个我觉得还真能做 全自动上分辅助。。。

fortytwo 发表于 2019-9-8 04:46

这个如果靠官方的话学习会很慢吧,一局需要那么长时间,同时也有防挂机的机制,长时间运行可能会导致封号,这个也需要大量账号,其次每个版本单个棋子,羁绊的强度等级不同,也会影响结果。实际实现起来挺难的。

聊胜于无丶 发表于 2019-9-8 06:50

我不管,我就是要赌枪

powerman 发表于 2019-9-8 07:26

理论上可行,但是需要大量数据,且官方时时更新,不过吃烂哼问题应该不大

孤独的老大哥 发表于 2019-9-8 07:35

晓得了晓得了

117882697 发表于 2019-9-8 08:20

把辅助说的很官方

我不该爱你的 发表于 2019-9-8 08:44

云顶数据交互基本全在服务器完成,本地不存储任何数据,类似正常模式的作弊脚本很难实现吧。
页: [1] 2 3 4 5 6
查看完整版本: 云顶之弈辅助技术交流