找出Android锁定模式


26

假设您看到您的朋友在他们的Android手机中输入了他或她的密码。您不记得他们是如何制作图案的,但是您仍然记得图案的外观。作为您关心的朋友,您想知道他们的密码有多安全。您的工作是计算形成特定图案的所有方式。

Android模式如何运作

模式是在3x3的节点网格上绘制的。在一种模式中,无需访问屏幕即可访问一系列节点。他们访问的每个节点都通过一条边连接到前一个节点。要记住两个规则。

  • 您最多只能访问一个节点

  • 边缘可能无法通过未访问的节点

请注意,尽管通常很难执行,因此在实际的android锁组合中并不常见,但可以像Knight一样移动。即,可以从一侧移动到不相邻的拐角处或以另一种方式移动。这是采用此举的两种模式示例:

这是正在执行的动画Gif

解决模式

典型的模式可能如下所示:

对于这种简单的模式,有两种方法可以绘制两种模式。您可以从两个松散的一端开始,然后穿过突出显示的节点到达另一个节点。尽管对于许多模式而言都是如此,但对于人类通常采用的模式而言,并非对所有模式都如此。

考虑以下模式:

有两种立即可识别的解决方案。从左上方开始的一个:

还有一个从底部中心开始:

但是,因为一旦选择了一条线,就允许它通过一个点,因此从顶部中间开始有一个附加的花样:

这个特定的模式有3个解决方案,但是模式可以有1到4个解决方案之间的任何位置[需要引用]

以下是每个示例的一些示例:

1。

2。

3。

4。

输入输出

节点可以表示为零到九之间的整数,它们的等效字符串或a到i(或A到I)的字符。每个节点必须具有这些集合之一中的唯一表示。

解决方案将由包含节点表示形式的有序容器表示。节点的顺序必须与传递顺序相同。

模式将由节点对的无序容器表示。每对代表一条开始连接该对中两个点的边。模式表示不是唯一的。

您将通过标准输入方法将模式表示作为输入,并通过标准输出方法输出创建相同模式的所有可能解决方案。

您可以假设每个输入将至少具有一个解决方案,并将连接至少4个节点。

如果您愿意或被语言选择所迫,则可以选择使用有序容器代替无序容器。

测试用例

节点按以下模式排列:

0 1 2
3 4 5
6 7 8

让我们{...}成为一个无序的容器,[...]成为一个有序的容器,然后(...)成为一对。

以下输入和输出应匹配

{(1,4),(3,5),(5,8)} -> {[1,4,3,5,8]}
{(1,4),(3,4),(5,4),(8,5)} -> {[1,4,3,5,8]}
{(0,4),(4,5),(5,8),(7,8)} -> {[0,4,5,8,7],[7,8,5,4,0]}
{(0,2),(2,4),(4,7)} -> {[0,1,2,4,7],[1,0,2,4,7],[7,4,2,1,0]}
{(0,2),(2,6),(6,8)} -> {[0,1,2,4,6,7,8],[1,0,2,4,6,7,8],[8,7,6,4,2,1,0],[7,8,6,4,2,1,0]}
{(2,3),(3,7),(7,8)} -> {[2,3,7,8],[8,7,3,2]}
{(0,7),(1,2),(1,4),(2,7)} -> {[0,7,2,1,4],[4,1,2,7,0]}
{(0,4),(0,7),(1,3),(2,6),(2,8),(3,4),(5,7)} -> {[1,3,4,0,7,5,8,2,6]}
{(1,3),(5,8)} -> {}

可以在此处找到所有测试用例的imgur相册作为图片。模式以红色显示在蓝色解决方案中。

计分

这是代码高尔夫。最少的字节数获胜。


1
好问题,我经常在私人场合也想知道。:)
ThreeFx

您会在脑中回答这个问题吗?现在这将令人印象深刻。:P
DJMcMayhem

哪一种模式只能用一种方法解决?我想您只需轻轻地反转箭头就至少有2个。
ThreeFx

@DJMcMayhem我会尽力而为,但我无法做出任何承诺
Wheat Wizard

@ThreeFx尝试一个自己。因为您不能在已经访问过的节点处停止,但是可以通过一种模式,所以可以将其设为定向。
小麦巫师

Answers:


3

Python 2.7、493430字节

exec("L=['012','345','678','036','147','258','048','246'];L+=[i[::-1]IL];S=sorted;F=lambda t:''.join(str(i)It)\ndef N(x):\n s=' '.join(F(S(i))Ix)\nIL:s=s.replace(i[::2],i[:2]+' '+i[1:])\n return S(set(s.split()))\ndef P(s):\n e=0\nIL:e|=-1<s.find(i[::2])<s.find(i[1])\n return[zip(s[:-1],s[1:]),L][e]\nx=N(input());print[F(i)I__import__('itertools').permutations({iI`x`if i.isdigit()})if x==N(P(F(i)))]".replace('I',' for i in '))

单行版本用该程序包装程序,exec("...".replace('I',' for i in '))以便所有for循环和生成器都可以通过一个短路,I并在此可读性更高的版本上节省15个字节:

L=['012','345','678','036','147','258','048','246'];L+=[i[::-1]for i in L]
S=sorted;F=lambda t:''.join(str(i)for i in t)
def N(x):
 s=' '.join(F(S(i))for i in x)
 for i in L:s=s.replace(i[::2],i[:2]+' '+i[1:])
 return S(set(s.split()))
def P(s):
 e=0
 for i in L:e|=-1<s.find(i[::2])<s.find(i[1])
 return[zip(s[:-1],s[1:]),L][e]
x=N(input())
print[F(i)for i in __import__('itertools').permutations({i for i in`x`if i.isdigit()})if x==N(P(F(i)))]

程序以所示方式(例如{(1,4),(3,4),(5,4),(8,5)})或字符串列表(例如['14','34','54','85'])(或其他python友好格式)获取输入,并以字符串列表形式返回输出。因此,从技术上讲,我们有一个订购容器的订购容器。

该函数N对模式进行归一化,以便可以轻松比较两个模式。归一化对表示边缘的对进行排序(因此'02'而不是'20'),使用字符串替换来扩展双边缘(例如,'02'变为'01 12'),将边缘分成一组以删除重复项,并对结果进行排序。

该函数F将整数/字符串的元组平整为字符串,因此我们可以规范化以不同方式生成的路径。

该列表L包含屏幕上的所有行。

然后,我们对归一化模式中所有数字的每个排列进行计算,并计算出有效路径或L无效路径(它从未像实际路径那样归一化为对的列表),或指示有效的访问顺序节点的对的列表。如果这归一化为相同的模式,那么我们有一个有效的解决方案,并将其包括在最终列表中。

验证排列是否为字符串所需的主要检查s-1<s.find(i[::2])<s.find(i[1])检测行错误i。例如,在该行中'210',代码检测到是否'20'发生错误(即,其索引大于-1)并'1'在此之后发生。我们不必担心1不会出现,因为1不在输入中时会以规范化模式显示。


注:我知道更换 str(i)for i in t map(str,t) {i for i in`x`if i.isdigit()} set('012345678')&set(`x`) 将使原有的代码短,但是这仍然会稍长即代 I


2
False可能是,1<0并且在处有一个无用的空格F(i) for。+1。
Yytsi's

@TuukkaX谢谢,我的脸,当我看到我离开伪称False英寸
莱纳斯

['012','345','678','036','147','258','048','246']可以'012 345 678 036 147 258 048 246'.split()'为-1个字节。
Xcoder先生18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.