[英]Using combinatorics in Python to list 4-digit passcodes
我偶然发现了这篇有趣的文章,说明为什么使用3个唯一数字来表示4位数密码是最安全的: (LINK)
所涉及的数学非常简单 - 如果您必须根据屏幕上留下的污迹猜测手机的4位数密码,那么:
4个污迹表示密码中有4个唯一编号。 由于它们每个必须至少使用一次,那么我们有4! = 24
4! = 24
可能的密码。
通过3个不同的数字,密码变得更加安全。 由于有三个污迹,一个数字重复 - 但我们不知道哪一个。 因此,考虑到多重性,我们得到(4!/2!) x 3 = 36
可能的密码。
同样,有2个不同的数字,我们得到14个可能的密码。
我的问题是,有什么方法可以在Python中“证明”上述内容吗? 一种证明这3个数字的方法可以提供最安全的密码,使用Python代码,如果给它一些数字,可能会列出所有可能的密码? 我正在考虑使用itertools
,以itertools.permutations
为起点,但后来我发现Python有一个组合模块,这可能是一种更优雅的方式。 有人会善意地告诉我如何使用它吗? 我正在阅读文档,但有些语法正在逃避我。
标准发行版中没有combinatorics
模块,但无论如何都很容易做到。 例如,
def guess(smudged_numbers):
from itertools import product
num_smudges = len(smudged_numbers)
for raw in product(smudged_numbers, repeat=4):
if len(set(raw)) == num_smudges:
yield raw
count = 0
for nums in guess([1, 8]):
print nums
count += 1
print "total", count
打印:
(1, 1, 1, 8)
(1, 1, 8, 1)
(1, 1, 8, 8)
(1, 8, 1, 1)
(1, 8, 1, 8)
(1, 8, 8, 1)
(1, 8, 8, 8)
(8, 1, 1, 1)
(8, 1, 1, 8)
(8, 1, 8, 1)
(8, 1, 8, 8)
(8, 8, 1, 1)
(8, 8, 1, 8)
(8, 8, 8, 1)
total 14
搜索空间非常小( len(num_smudges)**4
,最多4 ** 4 = 256),所以没有任何意义做任何发烧友;-)
工作原理:它生成所有可能的( product
)4元组( repeat=4
),其中包含传递的污迹数字序列。 因此对于[1, 8]
,它生成所有2 ** 4 = len(smudged_numbers)**4
= 16个元组的16种可能性除了1和8之外什么都没有。
将原始可能性转换为set
然后告诉我们在原始4元组中出现了多少( len
)个不同的数字。 我们只想要包含所有污迹数字的那些。 这里的所有都是它的。 在[1, 8]
情况下,这一步只能清除16个原始4元组中的2个: (1, 1, 1, 1)
1,1,1,1 (1, 1, 1, 1)
和(8, 8, 8, 8)
。
我尝试使用itertools
模块中的permutations
方法。
我已经从random
模块中添加了shuffle
方法,以便从正常的破解程序生成更多随机尝试。 (为了试试你的运气你永远不会连续去?)但是,如果你想要串行尝试方法,你可以删除shuffle(codes_to_try)
行。
from itertools import combinations, permutations
from random import randint, shuffle
def crack_the_code(smudges, actual_code):
""" Takes a list of digit strings (smudges) & generates all possible
permutations of it (4 digits long). It then compares the actual given
code & returns the index of it in the generated list, which basically
becomes the number of tries.
"""
attempts_to_crack = 0
no_smudges = len(smudges)
if no_smudges == 3:
all_codes = ["".join(digits)
for repeated_num in smudges
for digits in permutations([repeated_num]+smudges)
]
all_codes = list(set(all_codes)) # remove duplicates
elif no_smudges == 4:
all_codes = ["".join(digits)
for digits in permutations(smudges)
]
else:
print "Smudges aren't 3 or 4"
raise ValueError
shuffle(all_codes)
return all_codes.index(actual_code)
print crack_the_code(["1","2","3"],"1232")
# above prints random values between 0 & 35 inclusive.
注意 - 如果你喜欢int
&not str
你可以使用该函数。 PS - 我保持代码不言自明,但你总是可以评论并问一些你不理解的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.