跳一跳AI(wai gua)的实现原理详细介绍

简介: 跳一跳AI(wai gua)的实现原理详细介绍

准备

由于是手机游戏,所以依赖于手机的自动化测试框架,例如android的ADB,ios的话可以选择facebook开源的WebDriverAgent(https://github.com/facebook/WebDriverAgent)来模拟对手机的操作(其实就是对屏幕的点击)。

所需环境:(andorid和python为例,比较好找)

android手机,打开 USB 调试功能

Python 3.5+(2.7也可以,没有多大影响)

ADB驱动安装完成并可以正常连接手机

matplot 、opencv、numpy(pip直接安装就好)

原理

  1. 通过自动化的测试框架对手机屏幕进行截图并传输到PC。
  2. PC端对图片进行处理,处理包括以下几个步骤:
    a. 寻找棋子坐标点(最低端中心):这一步很简单,因为棋子的颜色是固定的,直接按照颜色找就可以了
    b. 寻找下一跳的落地点棋盘位置并计算棋盘中心点位置:这一步就比较麻烦一些,棋盘是在左上和右上随机出现,而且大小,形状也都不一样,这就给识别增加了难度。
    c.计算棋子与中心点位置距离:只要找到了两个点,做一个减法就可以了
    d.通过距离计算按压时间:这个是除了寻找落地棋盘以外最复杂的操作了,因为每个手机的屏幕大小不一样,所以对于不同手机像素代表的按压时间也是不一样的。
    e.按压时间修正:我们的每一跳都不可能跳到最中心的位置,总会有一个误差出现,如果不进行修正,这个误差可能会越来越大,导致后面的跳跃失败,所以在跳跃的每一步后都需要根据落地点与实际的中心点的差值来更新按压时间,这就跟我们在神经网络中计算误差时要达到误差最小化是相似的,这个我们后面再细说。
  3. 通过自动化测试框架发送按压操作给手机,按压的时间为2.d步计算结果。
  4. 休息1-2秒后继续重复步骤1

关键点代码实现:

导入基本库

import sys
import matplotlib.pylab as plt
import numpy as np

这里其实只需要numpy和matplot就可以了,opencv都没用到

读取截图

#读入文件
i = plt.imread("./1.jpg") 
#这个函数是将图片进行灰度处理,也就是说1-255的数值,越小越暗,
def to_grayscale(im, weights = np.c_[0.2989, 0.5870, 0.1140]):
    im=im[...,:3]
    tile = np.tile(weights, reps=(im.shape[0],im.shape[1],1))
    return np.sum(tile * im, axis=2)
img = to_grayscale(i)
plt.imshow(img)
plt.show()

读入完成图片后先展示下看看灰度处理的结果,然后先进行简单的找棋子的处理,棋子的处理很简单,因为颜色不变,所以在一个区间之内找就可以了,而且不需要使用灰度图,直接用原图,通过像素大小判断就可以了

#找到棋子中心点
a=[]
for h in range(i.shape[0]-1,0,-1):
    for w in range(0,i.shape[1],1):
        if 50 <i[h,w,0]<60 and 50<i[h,w,1]<60 and 95<i[h,w,2]<105 :
            a.append([h,w])
point=np.mean(a, axis=0).astype(int)
#point为找到的棋子中心点
print(point)

找到棋子中心点后开始处理目标位置中心点,目标位置的中心点分为4步,先找到最上点,也就是Y轴的最大值,然后根据Y轴向下遍历,找到Y轴的最小值,取最大值和最小值的平均值(中心点Y轴坐标)确定X轴的方位,再根据X轴分别像两个方向遍历,找到X轴的最大和最小值,再取平均值(中心点Y轴坐标),在进行组合就为目标的中心点位置了。

max_diff_color=10 #灰度后像素颜色差
step=5 #像素点数
#找到顶点Y
y_top=0 
for h in range(350, img.shape[0], step):
    last_pixel = img[h,0]
    for w in range(1, img.shape[1],step):
        pixel = img[h,w]
        a=abs(pixel-last_pixel)
        last_pixel=pixel
        if a>max_diff_color:
            y_top = [h,w] #多个像素点
            break
    if y_top:
        break
print(y_top)
#找到底端Y
y_btn=0;
last_pixel = img[y_top[0]+10,y_top[1]]
for h in range(y_top[0]+10, img.shape[0], step):
    pixel = img[h,y_top[1]]
    a=abs(pixel-last_pixel)
    last_pixel=pixel
    if a>max_diff_color:
        y_btn = [h,y_top[1]] 
        break;
print(y_btn)
#Y轴平均值,中点
avg_x=[int((y_btn[0]+y_top[0])/2),y_btn[1]]
print (avg_x)
#X轴最小值
x_left=0
last_pixel = img[avg_x[0],y_top[1]-10]
for w in range(avg_x[1],0,-step):
    pixel = img[avg_x[0],w]
    a=abs(pixel-last_pixel)
    last_pixel=pixel
    if a>max_diff_color:
        x_left = [avg_x[0],w] 
        break;
print(x_left)
#X轴最大值
x_right=0
last_pixel = img[avg_x[0],y_top[1]-10]
for w in range(avg_x[1],img.shape[1],step):
    pixel = img[avg_x[0],w]
    a=abs(pixel-last_pixel)
    last_pixel=pixel
    if a>max_diff_color:
        x_right = [avg_x[0],w] 
        break;
print(x_right)
#最后组合成中心点
mid=[avg_x[0],int((x_right[1]+x_left[1])/2)]
print(mid)

这里mid就是我们要的目标的中心点位置,下面我们查看下

img[mid[0]-10:mid[0]+10,mid[1]-10:mid[1]+10]=1
img[point[0]-10:point[0]+10,point[1]-10:point[1]+10]=300
plt.imshow(img,cmap='Greys')
plt.show()

然后就是计算距离,这里我们用欧式距离,numpy一句话就搞定了

dist=np.linalg.norm(point - mid)

最后一步,计算按压距离

#我们先定义一个系数,可以根据初始情况调整
magicnumber=1.0
press_time = dist* magicnumber
#点击后我们还要根据落地点和上一步计算出来的中心点的差值来更新magicnumber
lr=0.05 # learning rate 每一次的更新值,这个可以根据实际情况调整
#下方
magicnumber=(1+lr)*magicnumber
#上方
magicnumber=(1-lr)*magicnumber

模拟点击

import os
cmd = 'adb shell input swipe {x1} {y1} {x2} {y2} {duration}'.format(
        x1=300,
        y1=300,
        x2=300,
        y2=300,
        duration=press_time
    )
os.system(cmd)

关于参数的自动更新说明

上面也说到了,这个magicnumber系数是需要根据前一跳结果和计算出来的中心点的差值对比来动态的改变。最简单的解释也是我们人的操作就是:上一次跳过了,下次相同距离的话就要按的时间短一些,反之就要多按一会。

而这个差值其实就是我们在机器学习中的loss function,(其实cost function也可以,因为一个是loss function是针对单个样本的,cost function是针对整体样本的,其实就是loss function的平均),而lr其实我们可以理解为就是使用随机梯度下降优化时的学习率,也很简单就是为了使差值最小。而magicnumber其实就是我们所需要训练的权重模型,例如在神经网络中我们经常用到的初始化 np.random.randn。

一点废话

大概完成了这个简单项目的技术要点,其实这里面一点人工智能的方法也没用到,用的最多的就是numpy对于数组或者叫矩阵的处理,如果说非要往AI上靠的话那就只能说这个项目用了一些强化学习思路吧。

如果再深入一些可以改进的地方有以下几个方面:

1,程序完全自动学习,这里的几个参数完全可以做成初始化后,通过AI自动完成,前几次肯定AI不会有太多的分数,但是后面肯定会越来越好,参考Flap Bird,已经给出了很好的答案。

2,关于learning rate,将每一跳的计算中心点与实际落点相减求导来优化权重:cost function = 计算中心点-实际落点,并且对这个值进行求导,来优化我们的权重值,我们的cost function是一条直线所以肯定是收敛的。

3,加入CV模块,通过卷积进行物体的识别,能够直接自动识别出棋子和目标,这样训练后就不需要人工再来进行标注了。如果做得再细化一下可以做到 井盖,留声机,便利店,魔方等加分的元素都进行判断,但是这样需要更多的训练样本,当然,这些训练样本可以在实际使用的时候收集,但是这就是一个很大的工程了。

成果展示

图中目标显示的白点为程序计算的目标中心点,棋子下方的黑点为计算出的棋子中心位置。


2.jpgimage.png

1.jpg



image.png


这张图可以看出由于原图中标记有中心点,所以计算出现偏差,使得计算点偏上,说明程序还有优化空间,但是经过测试,并不影响运行。


3.jpg

image.png

最后

这里是我收集的各个语言版本的源代码地址,有兴趣的下来看吧:

https://github.com/wangshub/wechat_jump_game 星最多,android ios都支持,ios要安装wda,已测试可用,其他python也很多

https://github.com/faceair/youjumpijump go的

https://github.com/metowolf/JumpJumpHelper 没错,php是最好的语言

https://github.com/wotermelon/toJump nodejs,js的也很多,不一一写了

https://github.com/fourbrother/WXJumpGameUtils 这个是JAVA的

https://github.com/iOSDevLog/JumpJump Kotlin,就当java看吧

https://github.com/Nihiue/JumpHelper c#的来了

https://github.com/experdot/AutoJump.NET VB.net的也来了

其他的还有很多,排名不分先后

目录
相关文章
|
23天前
|
人工智能 前端开发 编译器
【AI系统】LLVM 架构设计和原理
本文介绍了LLVM的诞生背景及其与GCC的区别,重点阐述了LLVM的架构特点,包括其组件独立性、中间表示(IR)的优势及整体架构。通过Clang+LLVM的实际编译案例,展示了从C代码到可执行文件的全过程,突显了LLVM在编译器领域的创新与优势。
45 3
|
18天前
|
机器学习/深度学习 人工智能 自然语言处理
【AI系统】知识蒸馏原理
本文深入解析知识蒸馏(Knowledge Distillation, KD),一种将大型教师模型的知识高效转移至小型学生模型的技术,旨在减少模型复杂度和计算开销,同时保持高性能。文章涵盖知识蒸馏的基本原理、不同类型的知识(如响应、特征、关系知识)、蒸馏方式(离线、在线、自蒸馏)及Hinton的经典算法,为读者提供全面的理解。
45 2
【AI系统】知识蒸馏原理
|
21天前
|
存储 人工智能 JavaScript
【AI系统】公共表达式消除原理
公共子表达式消除(CSE)是编译器优化技术,旨在通过识别并消除重复计算的表达式,减少计算量,提升程序执行效率。CSE分为局部和全局两种,局部CSE仅在单个基本块内操作,而全局CSE跨越多个基本块。技术手段包括局部值编号和缓式代码移动等,广泛应用于传统编译器及AI编译器中,有效简化计算图,降低计算成本。
41 4
|
22天前
|
存储 人工智能 缓存
【AI系统】布局转换原理与算法
数据布局转换技术通过优化内存中数据的排布,提升程序执行效率,特别是对于缓存性能的影响显著。本文介绍了数据在内存中的排布方式,包括内存对齐、大小端存储等概念,并详细探讨了张量数据在内存中的排布,如行优先与列优先排布,以及在深度学习中常见的NCHW与NHWC两种数据布局方式。这些布局方式的选择直接影响到程序的性能,尤其是在GPU和CPU上的表现。此外,还讨论了连续与非连续张量的概念及其对性能的影响。
44 3
|
21天前
|
机器学习/深度学习 人工智能 编译器
【AI系统】Auto-Tuning 原理
本文探讨了在多样化硬件平台上部署深度神经网络(DNN)时,传统算子库面临的挑战及解决方案。随着硬件平台的多样化和快速迭代,手动编写高性能算子库变得日益困难。文中介绍了基于TVM的三种自动调优系统——AutoTVM、Ansor和Meta Scheduler,它们通过自动生成高性能算子,有效解决了传统方法的局限性,提高了DNN在不同硬件平台上的执行效率。
26 1
|
27天前
|
机器学习/深度学习 人工智能 并行计算
【AI系统】NVLink 原理剖析
随着AI技术的发展,大模型参数量激增,对底层硬件和网络架构提出新挑战。高效训练这些模型需要大规模GPU集群及高速网络连接,以实现快速数据交换。然而,网络瓶颈限制了GPU性能的充分发挥,表明单纯增加GPU数量不能线性提升算力。因此,算存互连和算力互连技术成为关键,如PCIe、NVLink和NVSwitch等,它们通过提高数据传输速度和效率,支持大规模并行计算,解决了大规模GPU集群中的通信延迟问题,推动了万亿级模型训练的实现。
51 2
|
1月前
|
机器学习/深度学习 人工智能 算法
强化学习在游戏AI中的应用,从基本原理、优势、应用场景到具体实现方法,以及Python在其中的作用
本文探讨了强化学习在游戏AI中的应用,从基本原理、优势、应用场景到具体实现方法,以及Python在其中的作用,通过案例分析展示了其潜力,并讨论了面临的挑战及未来发展趋势。强化学习正为游戏AI带来新的可能性。
93 4
|
28天前
|
存储 缓存 人工智能
【AI系统】GPU 工作原理
本文详细解析了AI计算体系中的GPU工作原理,重点介绍了GPU与CPU在架构上的差异,强调了GPU在并行计算方面的优势。文章通过$AX+Y$的例子,展示了GPU如何通过并行和并发提高计算效率,并深入探讨了GPU的缓存机制及线程原理,解释了GPU如何通过大量线程和Warp来掩盖延迟问题,实现高效计算。
75 0
|
21天前
|
存储 人工智能 编译器
【AI系统】常量折叠原理
常量折叠是一种编译器优化技术,通过在编译阶段计算常量表达式,用结果替换原表达式,减少运行时计算。传统编译器在编译期间识别并计算常量表达式,如 Python 中 `day_sec = 24*60*60` 被优化为 `day_sec = 86400`。AI 编译器则在计算图中进行类似优化,如 TensorFlow 通过分析计算图节点,提前计算确定结果的节点,提高执行效率。
29 0
|
28天前
|
机器学习/深度学习 人工智能 并行计算
【AI系统】Tensor Core 基本原理
本文深入介绍了英伟达GPU中的Tensor Core,一种专为加速深度学习设计的硬件单元。文章从发展历程、卷积计算、混合精度训练及基本原理等方面,详细解析了Tensor Core的工作机制及其在深度学习中的应用,旨在帮助读者全面理解Tensor Core技术。通过具体代码示例,展示了如何在CUDA编程中利用Tensor Core实现高效的矩阵运算,从而加速模型训练和推理过程。
72 0

热门文章

最新文章