繁体   English   中英

在Python中使用组合学来列出4位数的密码

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM