一、绝地反击

最近女票迷上了某平台的连连看对战小游戏,于是免不了要找哥哥我 PK 一翻,虽然是被迫卷入战争,但是以朕惊世骇俗的智商,那当然是胜券在握啦~~ 没曾想,几个回合下来,竟被啪啪啪打脸,快把这个月的口粮都输光了(每把5块钱啊,肉疼!!) 哎,完全拼手速是没有希望的了,得想办法让连连看自动打

“连连看”都不会打的直男们,赶紧去怼一局

二、可行性

前段时间跳一跳火起来的时候,有人就通过 adb 截屏并发送到电脑分析,再求得距离然后计算出按键时长,最后通过 adb shell 自动按键,从而获得完美跳跳分,这一招用在连连看是否管用呢? 理论上,靠谱,分解如下:

  1. adb 截图传到电脑
  2. 将连连看的点击区域识别为一个二维矩阵,每一种小动物用一个数字表示
  3. 对二维矩阵求解,计算出每个位置的点击顺序数组
  4. 通过 adb shell 一把梭,一次性点掉所有

酱紫如果顺利的话并且不被女票发现,赢回三个月的口粮都很有希望呀~~

三、实施步骤

技术选型

从上一节的分析来看,方案的实施涉及到很多图片的分析处理,Python 可以方便的调用很多图片库,而且网上也有很多作业可以抄,所以选择基于 Python 来做

环境搭建

没有很具体的安装步骤,需要的咨询谷歌哥

1) 安装 adb 环境。安装完成后,用数据线连接一台 android 手机,执行一些简单的 adb 命令预热下

// 是否连接上
adb devices// 可否截屏保存
adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png /yourDocuments/screenshot.png// 可否点击屏幕
adb shell input tap 100 100
复制代码

2)安装 python 和相关的图片库,在安装 openCv 的时候还踩了个大坑,记录了下,仅供参考

图片处理

1)截屏保存 在终端,执行如上的两个 adb 命令就可以截屏保存了,也就是说,这里需要一个可以调用终端命令,同时可以等待返回的 Python 方法:

// 执行终端命令的方法
def sh(command):p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)print p.stdout.read()// 截屏保存
sh('adb shell /system/bin/screencap -p /sdcard/screenshot.png')
sh('adb pull /sdcard/screenshot.png /yourDocuments/screenshot.png')
复制代码

2)裁剪有效区域、再等比切出小动物头像 如果不要求很通用只是对你的手机有效的话,那么只需要将第一步截下来的屏幕用工具来量一量(如 Mark Man),就可以用如下方式裁剪出有效区域

from PIL import Image
def cut (im, x, y, w, h, name):region = im.crop((x, y, x+w, y+h))region.save("./screenshot/" + name + ".png")# 有效点击区域裁剪 (不通用的做法是,把这个矩形的坐标量出来)
gx = 43
gy = 401
gw = 993
gh = 1420
cut(Image.open("./screenshot/screenshot.png"), gx, gy, gw, gh, 'main')
复制代码

如果要做得通用一些,就需要计算图片的比例了(只用于打败女票的,完全没必要嘛)

然后再按照10行7列切成小块,并且根据二维数组的下标命名

# -*-coding:utf-8-*-
from PIL import Image
import cutImg
def cut ():im = Image.open("./screenshot/main.png")# 图片的宽度和高度img_size = im.sizewidth = img_size[0]height = img_size[1]distanceW = width / 7distanceH = height / 10print(distanceW, distanceH)x = 0y = 0for num in range(0, 10):for i in range(0, 7):x = distanceW * iy = distanceH * numname = str(num) + str(i)cutImg.cut(im, x + 15, y + 15, distanceW - 20, distanceH - 20, name)return [distanceW, distanceH]
复制代码

3)解析小动物头像输出数字二维矩阵(第一回合)

这一步着实需要下功夫,还踩了不少坑~~

首先想到的是通过求解图片的 hash 值,利用 hash 值来比对图片的相似度(例如感知 hash 算法)。网上有各种求 hash 值的算法,实现起来倒也简单,但是,比较的正确率只能达到百分之七、八十(这样我们分析出的点击路径,肯定打不过啦!!),主要是这些小动物头像在 hash 算法下显得都太相似了,拿感知哈希算法来说: a) 缩小图片尺寸 b) 转为灰度图片 c) 计算灰度平均值 d) 比较像素的灰度 e) 计算哈希值 f) 对比图片指纹

想象一下,上面的小猪头和小猴头经过如上的变换后,还有多少差异呢?

转念一想,这个问题在机器学习领域,不过是那种最最简单的分类问题,so,完全可以先训练一个模型出来

4)解析小动物头像输出数字二维矩阵(第一回合) Turicreate 是苹果开源的基于 python 机器学习框架,特点是轻量(只是分类相似的图片而已,当然是越简单越好),先安装之

