Skip to content

Add Project Euler problem 79 solution 1 #8607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 2, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
50 changes: 50 additions & 0 deletions project_euler/problem_079/keylog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
319
680
180
690
129
620
762
689
762
318
368
710
720
710
629
168
160
689
716
731
736
729
316
729
729
710
769
290
719
680
318
389
162
289
162
718
729
319
790
680
890
362
319
760
316
729
380
319
728
716
72 changes: 72 additions & 0 deletions project_euler/problem_079/sol1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
Project Euler Problem 79: https://projecteuler.net/problem=79

Passcode derivation

A common security method used for online banking is to ask the user for three
random characters from a passcode. For example, if the passcode was 531278,
they may ask for the 2nd, 3rd, and 5th characters; the expected reply would
be: 317.

The text file, keylog.txt, contains fifty successful login attempts.

Given that the three characters are always asked for in order, analyse the file
so as to determine the shortest possible secret passcode of unknown length.
"""
import itertools
import os


def find_secret_passcode(logins: list[str]) -> int:
"""
Returns the shortest possible secret passcode of unknown length.

>>> find_secret_passcode(["319", "680", "180", "690", "129", "620", "698",
... "318", "328", "310", "320", "610", "629", "198", "190", "631"])
6312980

>>> find_secret_passcode(["135", "259", "235", "189", "690", "168", "120",
... "136", "289", "589", "160", "165", "580", "369", "250", "280"])
12365890

>>> find_secret_passcode(["426", "281", "061", "819" "268", "406", "420",
... "428", "209", "689", "019", "421", "469", "261", "681", "201"])
4206819
"""

# Split each login by character e.g. '319' -> ('3', '1', '9')
split_logins = [tuple(login) for login in logins]

unique_chars = {char for login in split_logins for char in login}

for permutation in itertools.permutations(unique_chars):
satisfied = True
for login in logins:
if not (
permutation.index(login[0])
< permutation.index(login[1])
< permutation.index(login[2])
):
satisfied = False
break

if satisfied:
return int("".join(permutation))
break

raise Exception("Unable to find the secret passcode")


def solution() -> int:
"""
Returns the shortest possible secret passcode of unknown length
for successful login attempts given by keylog.txt.
"""
with open(os.path.dirname(__file__) + "/keylog.txt") as file:
logins = file.read().splitlines()

return find_secret_passcode(logins)


if __name__ == "__main__":
print(f"{solution() = }")