刚开始学习 Python,萌新总有一颗渴望做实践享受成就感的心,最近 "跳一跳" 比较火,在看了一些前辈的辅助程序教程后,我就也想写一个自己版本的辅助(for Android).
写辅助程序的起因就是这样啦,我觉得写 "跳一跳" 的辅助比玩 "跳一跳" 更有趣,所以对于那些被辅助程序伤到的 "跳一跳" 玩家,我表达一下歉意~
另外也希望把我的思路分享给大家,代码挂在这里,供大家各取所需,自娱自乐~
enjoyself.wechathop
下面就聊一聊这个程序的细节啦,首先是实现原理,萌新版本的原理当然很简单啦.由于很多的知识不太懂(比如 os 库,Image 库,ADB 操作等),不懂的部分我就试着套教程,或者照搬别人的轮子.我主要借鉴的是 @霍雍 在下面这篇文章里的程序结构,只是修改了其中的算法.
霍雍:人人都能看懂的 "跳一跳" 平民算法
程序中最主要的部分都集中在 "jump_one 函数"(基本是 copy 了 @霍雍 的部分),每一次跳跃的实现主要分为五个步骤:
第一步,通过 ADB 截屏,命名为 x.png,存储到手机
def jump_one(filename):
os.system('adb shell screencap ' + phonePath + filename) #第一步
os.system('adb pull ' + phonePath + filename + " " + imgPath + filename) #第二步
os.system('adb shell rm ' + phonePath + filename) #第三步
swipetime = timecalculate(filename) #第四步
os.system('adb shell input swipe 300 1500 300 1500 ' + str(swipetime)) #第五步
time.sleep(1)
return swipetime
第二步,通过 ADB 将 x.png 从手机复制到电脑
第三步,通过 ADB 删除手机上的 x.png
第四步,根据 filename 调用对应命名的截图,计算触摸时间
第五步,根据所算时间,通过 ADB 执行原位滑屏操作
容易看到,五步中有四步是通过 os.system() 函数控制 ADB 完成的(导致效率不高,时间都花在 ADB 操作上...T-T),比较简单就略过了,核心部分在时间计算上.
PS:我称跳动的小人为 "棋子(chessman)",下一个落脚的物体为 "棋盘(chessboard)".
时间计算 → 距离计算 → △X 计算
有个隐藏信息是,触摸时间与跳跃距离成正比,因此我们算出需要跳跃的距离,就能得到时间.
另一个隐藏信息是,跳跃方向都是斜着的,但倾斜角度 "基本是" 固定的(实际有少许偏移),因此我们只需计算 △X 或者 △Y 即可.
最后一个隐藏信息是,游戏初始时的 "棋子" 和 "棋盘" 位置总是固定的,因此可以反复测试初始游戏时的 触摸时间 init_time 与 距离 init_X 的关系,得到这个常数比值 K 后,后续计算就简单了:
△T = △X * K = △X * (init_x / init_time)
跳跃思路
△X 计算 → 找特征像素的坐标
如何找 "棋子" 与 "棋盘" 的△X 呢?我看到的帖子,大家有用像素识别的,有用深度学习图像识别的,有用 OpenCV 提取图像边缘再识别的...... 我...... 我... 我会的少,只能用笨办法的 "像素识别" 了...
即找到 "棋子" 左上角的第一个像素 (x, y),再计算该行属于 "棋子" 像素的个数 n,从而 X = x + n//2,即可得到 "棋子" 的横坐标 X 啦,"棋盘" 同理.原理示意图如下:
识别特征像素
找特征像素的坐标 → 像素识别
识别利用的特征包括:"棋子" 顶部像素颜色稳定,亮度较低,与背景像素色差较大;"棋盘" 顶部像素颜色不稳定,亮度不稳定,但亮度一定比 "棋子" 高,且与背景像素有一定色差(并且总与 "棋子" 的第一像素保持一定距离,用于寻找位置较为靠近的 "棋盘").
利用上述特征,for 循环逐个对截图像素进行判断,即可筛选出特征像素啦,效果如下:
识别 "棋子"
识别 "棋盘"
从结果来看,识别的成功率还不错~ 然并卵,并不能保证 "棋子" 不跑偏,我觉得可能的原因包括像素识别误差的累积(比如并非所有 "棋盘" 的中心都在其顶点的正下方,如 "硬盘" 物体),ADB 操作的延迟等等.
逐渐跑偏
大家可以看到 "棋子" 逐渐越跳越偏的过程,其原因就在于存在细小偏差,不能保证每次都落在中心这就意味着,棋子容易 "中心 → 中心 → 中心" 连中多元,也容易 "歪一点 → 再歪一点 → 扑街".不过,"棋子" 其实并非是沿固定方向跳跃,而是以 "棋子" 中心与下一个 "棋盘" 中心构成的直线的方向跳跃,视情况这种偏差可能会相互抵消,回到正轨.(暂时无图...)
在上述本征不稳定性的基础上呢,大家可能需要多试几次才能拿到理想的分数,测试大概平均能拿到 1000+,基本上 1000~3000 问题不大,我最高拿过 3179.
最好成绩
程序的效率并太高,优化后平均跳一次需要 4.5~5s,经过测试,约 4s 的时间花在 ADB 的操作上了...
...┐('~`;)┌ ...
如果开发个 APP,所有操作都在手机上进行会不会快一些...
使用说明:
我用 Python3 写的,在 Windows 7 上测试跑得很欢,Linux 上没有试.
由于使用了 ADB 工具,所以是针对 Android 手机的,手机需要打开 "USB 调试",电脑端需要安装好手机驱动(或者让手机助手如豌豆荚连一下手机,再退出豌豆荚).
建议打开 cmd 命令行,用 "cd" 命令,进入 ADB 工具所在路径,输入 "adb",检测 adb 是否正常使用.
运行. py 文件前,建议用 IDE 打开,调整一下基本参数(在程序最下面):
预期跳多少步,默认 70
分辨率,默认 1440 * 2560 (for Samsung S6)
init_x,经过我的测试,填 607 (for 1440 * 2560)或 455 (for 1080 * 1920, 1080p),效果比较好,默认 607
init_time,经过我和 @霍雍 各自测试,最后不约而同认为 723 比较好,默认 723
phonePath,手机上临时存储截图的路径,建议新建一个,默认 / storage/emulated/0/test/
imgPath,电脑端存储截图的路径,建议新建一个,默认 C:\Users\Administrator\test\
开始游戏:
手机连接电脑,可能有 "是否允许该计算机调试" 之类的弹窗,点允许调试.
手机进入 "跳一跳" 界面后,电脑端运行. py 文件即可.
运行. py 文件的方式有两种,用 Python 的 IDE 打开并执行;或者用 cmd 命令执行 "python + .py 文件的路径" 指令,如:
python c: \users\administrator\test\wechathop.py
也可以在 cmd 窗口输入:"python"+" "(空格),
然后把 wechathop.py 文件拖入 cmd 窗口,按回车执行即可.
萌新上路,胆大粗心,很多代码写法以及程序使用方法上不严谨,不标准,本程序也仅供娱乐,请其他萌新们谨慎参考,大佬们多指导~~
来源: http://www.jianshu.com/p/f202796ba27a