然后将上面写好的截屏裁剪代码多执行几次,手工分类,准备好训练数据:

给每种小动物创建一个文件夹,再将所有该种类的动物装进去

开始训练,并保存模型:

#!/usr/bin/env python
#encoding=utf-8
import turicreate as tc
img_folder = 'data'
// 导入数据
data = tc.image_analysis.load_images(img_folder, with_path=True)
// 使用文件名来做标签
data['label'] = data['path'].apply(lambda path: path.split('/')[len(path.split('/')) - 2])
data.save('doraemon-walle.sframe')
// 百分之八十的数据用于训练,百分之二十用于测试
train_data, test_data = data.random_split(0.8, seed=2)
// 开始训练模型
model = tc.image_classifier.create(train_data, target='label')
// 测试模型
predictions = model.predict(test_data)
metrics = model.evaluate(test_data)
// 输出测试结果
print(metrics['accuracy'])
model.save('my_model_file')
复制代码

执行到倒数第二行的时候,顺利输出1.0(百分百的正确率有木有):

使用训练好的模型,输出二维矩阵:

import turicreate as tc
loaded_model = tc.load_model('my_model_file')
def getDataset():data = tc.image_analysis.load_images('screenshot', with_path=True)arr = loaded_model.predict(data)result = []temp = []for index in range(len(arr)):if (index % 7 == 0):temp = []if ((index + 1) % 7 == 0):result.append(temp)// f 为 0,标记为未删除temp.append({'v': int(arr[index]), 'f': 0})return result
复制代码

路径求解

1)判断两个动物图标可连 需要满足如下条件: a) 相同的图标 b) 两种直接存在一条通路,它是一条只经过没有图案的地方、且转折点不超过2个的折线 具体代码实现可以看看这篇博文的分析(虽然是 C 版),这里我就不贴了,繁琐占篇幅

2) 搜索路径,最简单粗暴的一种做法 (1)从矩阵中挑出一个未被标记为删除的元素,(2)再从矩阵中余下的不被标记删除的元素寻找一个跟它一样的元素,判断是否可以相连,是则将两个元素标记为删除,并将点击坐标压入坐标数组,否则重复(2),(3)重复(1),知道找到所有的点击坐标点 但是这种做法是 O(nXn),很遗憾,暂时也没有想到更好的办法,只是想到了一个小小的优化策略,开始先遍历一轮,将所有挨着的相同图标消掉(显而易见的事情当然要先办啦),减小 N,节省一下算法的时间

然后在“盲狙”的过程中,因为循环停止的条件是找到所有的坐标点,假如游戏给了个无解的矩阵,或者咱们图片识别错了导致无解,就会陷入死循环(虽然这样的概率极低,没遇到过),所以要做一下循环保护

# 遍历消除(盲狙)
def commonBuild():global dataglobal posfor num in range(0, 10):for i in range(0, 7):item = data[num][i]if (item['f'] == 1):continuefor ix in range(0, 10):if (item['f'] == 1):breakfor iy in range(0, 7):item1 = data[ix][iy]if (item1['f'] == 1 or item1['v'] != item['v'] or (ix == num and iy == i)):continueif (remove.canRemove(num, i, ix, iy, data) == 1):item['f'] = 1item1['f'] = 1pos.append(getPos(i, num))pos.append(getPos(iy, ix))break
// 达到 70 也即所有的坐标都找到即停止
// 否则也最多循环十次
count = 0
while (len(pos) < 70 and count < 10):count = count + 1commonBuild()
print(count)
复制代码

很幸运,经过优化后的算法,基本上每次 count 都输出为 1,不需要遍历太多次。假如真的出现了无解矩阵,循环了 10 次退出了,那该如何是好呢?这个时候自己将机器没有打完的点掉也应该没有难度了

adb 一把梭

克服艰难险阻把坐标数组计算出来之后,后面的事情就简单了,执行 adb 命令一把梭

for index in range(len(pos)):command = 'adb shell input tap ' + str(pos[index][0]) + ' ' + str(pos[index][1])print(command)os.system(command)
复制代码

四、后来,我赢了么?

然而并没有!!! 因为每条 adb 命令的执行间隔基本差不多要到 1 秒,逐条执行完之后黄花菜都凉了,要知道正常人打完一局也就 30、40 秒,作为机器人,这打完居然要 1 分多钟,真是弱智机器人

尝试将命令写入一个 sh 文件,然后通过 adb shell 执行批处理文件,稍微快了一点点,但是依然还需要几十秒(在此之前还尝试写一个堡垒 app 来一次性接收坐标,然后再 android 系统中执行命令,都木有用)。然后优化分析算法的动力都木有了

不过话说回来,跟女票打游戏,还要用赢的么?

感兴趣加微勾搭:facemagic2014

