Fix problem number

This commit is contained in:
David Doblas Jiménez 2021-10-30 18:56:42 +02:00
parent a311ea75f8
commit 7190721c5f
10 changed files with 163 additions and 88 deletions

View File

@ -15,34 +15,45 @@ from utils import timeit, list_primes, is_prime
@timeit("Problem 51") @timeit("Problem 51")
def compute(): def compute():
""" """
By replacing the 1st digit of the 2-digit number *3, it turns out that By replacing the 1st digit of the 2-digit number *3, it turns out that
six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime. six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.
By replacing the 3rd and 4th digits of 56**3 with the same digit, this 5-digit By replacing the 3rd and 4th digits of 56**3 with the same digit, this 5-digit
number is the first example having seven primes among the ten generated numbers, number is the first example having seven primes among the ten generated numbers,
yielding the family: yielding the family:
56003, 56113, 56333, 56443, 56663, 56773, and 56993. 56003, 56113, 56333, 56443, 56663, 56773, and 56993.
Consequently 56003, being the first member of this family, is the smallest prime Consequently 56003, being the first member of this family, is the smallest prime
with this property. with this property.
Find the smallest prime which, by replacing part of the number (not necessarily Find the smallest prime which, by replacing part of the number (not necessarily
adjacent digits) with the same digit, is part of an eight prime value family. adjacent digits) with the same digit, is part of an eight prime value family.
""" """
primes = sorted(set(list_primes(1_000_000)) - set(list_primes(57_000))) primes = sorted(set(list_primes(1_000_000)) - set(list_primes(57_000)))
digits = {'0':[], '1':[], '2':[],'3':[], '4':[], '5':[],'6':[], '7':[], '8':[], '9':[]} digits = {
"0": [],
"1": [],
"2": [],
"3": [],
"4": [],
"5": [],
"6": [],
"7": [],
"8": [],
"9": [],
}
for d in digits.keys(): for d in digits.keys():
for p in primes: for p in primes:
p = str(p) p = str(p)
if p.count(d) == 3 and p[-1] != d: if p.count(d) == 3 and p[-1] != d:
digits[d].append(p) digits[d].append(p)
for d in {'0', '1', '2'}: for d in {"0", "1", "2"}:
for p in digits[d]: for p in digits[d]:
res = 0 res = 0
i = 10 i = 10
for D in {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}-{d}: for D in {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} - {d}:
i -= 1 i -= 1
q = int(p.replace(d, D)) q = int(p.replace(d, D))
if is_prime(q) and q > 57_000: if is_prime(q) and q > 57_000:
@ -55,4 +66,4 @@ def compute():
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(51):003d}: {compute()}") print(f"Result for Problem 51: {compute()}")

View File

@ -15,22 +15,25 @@ from utils import timeit
@timeit("Problem 52") @timeit("Problem 52")
def compute(): def compute():
""" """
It can be seen that the number, 125874, and its double, 251748, It can be seen that the number, 125874, and its double, 251748,
contain exactly the same digits, but in a different order. contain exactly the same digits, but in a different order.
Find the smallest positive integer, x, such that 2x, 3x, 4x, 5x, Find the smallest positive integer, x, such that 2x, 3x, 4x, 5x,
and 6x, contain the same digits. and 6x, contain the same digits.
""" """
for number in range(123456, 1_000_000): for number in range(123456, 1_000_000):
if sorted(str(number)) \ if (
== sorted(str(2*number)) \ sorted(str(number))
== sorted(str(3*number)) \ == sorted(str(2 * number))
== sorted(str(4*number)) \ == sorted(str(3 * number))
== sorted(str(5*number)) == sorted(str(6*number)): == sorted(str(4 * number))
== sorted(str(5 * number))
== sorted(str(6 * number))
):
return number return number
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(52):003d}: {compute()}") print(f"Result for Problem 52: {compute()}")

View File

