本帖最后由 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% 的胜率,几乎与人类打成平手。
我们利用机器学习技术同样也可以增加在云顶之弈中对局的胜率
下面引入基础的概念:回归问题和分类问题。
在李航《统计学习方法》的解释为:
输入变量与输出变量均为连续变量的预测问题是回归问题
输出变量为有限个离散变量的预测问题为分类问题
输入变量与输出变量均为变量序列的预测问题为标注问题
举个例子:
预测明天的气温是多少度,这是一个回归任务;
预测明天是阴、晴还是雨,就是一个分类任务。
有三种主要类型的机器学习:监督学习、非监督学习和强化学习。
广义上来说,机器学习是一种能够赋予机器学习的能力以此让它完成直接编程无法完成的功能的方法。但从实践的意义上来说,机器学习是一种通过利用数据,训练出模型,然后使用模型预测的一种方法。
召唤师峡谷机器学习自动对战例图:
同理我们可以通过收集大量的游戏数据让程序进行分析之后可以推出在哪个时间段用哪个阵容会让你存活的时间更久 通俗来说就是让你吃鸡
比如阶段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开放平台)
由于河蟹原因我只会讲述原理不会提供非常清晰地明码
百度文字识别代码示例:
[Python] 纯文本查看 复制代码 """ 读取图片 """
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包可以干更多的事情
附上类似的代码给大家参考:
[Python] 纯文本查看 复制代码 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[1]:box[3], box[0]:box[2]]
def isbox1inbox2(box1,box2):
"""box1 in box2?"""
if (box2[0] <= box1[0] and box1[2] <= box2[2]) and (box2[1] <= box1[1] and box1[3] <= box2[3]):
return True
def screenshot_to_text():
ss = np.array(screenshot())
#boxes of 5 champs
xi,yi,xs,ys = int(ss.shape[1]*25/100),int(ss.shape[0]*96/100),int(ss.shape[1]*33/100),int(ss.shape[0]*99/100)
xi2,yi2,xs2,ys2 = int(ss.shape[1]*35/100),int(ss.shape[0]*96/100),int(ss.shape[1]*43/100),int(ss.shape[0]*99/100)
xi3,yi3,xs3,ys3 = int(ss.shape[1]*46/100),int(ss.shape[0]*96/100),int(ss.shape[1]*53/100),int(ss.shape[0]*99/100)
xi4,yi4,xs4,ys4 = int(ss.shape[1]*56/100),int(ss.shape[0]*96/100),int(ss.shape[1]*64/100),int(ss.shape[0]*99/100)
xi5,yi5,xs5,ys5 = int(ss.shape[1]*67/100),int(ss.shape[0]*96/100),int(ss.shape[1]*75/100),int(ss.shape[0]*99/100)
img = crop(ss,[xi,yi,xs5,ys5])
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# =============================================================================
# cv2.imshow("",img)
# k = cv2.waitKey(1) & 0xFF
# if k == 27:
# return
# =============================================================================
boxes = [[xi,yi,xs,ys],
[xi2,yi2,xs2,ys2],
[xi3,yi3,xs3,ys3],
[xi4,yi4,xs4,ys4],
[xi5,yi5,xs5,ys5]]
lower_red = np.array([60,117,62])
upper_red = np.array([213,228,218])
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[0]],["",boxes[1]],["",boxes[2]],["",boxes[3]],["",boxes[4]]]
if textList == ['']:
return None
for i in textList:
i = i.split()
box1 = [xi+int(i[1]),
ss.shape[0]-int(i[2]),
xi+int(i[3]),
ss.shape[0]-int(i[4])]
for boxIndex,box2 in enumerate(boxes):
if isbox1inbox2(box1,box2):
texts[boxIndex][0]+=i[0]
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 = [similar(champ,champFromText[0]) for champ in comps[comp]]
maxRate = similarRates[np.argmax(similarRates)]
if maxRate > .801:
if champFromText[1] not in maskChamps:
maskChamps.append(champFromText[1])
print(champFromText[0],comps[comp][np.argmax(similarRates)])
self.active.emit(maskChamps)
def stop(self):
self.running = False
如有不足请指出谢谢,今天先到这 明天我们继续!
ok关于大家提出的如何 收集数据 其实云顶之弈每个版本 强势的就这几个阵容 下次我会专门介绍如何利用爬虫爬取各种网站获得数据
|