程序员玩连连看的正确姿势相关推荐

  1. 面试全攻略,教你解锁程序员面试时的正确姿势

    面试全攻略,教你解锁程序员面试时的正确姿势 随着金九银十的到来很多人在考虑跳槽,特地奉上面试攻略,拿到offer不是梦 面试,难还是不难? 取决于面试者的底蕴(气场+技能).心态和认知及沟通技巧. 面 ...

  2. 程序员取悦女票的正确姿势---Tip1

    代码地址如下: http://www.demodashi.com/demo/11695.html 前言 女孩子都喜欢用美图工具进行图片美容,近来无事时,特意为某人写了个自定义图片滤镜生成器,安装到手机 ...

  3. 从技术思维角度聊一聊,『程序员』摆地摊的正确姿势

    有人说程序员这个职业,三年升高工,七年做架构,十年送外卖.对此虽然我也曾非常认可,但现在我可以前瞻性(马后炮)地说四个字,杞人忧天!目光肤浅!正所谓天生我材必有用,用完再把外卖送,现在,新的风口--万 ...

  4. 程序员取悦女票的正确姿势---Tip1(iOS美容篇)

    前言 女孩子都喜欢用美图工具进行图片美容,近来无事时,特意为某人写了个自定义图片滤镜生成器,安装到手机即可完成自定义滤镜渲染照片.app独一无二,虽简亦繁. JH定律: 魔镜:最漂亮的女人是你老婆 魔 ...

  5. 程序员造轮子的正确姿势

    作者 | 黄峰达,CSDN 博客专家 Phodal 责编 | 唐小引 出品 | CSDN(ID:CSDNnews) 过去的几年里,我一直在打造各式各样的编程相关的工具.这些工具有的是用于指导软件开发工 ...

  6. 程序员过端午的正确姿势,一般人看不懂

    当然是选择 Coding... 啦... 推荐 扩展阅读 1.<ECMAScript 6 系列>原创教程 2.<Vue2.0基础系列>原创教程 3.<ECMAScript ...

  7. 通过机器学习识别“迪士尼在逃公主”,程序员宠女的正确打开方式!

    到了庆祝的时候了!我们刚刚送走了圣诞老人.现在正等待新年的钟声敲响.所以我想到建立一个很酷的东西(至少我的七岁小公主会觉得)同时学一点机器学习.所以我们要做一个什么? 我借用的我女儿所有迪士尼公主人偶 ...

  8. [Linux] PHP程序员玩转Linux系列-备份还原MySQL

    1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 前几天有个新闻,说是g ...

  9. [Linux] PHP程序员玩转Linux系列-腾讯云硬盘扩容挂载

    1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 4.PHP程序员玩转L ...

  10. [Linux] PHP程序员玩转Linux系列-Linux和Windows安装nginx

    1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 4.PHP程序员玩转L ...

最新文章

  1. centos7上开启单用户模式
  2. iOS中js与objective-c的交互(转)
  3. MyBatis 入门到精通(二) SQL语句映射XML文件
  4. linux常用命令 打开文件,【Linux】常用命令 lsof查看打开的文件
  5. 修改eclipse配置文件properties编码格式
  6. xml property标签注入一个类变量_java开发两年,连Spring的依赖注入的方式都搞不清楚,你工作可能有点悬!...
  7. mousetrap.js使用详解
  8. mysql analyze_mysql analyze和optimize
  9. evolution ubuntu邮箱_linux下有什么好用的邮件客户端?
  10. Mac 下终端运行C++
  11. 大学python考试题及答案_中国大学慕课mooc用Python玩转数据期末考试大全答案
  12. 小程序----个人中心页面
  13. Web网站模板-横向滚动个人简历响应式网站模板(HTML+CSS+JavaScript)
  14. 传奇开服教程完整版GOM引擎超详细的单机架设图文教程(小白一看就会)
  15. GPS授时服务器(NTP授时)为银行系统提供时间服务
  16. MATLAB矩阵分块拼装
  17. 深度学习项目开发流程
  18. 【AUTOSAR CanDrive 2.了解通信Hoh、CanId与PduID的Mapping关系】
  19. OpenCart 最新使用教学视频合集
  20. 启动报错,找不到tools.jar,C:\Program Files (x86)\Common Files\Oracle\Java\javapath问题,java环境变量不生效

热门文章

  1. 关于正则表达式中^和$
  2. 重新安装Linux自带的JDK
  3. canvas绘制圆环
  4. Json 转换 1 转成 true 0 转成false
  5. java多线程总结二(转)
  6. UE中使用正则表达式的一些技巧
  7. SpringMVC, Spring和Mybatis整合案例一
  8. 2015/8/30 Python基础(4):序列操作符
  9. 利用Quartz2D--context绘制矩形
  10. 隔行变色( 表格隔行变色 + LI 浮动隔行变色 )