@ -27,7 +27,7 @@ def compute():
It is not until It is not until
, that a value exceeds one-million: (23 over 10) = 1144066. , that a value exceeds one-million: (23 over 10) = 1144066.
How many, not necessarily distinct, values of (n over r) for 1<=n<=100, are greater than one-million? How many, not necessarily distinct, values of (n over r) for 1<=n<=100, are greater than one-million?
""" """
ans = 0 ans = 0
@ -41,4 +41,4 @@ def compute():
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(53):003d}: {compute()}") print(f"Result for Problem 53: {compute()}")

View File

@ -16,7 +16,7 @@ from utils import timeit
@timeit("Problem 54") @timeit("Problem 54")
def compute(): def compute():
""" """
In the card game poker, a hand consists of five cards and are ranked, In the card game poker, a hand consists of five cards and are ranked,
from lowest to highest, in the following way: from lowest to highest, in the following way:
High Card: Highest value card. High Card: Highest value card.
@ -34,11 +34,11 @@ def compute():
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace. 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.
If two players have the same ranked hands then the rank made up of the If two players have the same ranked hands then the rank made up of the
highest value wins; for example, a pair of eights beats a pair of fives highest value wins; for example, a pair of eights beats a pair of fives
(see example 1 below). But if two ranks tie, for example, both players (see example 1 below). But if two ranks tie, for example, both players
have a pair of queens, then highest cards in each hand are compared have a pair of queens, then highest cards in each hand are compared
(see example 4 below); if the highest cards tie then the next highest (see example 4 below); if the highest cards tie then the next highest
cards are compared, and so on. cards are compared, and so on.
Consider the following five hands dealt to two players: Consider the following five hands dealt to two players:
@ -56,12 +56,12 @@ def compute():
5 2H 2D 4C 4D 4S 3C 3D 3S 9S 9D Player 1 5 2H 2D 4C 4D 4S 3C 3D 3S 9S 9D Player 1
Full House Full House Full House Full House
With Three Fours with Three Threes With Three Fours with Three Threes
The file, poker.txt, contains one-thousand random hands dealt to two The file, poker.txt, contains one-thousand random hands dealt to two
players. Each line of the file contains ten cards (separated by a single players. Each line of the file contains ten cards (separated by a single
space): the first five are Player 1's cards and the last five are Player space): the first five are Player 1's cards and the last five are Player
2's cards. You can assume that all hands are valid (no invalid characters 2's cards. You can assume that all hands are valid (no invalid characters
or repeated cards), each player's hand is in no specific order, and in or repeated cards), each player's hand is in no specific order, and in
each hand there is a clear winner. each hand there is a clear winner.
How many hands does Player 1 win? How many hands does Player 1 win?
@ -79,7 +79,6 @@ def compute():
def to_numerical(hand: list) -> list: def to_numerical(hand: list) -> list:
return sorted([int(x[:-1]) for x in hand], reverse=True) return sorted([int(x[:-1]) for x in hand], reverse=True)
# 10 Ranks functions. # 10 Ranks functions.
def high_card(str_hand: list) -> list: def high_card(str_hand: list) -> list:
return to_numerical(str_hand) return to_numerical(str_hand)
@ -87,7 +86,7 @@ def compute():
def one_pair(hand: list) -> int: def one_pair(hand: list) -> int:
return n_of_a_kind(hand, 2) return n_of_a_kind(hand, 2)
def two_pair(hand: list) -> int: def two_pair(hand: list) -> int:
pairs = set([x for x in hand if hand.count(x) == 2]) pairs = set([x for x in hand if hand.count(x) == 2])
return 0 if len(pairs) < 2 else max(pairs) return 0 if len(pairs) < 2 else max(pairs)
@ -95,7 +94,7 @@ def compute():
return n_of_a_kind(hand, 3) return n_of_a_kind(hand, 3)
def straight(hand: list) -> int: def straight(hand: list) -> int:
return 0 if not list(range(hand[0], hand[-1]-1, -1)) == hand else max(hand) return 0 if not list(range(hand[0], hand[-1] - 1, -1)) == hand else max(hand)
def flush(str_hand: list) -> bool: def flush(str_hand: list) -> bool:
return len(set([x[-1] for x in str_hand])) == 1 return len(set([x[-1] for x in str_hand])) == 1
@ -113,7 +112,6 @@ def compute():
def royal_flush(str_hand: list) -> bool: def royal_flush(str_hand: list) -> bool:
return flush(str_hand) and list(range(14, 9, -1)) == to_numerical(str_hand) return flush(str_hand) and list(range(14, 9, -1)) == to_numerical(str_hand)
replace_map = {"T": 10, "J": 11, "Q": 12, "K": 13, "A": 14} replace_map = {"T": 10, "J": 11, "Q": 12, "K": 13, "A": 14}
score = [0, 0] score = [0, 0]
@ -121,10 +119,25 @@ def compute():
for line in open(file, "r").read().splitlines(): for line in open(file, "r").read().splitlines():
line = replace_values_in_string(line, replace_map).split() line = replace_values_in_string(line, replace_map).split()
hands = line[:5], line[5:] hands = line[:5], line[5:]
for rank in (royal_flush, straight_flush, four_of_a_kind, full_house, flush, for rank in (
straight, three_of_a_kind, two_pair, one_pair, high_card): royal_flush,
should_convert_hand = "str" not in rank.__code__.co_varnames[0] # Checks parameter name. straight_flush,
result = [rank(to_numerical(hand) if should_convert_hand else hand) for hand in hands] four_of_a_kind,
full_house,
flush,
straight,
three_of_a_kind,
two_pair,
one_pair,
high_card,
):
should_convert_hand = (
"str" not in rank.__code__.co_varnames[0]
) # Checks parameter name.
result = [
rank(to_numerical(hand) if should_convert_hand else hand)
for hand in hands
]
if result[0] != result[1]: if result[0] != result[1]:
score[0 if result[0] > result[1] else 1] += 1 score[0 if result[0] > result[1] else 1] += 1
break break
@ -134,4 +147,4 @@ def compute():
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(54):003d}: {compute()}") print(f"Result for Problem 54: {compute()}")

