数独android程序,Android-数独世界自动完成标准数独的小脚本

最近从GP上翻出了之前玩的一款消磨时间的游戏“数独世界” --le.lenovo.sudoku,登陆了GP账号发现已经取得了一些成就,但之前的记录没了,得从新开始玩。懒得费力的去重复完成之前关卡,于是想着怎么能自动填充数独。

f54f44d192f3

抱着试一试的态度,开始了研究。

一、反编译

这款app做了混淆处理,和一些简单的防反编译的措施。正常的工具会失败,得使用强力的反编译工具才行。

1、去广告

广告挺多的,从splash activity、ResumeGameActivity、SudokuActivity等页面都有广告。查看了一下,是使用的Android原生广告,并且程序打印了广告的一些log出来。顺着log可以找到关键地方,然后禁用掉。在AndroidManifest.xml中,也可以看到广告activity的声明,直接删掉就好了。剩下可能残留一些banner广告,暂时留着吧,也给开发者留点收入。

2、分析页面布局

游戏的主页面是SudokuActivity,查看布局发现,棋盘宫格的部分是自定义SuduPuzzleView,使用draw方法绘制出来。因为对Android不了解,没想到什么办法能够识别这块内容。代码中做了混淆,数独的生成的地方也懒得找(不才,没找到),于是就换了种思路,打算用python来解决。

二、用python解决

总体的方法思路如下:

识别初始化的数独 -> 解数独 -> 将解填入至游戏中

1、解数独

最复杂的部分就是解数独了,好的算法会更快。但是算法什么的目前还搞不定,先找一找解数独的相关资料用现成的。发现一个排除候选猜测法,感觉还是很不错的。试验了一些数独,解得很快,具体的算法可以参看他的page。

Python秒解最难数独

大概是这样:先是采用“排除候选法”,确定能确定的数字,中间还额外增加了隐形排除法用来简化问题。当所有的空位都确定后,仍有一些空位有多个值,这时候就采用作者后半部分的猜测算法。先是进行对候选的列表进行评分,根据评分选择候选列表中数字最少的一个来开始 猜测-回溯。

f54f44d192f3

2、识别数独

有了解数独的方法,剩下的就好办了,只需给他传一个初始化的data数组就行。有内容的填对应的数字,空内容的则填写0。

初始化数组的方法打算用图片处理:先把当前游戏页面截图,然后分别识别数独9x9宫格的对应内容,之后存入data数组

处理图片用的是PIL库,用到的基本操作都很简单:

# 读取image

image = Image.open(ori_img)

# 确定剪裁区域

box = (x_start, y_start, x_end, y_end)

# 剪裁图片

newImage = image.crop(box)

#保存剪裁的图片

newImage.save(save_file)

图片识别使用的是tesseract-ocr引擎和pytesseract库。因为游戏中数字的背景很纯(忽略颜色),所以非常容易识别,出错率很小。使用方法也异常的简单。需要注意的就是参数psm,不同情况需要调整psm参数才行。

# PIL 打开已经剪裁好的图片

image = Image.open(img)

# 转换为L -> 灰色图像 方便识别。

# 关于PIL其他8种模式可以翻阅其他资料,这里采用L模式

image = image.convert('L')

# 使用pytesseract模块中的image_to_string方法,将图片识别的数字转为string。

text = pytesseract.image_to_string(image, config='-psm 9')

# string转int,这里偷懒,没做校验。如果出错的就挂了╥﹏╥...

number = int(text)

# 返回数字供调用方

return number

附:psm参数的说明,可以使用命令tesseract --help-psm查看

$ tesseract --help-psm

Page segmentation modes:

0 Orientation and script detection (OSD) only.

1 Automatic page segmentation with OSD.

2 Automatic page segmentation, but no OSD, or OCR.

3 Fully automatic page segmentation, but no OSD. (Default)

4 Assume a single column of text of variable sizes.

5 Assume a single uniform block of vertically aligned text.

