我正在参与「兔了个兔」构思投稿大赛,详情请看:「兔了个兔」构思投稿大赛
0x0、事出必有因
新年开工榜首周,节后综合征,无心作业~
(图片出处:深圳卫健委公号),咱们都讨了多少开门红包哇?说粗来,让杰哥酸一下~
记住春节前最终一周,本想玩小游戏消磨时刻,成果却被一个 “孤岛求生” 的玩法拿捏,一怒之下 手搓”辅佐”,利用 “科技” 降维打击,直接屠榜,最终还写了一篇文章 《手搓游戏”辅佐”,你怎样跟我玩?》 记录详细的实践进程 。
分数是 第二名的两倍,你怎样跟我玩?
然后,这小游戏春节的时分很接地气地推出了一系列 “春节活动”,其中有个形式叫 “以诗会友”,玩法如下:
em?这不纯纯的 对春联 吗?(也叫对对子、对春等),依据上联对出下联。而在游戏里的规则是这样的 :
体系给出 完好上联、部分下联 (也可能全不给) 及一些 备选词,玩家依据这些 猜出完好下联,然后 将对应备选词拖拽到正确的框框中 补全下联。下联正确取得积分,切到下一题,如此循环,直至倒计时完,游戏完毕。
简略,鄙人可是 七省文状元兼参谋将军,绰号对王之王的对穿肠,会怕这个?直接开对~
在经历了好几局一个都对不出来后,杰哥:
em… 智力不够科技凑,老老实实想办法整个 辅佐 吧!
思路分析
对春联的玩法本质上便是常见的 问答类游戏,记住之前有段时刻,这类小游戏超火,什么全民答题赢现金,当时涌现了不少的 “辅佐”。剖析下这类辅佐的完成原理,能够简略拆解成这三步:
- 辨认问题:原生类-拿到问题组件直接提取文本,非原生类-截图然后进行OCR文字辨认;
- 检索答案:利用查找引擎、问答机器人、查题API、题库等获取问题的正确答案;
- 主动答题:拿着检索到的答案模仿用户答题,如填空、点击选项、勾选、拖拽点击等;
思路非常清晰,接着便是依据这款小游戏的实际情况,来开发对春联的 “辅佐” 了~
0x1、问题辨认
小游戏非原生,直接 无脑OCR,截个屏,丢 chineseocr_lite 辨认看下作用:
还能够,上联正确辨认,下联只错了一个字。拿上下联的大约坐标区域 裁剪 一下,扫除无关项进步辨认速度之余,看能否进步准确度~
裁剪后的图片:
速度好像快了,但辨认率反而降低了:
转灰度后仍旧如此:
我又写了一个拼接图片的办法,测验将上下联水平拼接一波:
间距设置为400,辨认成果如下:
奇特,居然好一点,再灰度化下试试看:
更好了,换成其它对联试试:
辨认成果:
擦,由于填空的框框,上下联直接被拆散了,所以为了保险点,还要对辨认成果做下处理:
依据坐标判断是上联仍是下联,正则提取中文(有时会辨认出一些标点符号),最终拼接
详细代码如下:
运转看看作用:
能够,又试了几个样本发现都能比较准确地拿到上下联~
0x2、检索答案
上联拿到了,接着便是检索答案了,杰哥的思路有三:查找引擎、ChatGPT API、题库,一一测验~
① 查找引擎
没找到直接能用的查找API,只能 浏览器拜访咯,一种最粗犷的办法便是用 webbrowser
恳求URL,以百度查找为例:
while True:
input() # 操控台每按一次回车触发一次检索
first_couplet = extract_couplet() # 解析当时上联
# 查找下联
webbrowser.open("https://www.baidu.com/s?wd={}的下联".format(first_couplet))
运转后,每次回车都会翻开浏览器检索:
从查找成果中,杰哥发现了一个问题:一个上联可能有多个匹配的下联,但游戏里只要 “一个正确答案”,这就需求咱们用肉眼 + 脑子来筛选出匹配的下联。费时费力,难顶…
得把这个进程主动化,主动解析成果并辨认出适宜对联,思路马上来:取得网页源码 + 正则提取,先试下 request库 直接恳求URL:
情理之中,直接触发了 百度安全验证,那就浏览器模仿拜访吧。直接 Puppeteer库 走一波,这库之前介绍过了:
Puppeteer 是Google官方出品的经过DevTools协议口操控headless Chrome的 NodeJS 库,经过其供给的API可直接操控Chrome模仿大部分用户操作,来进行UI Test、爬虫拜访页面收集数据。而 Pyppeteer 则是Puppeteer的Python完成,背面也是依赖类似于Chrome的浏览器 → Chromium 来模仿。
直接写代码拿到网页源码:
运转下看看:
能够,成功拿到网页源码,接着便是思考怎么 写正则 了,直接写出最粗犷的匹配表达式 (应该能看懂吧~):
# 上联 → 要么是中英文逗号中的一个,要么没有 → 中文{上联的长度}
match_pattern = re.compile(r"{}[,,]?([\u4e00-\u9fa5]{{{count}}})".format(first_couplet, count=len(first_couplet)), re.S)
匹配下试试,同时把成果放到set中间接 去重:
运转看看:
作用很赞,再往下细化便是:遍历 部分下联+可选词,然后核算每个下联中呈现这些字的比重(个数),最高的那个便是 “正确答案” 啦!
查找引擎这Part就到这,接着试试 ChatGPT ~
② ChatGPT API
ChatGPT就不用介绍了,前阵子火得一塌糊涂,注册办法能够看我之前写的《无聊试试最近很火的ChatGPT (附:注册办法)》,或许某宝直接买别人注册好的。
这里不需求像百度查找相同经过浏览器拜访,由于它供给了API,注册完账号,登录后翻开 API keys,点击 Create new secret key
,创立一个秘钥:
注意,这个Secret Key要自己存好!网站不供给后续检查,忘记了的话只能删掉从头创立。先pip装下库:
pip install openai
# 假如很慢的话,能够用清华镜像源
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple openai
直接copy样例:
import openai
start_sequence = "\nA:"
restart_sequence = "Q: "
# Replace `<your_api_key>` with your actual OpenAI API key
openai.api_key = "<your_api_key>"
prompt = " "
while len(prompt) != 0:
# Ask a question
prompt = input(restart_sequence)
# prompt = "tell me in Chinese:" + input("\n请输入要翻译的内容:")
# Get my answer
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
temperature=1,
max_tokens=2000,
frequency_penalty=0,
presence_penalty=0
)
# Print my answer
print(start_sequence, response["choices"][0]["text"].strip())
运转,测验发问:
这啥?AI自己乱编?调整话术再次打听:
啊,这…我多嘴问了两句:
牛,直接把我整无语了,可能我需求学习下《发问的艺术》吧,看来ChatGPT的创造性不太适合咱们的业务场景…
附:几个根本参数的意义
- model → 要运用的模型的 ID,拜访 OpenAI Docs Models 页面能够检查悉数可用的模型
- prompt → 生成成果的提示文本,即你想要得到的内容描绘
- max_tokens → 生成成果时的最大 tokens 数,不能超过模型的上下文长度,能够把成果内容复制到 OpenAI Tokenizer 来了解 tokens 的计数办法
- temperature → 操控成果的随机性,假如希望成果更有构思能够测验 0.9,或许希望有固定成果能够测验 0.0
- top_p → 一个可用于代替 temperature 的参数,对应机器学习中 nucleus sampling,假如设置 0.1 意味着只考虑构成前 10% 概率质量的 tokens
- frequency_penalty → -2.0 ~ 2.0 之间的数字,正值会依据新 tokens 在文本中的现有频率对其进行赏罚,然后降低模型逐字重复同一行的可能性
- presence_penalty → -2.0 ~ 2.0 之间的数字,正值会依据到目前为止是否呈现在文本中来赏罚新 – tokens,然后添加模型谈论新主题的可能性
- stop → 最大长度为 4 的字符串列表,一旦生成的 tokens 包括其中的内容,将中止生成并回来成果
③ 题库
问答类游戏,根本都是有题库的,玩了几局发现 重复率还挺高,阐明规划不大 (估量30条左右)。然后,这形式随时能够玩,非实时 (所有玩家同时参与),试了下断网还能下一题,猜想是提前把题库下到本地,然后随机抽取生成问题。
综上,很大约率便是本地核算最终提交成绩,假如能 拿到提交成绩的接口,还对个屁春联,直接越过答题环节。
只惋惜,杰哥春节没带 “开发鸡” 回家,抓不了包,同理,没办法抓到题库。
无法直接获取,就只能自己 手动收集 了,自己玩,配合 查找引擎,把做过的题目记下来。
在记的时分,杰哥又想到了一个 “骚操作”,其实只需求重视 上联的榜首个字 + 备选词 就能够猜到下联了。直接写出代码:
比方辨认到”爆”字,直接输出下联:
接着便是把 下联和备选词 也抠出来了,核算呈现的比重(次数),最高的便是正确的下联。相同写出代码:
试验下这三个样本:
运转输出成果如下:
牛批,此处应有掌声!!!
当然,优化空间还有很多,比方即将辨认的文字都拼接到一张图再辨认,减少辨认次数也会快上不少~
0x3、主动答题
滑动的话,adb模仿滑动即可,直接给出东西代码:
def swipe(start_x, start_y, end_x, end_y):
"""
滑动,从开始坐标点滑动到结尾坐标
:param start_x: 开始坐标点x坐标
:param start_y: 开始坐标点y坐标
:param end_x: 结尾坐标点x坐标
:param end_y: 结尾坐标点y坐标
:return:
"""
return start_cmd('adb shell input swipe %d %d %d %d' % (start_x, start_y, end_x, end_y))
开始坐标,OCR那里能拿到,剩下的难点便是拿到 放置框的坐标,这个也不难,最简略的办法便是:
手动抠坐标点写,死几个组合,依据上联确定是几个字的组合(五六七),然后判断备选词对应第几个字,直接拿到坐标。
当然也能够搞得复杂点,动态核算,先找个适宜的阈值二值化图片 (如130):
然后便是 水平缓竖直方向遍历坐标点,找到闭合的正方形,直接写出遍历代码 (顺带画出来更直观):
运转看下作用:
根本能看到矩形的雏形了,不过得干掉其它的干扰像素点,正方形的四个角 一定是水平缓竖直方向相交的点:
处理后:
左面坐标点和有点坐标点肯定是对称的,处理下:
处理后:
能够,但还有瑕疵,把图片扩大:
还得再处理下,去掉粘连的点,由于咱们 只需求一个:
运转后能够看到要填 四个字的八个坐标点了,
同时也能够看到制作出来的四个正方形:
相同试下其它几个样本:
牛逼,完美辨认。拿到放置框的坐标,接着算出中心点,调用上面adb滑动的东西办法传参即可~
当然,动态核算这部分 并不优雅 乃至能够说有些 粗犷 了,用了很多集合和无脑遍历,但时刻仓促,能用就行。
本来想录个主动对春联的视频 显摆显摆,惋惜活动下架了,那只能靠各位读者自行脑补啦~
行吧,本节就到这,假如对你学习Android主动化有所协助,欢迎三连,感谢~
参考文献:
-
用Python调用OpenAI API做有趣的事