View File

@ -31,13 +31,13 @@ def compute():
of these numbers, and for the purpose of this problem, we shall assume that a of these numbers, and for the purpose of this problem, we shall assume that a
number is Lychrel until proven otherwise. In addition you are given that for number is Lychrel until proven otherwise. In addition you are given that for
every number below ten-thousand, it will either: every number below ten-thousand, it will either:
(i) become a palindrome in less than fifty iterations, or, (i) become a palindrome in less than fifty iterations, or,
(ii) no one, with all the computing power that exists, has managed so far to map (ii) no one, with all the computing power that exists, has managed so far to map
it to a palindrome. it to a palindrome.
In fact, 10677 is the first number to be shown to require over fifty iterations In fact, 10677 is the first number to be shown to require over fifty iterations
before producing a palindrome: before producing a palindrome:
4668731596684224866951378664 (53 iterations, 28-digits). 4668731596684224866951378664 (53 iterations, 28-digits).
Surprisingly, there are palindromic numbers that are themselves Lychrel numbers; Surprisingly, there are palindromic numbers that are themselves Lychrel numbers;
@ -57,10 +57,10 @@ def compute():
break break
if is_lychrel: if is_lychrel:
ans += 1 ans += 1
return ans return ans
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(55):003d}: {compute()}") print(f"Result for Problem 55: {compute()}")

View File

@ -15,7 +15,7 @@ from utils import timeit
@timeit("Problem 56") @timeit("Problem 56")
def compute(): def compute():
""" """
A googol (10^100) is a massive number: one followed by one-hundred zeros; A googol (10^100) is a massive number: one followed by one-hundred zeros;
100100 is almost unimaginably large: one followed by two-hundred zeros. 100100 is almost unimaginably large: one followed by two-hundred zeros.
Despite their size, the sum of the digits in each number is only 1. Despite their size, the sum of the digits in each number is only 1.
@ -26,7 +26,7 @@ def compute():
ans = 0 ans = 0
for a in range(100): for a in range(100):
for b in range(100): for b in range(100):
num = sum([int(digit) for digit in str(a**b)]) num = sum([int(digit) for digit in str(a ** b)])
if num > ans: if num > ans:
ans = num ans = num
@ -35,4 +35,4 @@ def compute():
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(56):003d}: {compute()}") print(f"Result for Problem 56: {compute()}")