6 Assume a single uniform block of text.

7 Treat the image as a single text line.

8 Treat the image as a single word.

9 Treat the image as a single word in a circle.

10 Treat the image as a single character.

11 Sparse text. Find as much text as possible in no particular order.

12 Sparse text with OSD.

13 Raw line. Treat the image as a single text line,

bypassing hacks that are Tesseract-specific.

这样通过识别9x9宫格的图片后,我们就自然而然的转化为我们需要的data数组。另外,解法中最后提供的类型是numpy的ndarray类型。

3、填充数字

这里更懒,通过最原始的adb点坐标形式。。。将数独的81个数据与对应的81个坐标联系起来,通过for循环依次填进去。因为只在自己的机器上,所以坐标什么的都写死了😄。

# 点击空格坐标定位

adb -s %s shell input tao x y

# 输入当前空格的解

adb -s %s shell input text num_input_from_data

三、实验

过程主要耗费在初始化data数组的时候,因为是线性执行的来保证数组的正确顺序,识别完一个后,才识别下一个。关于顺序问题暂时没想好怎么优化,最后填充解的时候也是一个个填进去的🤣。。。

f54f44d192f3

最终效果,点开查看gif。

(不知道为什么,gif有的时候动,有的时候不动🤣)

f54f44d192f3

四、总结

其实到了后面,目的就已经不是自动解题了。。。而是在这个过程中接触的新东西。

1、了解了数独

之前只是单纯的玩儿,但是没想到解题的过程中运用了很高深的知识,尤其是自己摸索出的一切技巧,居然有一些高大上的对应名词。

2、查看了各种数独的解题算法

思路可以理解,但写不出来。。。

3、接触了Tesseract-OCR引擎

发现图像识别可以运用到自己的工作中,如解决一些需要人工验证的自动化。感觉非常好玩,在试验过程中,有一些识别的不是很好,还能通过训练来提高识别度。

数独算法说明:用三个二维数组记录数独每个点的状态,SD(i, j)显示数值,也是真实数值(1到9)。ST(i, j)状态,1可由用户输入,2是题目给定的,不能改。SY(i, j)这符串,记录每个点中可能的值。 1、在进行自动计算时,只计算ST(i, j)为1的点,首先将所有状态为1的点的SY(i, j)值全部设为"123456789",SD(i, j)值全部设为0 2、逐点扫描,找到一个点,然后将该点所在的行、列、区域中已存在的SD(x, y)值从SY(i, j)中删除,因为数独规则是一个数值,在行、列、区域都不重复。 3、经第二步处理后,SY(i, j)为空,说明题目错误,SY(i, j)值为一位数字,就说明该点的值是唯一的,可以确定了。 4、剩余的SY(i, j)值最少也是二个数字的,或更多位数。随机从这些两位数的SY(i, j)中选取一个点。取其中的一位确定为该点的值后,重复第2步。如果错误遇错,则重复执行第4步。直到所有点都被确定。 注意:第2步是需要多次重复执行的,所有可用递归函数完成。如果执行结果出现错误(某数出现重复,或某点无值),需要对该过程所执行的所有操作进行回退。 第4步也是需要重复执行的。本和序用Goto跳转方式实现多次执行。 简单的数独,要么所有的点都具有独一值,第1步执行完成后,就已全部完成。或者具有多个解,随意猜测一个二位数的SY(i, j)的值都能成功。 难的数独,是可唯一确定的点很少,大部分点都有两种或多种可能的值,但最终正确答案只有一种或很少种解。 软件在自动计算过程中,具有很大的偶然性,对于骨灰级的数独题目在计算过程中,时间短的可能不到1秒就能完成,长的可能要几分钟,需要将各种可能性都测试一遍才有结果。 只要题目正确,多计算几次就能得到答案。 程序只处理有两种可能值的情况,对只存在三种可能值的情况未进一步处理,该情况非常极端了。 软件中包含网上下载的200个数独题目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值