View File

@ -16,7 +16,7 @@ from utils import timeit
@timeit("Problem 57") @timeit("Problem 57")
def compute(): def compute():
""" """
It is possible to show that the square root of two can be expressed It is possible to show that the square root of two can be expressed
as an infinite continued fraction. as an infinite continued fraction.
By expanding this for the first four iterations, we get: By expanding this for the first four iterations, we get:
@ -26,11 +26,11 @@ def compute():
1 + 1/2+1/2+1/2 = 17/12 = 1.41666... 1 + 1/2+1/2+1/2 = 17/12 = 1.41666...
1 + 1/2+1/2+1/2+1/2 = 41/29 = 1.41379... 1 + 1/2+1/2+1/2+1/2 = 41/29 = 1.41379...
The next three expansions are 99/70, 239/169, and 577/408, but the eighth The next three expansions are 99/70, 239/169, and 577/408, but the eighth
expansion, 1393/985, is the first example where the number of digits in expansion, 1393/985, is the first example where the number of digits in
the numerator exceeds the number of digits in the denominator. the numerator exceeds the number of digits in the denominator.
In the first one-thousand expansions, how many fractions contain a numerator In the first one-thousand expansions, how many fractions contain a numerator
with more digits than the denominator? with more digits than the denominator?
""" """
@ -41,10 +41,10 @@ def compute():
result = 1 + f result = 1 + f
if len(str(result.numerator)) > len(str(result.denominator)): if len(str(result.numerator)) > len(str(result.denominator)):
ans += 1 ans += 1
return ans return ans
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(57):003d}: {compute()}") print(f"Result for Problem 57: {compute()}")

View File

@ -15,7 +15,7 @@ from utils import timeit, is_prime
@timeit("Problem 58") @timeit("Problem 58")
def compute(): def compute():
""" """
Starting with 1 and spiralling anticlockwise in the following way, Starting with 1 and spiralling anticlockwise in the following way,
a square spiral with side length 7 is formed. a square spiral with side length 7 is formed.
37 36 35 34 33 32 31 37 36 35 34 33 32 31
@ -26,13 +26,13 @@ def compute():
42 21 22 23 24 25 26 42 21 22 23 24 25 26
43 44 45 46 47 48 49 43 44 45 46 47 48 49
It is interesting to note that the odd squares lie along the bottom right It is interesting to note that the odd squares lie along the bottom right
diagonal, but what is more interesting is that 8 out of the 13 numbers diagonal, but what is more interesting is that 8 out of the 13 numbers
lying along both diagonals are prime; that is, a ratio of 8/13 62%. lying along both diagonals are prime; that is, a ratio of 8/13 62%.
If one complete new layer is wrapped around the spiral above, a square If one complete new layer is wrapped around the spiral above, a square
spiral with side length 9 will be formed. If this process is continued, spiral with side length 9 will be formed. If this process is continued,
what is the side length of the square spiral for which the ratio of primes what is the side length of the square spiral for which the ratio of primes
along both diagonals first falls below 10%? along both diagonals first falls below 10%?
""" """
@ -53,4 +53,4 @@ def compute():
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(58):003d}: {compute()}") print(f"Result for Problem 58: {compute()}")

View File

@ -17,37 +17,37 @@ from utils import timeit
@timeit("Problem 59") @timeit("Problem 59")
def compute(): def compute():
""" """
Each character on a computer is assigned a unique code and the preferred Each character on a computer is assigned a unique code and the preferred
standard is ASCII (American Standard Code for Information Interchange). standard is ASCII (American Standard Code for Information Interchange).
For example, uppercase A = 65, asterisk (*) = 42, and lowercase k = 107. For example, uppercase A = 65, asterisk (*) = 42, and lowercase k = 107.
A modern encryption method is to take a text file, convert the bytes to A modern encryption method is to take a text file, convert the bytes to
ASCII, then XOR each byte with a given value, taken from a secret key. ASCII, then XOR each byte with a given value, taken from a secret key.
The advantage with the XOR function is that using the same encryption key The advantage with the XOR function is that using the same encryption key
on the cipher text, restores the plain text; for example, 65 XOR 42 = 107, on the cipher text, restores the plain text; for example, 65 XOR 42 = 107,
then 107 XOR 42 = 65. then 107 XOR 42 = 65.
For unbreakable encryption, the key is the same length as the plain text For unbreakable encryption, the key is the same length as the plain text
message, and the key is made up of random bytes. The user would keep the message, and the key is made up of random bytes. The user would keep the
encrypted message and the encryption key in different locations, and encrypted message and the encryption key in different locations, and
without both "halves", it is impossible to decrypt the message. without both "halves", it is impossible to decrypt the message.
Unfortunately, this method is impractical for most users, so the modified Unfortunately, this method is impractical for most users, so the modified
method is to use a password as a key. If the password is shorter than the method is to use a password as a key. If the password is shorter than the
message, which is likely, the key is repeated cyclically throughout the message, which is likely, the key is repeated cyclically throughout the
message. The balance for this method is using a sufficiently long password message. The balance for this method is using a sufficiently long password
key for security, but short enough to be memorable. key for security, but short enough to be memorable.
Your task has been made easy, as the encryption key consists of three Your task has been made easy, as the encryption key consists of three
lower case characters. Using p059_cipher.txt, a file containing the lower case characters. Using p059_cipher.txt, a file containing the
encrypted ASCII codes, and the knowledge that the plain text must contain encrypted ASCII codes, and the knowledge that the plain text must contain
common English words, decrypt the message and find the sum of the ASCII common English words, decrypt the message and find the sum of the ASCII
values in the original text. values in the original text.
""" """
with open('../files/Problem59.txt', 'r') as f: with open("../files/Problem59.txt", "r") as f:
# encrypted = list(map(int, f.read().split(','))) # encrypted = list(map(int, f.read().split(',')))
encrypted = [int(char) for char in f.read().split(',')] encrypted = [int(char) for char in f.read().split(",")]
# print(encrypted) # print(encrypted)
# print(test) # print(test)
plain_text = len(encrypted) // 3 plain_text = len(encrypted) // 3
@ -55,12 +55,12 @@ def compute():
decrypted = "" decrypted = ""
for k, i in zip(list(key) * plain_text, encrypted): for k, i in zip(list(key) * plain_text, encrypted):
decrypted += chr(ord(k) ^ i) decrypted += chr(ord(k) ^ i)
# assuming Euler will be in the text # assuming Euler will be in the text
if 'Euler' in decrypted: if "Euler" in decrypted:
return sum([ord(c) for c in decrypted]) return sum([ord(c) for c in decrypted])
if __name__ == "__main__": if __name__ == "__main__":
print(f"Result for Problem {int(59):003d}: {compute()}") print(f"Result for Problem 59: {compute()}")

View File

@ -0,0 +1,48 @@
import math
from functools import wraps
def timeit(name):
def profile(original):
import time
@wraps(original)
def wrapper(*args, **kwargs):
t0 = time.perf_counter()
result = original(*args, **kwargs)
t1 = time.perf_counter()
print(f"Time to evaluate problem {int(name[7:]):003d}: {(t1 - t0)*1000:.3f} ms\n")
return result
return wrapper
return profile
def is_prime(n):
if n <2:
return False
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0:
return False
return True
# Returns a list of True and False indicating whether each number is prime.
# For 0 <= i <= n, result[i] is True if i is a prime number, False otherwise.
def list_primality(n):
# Sieve of Eratosthenes
result = [True] * (n + 1)
result[0] = result[1] = False
for i in range(int(math.sqrt(n) + 1)):
if result[i]:
for j in range(i * i, len(result), i):
result[j] = False
return result
# Returns all the prime numbers less than or equal to n, in ascending order
# For example: list_primes(97) = [2, 3, 5, 7, 11, ..., 83, 89, 97].
def list_primes(n):
return [i for (i, is_prime) in enumerate(list_primality(n)) if is_prime]
def is_palindrome(num):
return str(num) == str(num)[::-1]