-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8adef7b
commit 88c5cde
Showing
11 changed files
with
252 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
""" | ||
Number utility functions. | ||
""" | ||
|
||
|
||
def decimal_to_binary(decimal_number: int, num_digits: int = 0) -> str: | ||
"""Get the binary representation of a given decimal number `decimal_number` as string.""" | ||
binary_representation = '' | ||
while decimal_number > 0: | ||
binary_representation = str(decimal_number % 2) + binary_representation | ||
decimal_number //= 2 | ||
return binary_representation.rjust(num_digits, '0') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
""" | ||
Problem 51: Prime digit replacements | ||
https://projecteuler.net/problem=51 | ||
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. | ||
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, yielding the family: | ||
56003, 56113, 56333, 56443, 56663, 56773, and 56993. | ||
Consequently 56003, being the first member of this family, | ||
is the smallest prime with this property. | ||
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. | ||
""" | ||
|
||
from typing import Set, Iterable, List, Tuple | ||
|
||
from src.common.primes import get_sorted_n_digit_primes | ||
from src.common.numbers import decimal_to_binary | ||
|
||
|
||
def _get_number_family_primes(number_family: str, primes_set: Set[int]) -> Iterable[int]: | ||
""" | ||
Get all prime numbers for a given number family `number_family`. | ||
For example, for `*3` it will yield `13`, `23`, `43`, `53`, `73`, and `83`. | ||
""" | ||
start_digit = 0 if number_family[0] != '*' else 1 | ||
for i in range(start_digit, 10): | ||
current_number = int(number_family.replace('*', str(i))) | ||
if current_number in primes_set: | ||
yield current_number | ||
|
||
|
||
def _get_number_family(number_str: str, mask: int) -> str: | ||
"""Get the number family for a given number string `number_str` and a mask `mask`.""" | ||
number_family = '' | ||
number_str_len = len(number_str) | ||
for idx, binary_mask in enumerate(decimal_to_binary(mask, number_str_len)): | ||
number_family += number_str[idx] if binary_mask == '0' else '*' | ||
return number_family | ||
|
||
|
||
def _get_number_families(number: int) -> Iterable[str]: | ||
"""Get all number families for a given number `number`.""" | ||
number_str = str(number) | ||
for i in range(1, pow(2, len(number_str))): | ||
yield _get_number_family(number_str, i) | ||
|
||
|
||
def get_target_prime_family(target_prime_family_value: int) -> Tuple[int, str, List[int]]: | ||
"""Get a prime family for a given target value `target_prime_family_value`.""" | ||
number_of_digits = 1 | ||
while True: | ||
print(f'Checking {number_of_digits} digit numbers...') | ||
primes_list = get_sorted_n_digit_primes(number_of_digits) | ||
primes_set = set(primes_list) | ||
checked_prime_families: Set[str] = set() | ||
|
||
for prime_number in primes_list: | ||
for prime_family in _get_number_families(prime_number): | ||
if prime_family not in checked_prime_families: | ||
checked_prime_families.add(prime_family) | ||
prime_family_primes = list(_get_number_family_primes(prime_family, primes_set)) | ||
prime_family_value = len(prime_family_primes) | ||
if prime_family_value == target_prime_family_value: | ||
return prime_family_primes[0], prime_family, prime_family_primes | ||
|
||
number_of_digits += 1 | ||
|
||
|
||
def main() -> None: | ||
"""Main function.""" | ||
target_prime_family_value = 8 | ||
smallest_prime, prime_family, primes = get_target_prime_family(target_prime_family_value) | ||
print(f'The smallest prime which, by replacing part of the number with the same digit, ' \ | ||
f'is part of an {target_prime_family_value} prime value family is {smallest_prime}.') | ||
print(f'The prime family is {prime_family} with the primes {primes}.') | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
""" | ||
Number utility functions. | ||
""" | ||
|
||
import pytest | ||
|
||
|
||
@pytest.mark.parametrize('test_input_decimal_number,expected_result', [ | ||
(1, '1'), | ||
(2, '10'), | ||
(3, '11'), | ||
(4, '100'), | ||
(5, '101'), | ||
(6, '110'), | ||
(7, '111'), | ||
(42, '101010'), | ||
(585, '1001001001'), | ||
]) | ||
def test_decimal_to_binary(test_input_decimal_number, expected_result): | ||
# arrange | ||
from src.common.numbers import decimal_to_binary | ||
|
||
# act | ||
actual_result = decimal_to_binary(test_input_decimal_number) | ||
|
||
# assert | ||
assert actual_result == expected_result | ||
|
||
|
||
def test_decimal_to_binary_with_num_digits(): | ||
# arrange | ||
from src.common.numbers import decimal_to_binary | ||
|
||
# act | ||
actual_result = decimal_to_binary(5, 6) | ||
|
||
# assert | ||
expected_result = '000101' | ||
assert actual_result == expected_result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
""" | ||
Problem 51: Prime digit replacements | ||
https://projecteuler.net/problem=51 | ||
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. | ||
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, yielding the family: | ||
56003, 56113, 56333, 56443, 56663, 56773, and 56993. | ||
Consequently 56003, being the first member of this family, | ||
is the smallest prime with this property. | ||
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. | ||
""" | ||
|
||
import pytest | ||
|
||
|
||
def test_get_number_family_primes(): | ||
""" | ||
Get all prime numbers for a given number family `number_family`. | ||
For example, for `*3` it will yield `13`, `23`, `43`, `53`, `73`, and `83`. | ||
""" | ||
# arrange | ||
from src.p051_prime_digit_replacements import _get_number_family_primes | ||
|
||
primes_set = { | ||
2, 3, 5, 7, | ||
11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, | ||
53, 59, 61, 67, 71, 73, 79, 83, 89, 97, | ||
} | ||
|
||
# act | ||
actual_result_iter = _get_number_family_primes('*3', primes_set) | ||
|
||
# assert | ||
expected_result = {13, 23, 43, 53, 73, 83} | ||
assert set(actual_result_iter) == expected_result | ||
|
||
|
||
@pytest.mark.parametrize('test_input_number_str,test_input_mask,expected_result', [ | ||
('123', 1, '12*'), | ||
('123', 2, '1*3'), | ||
('123', 3, '1**'), | ||
('123', 4, '*23'), | ||
('123', 5, '*2*'), | ||
('123', 6, '**3'), | ||
('123', 7, '***'), | ||
]) | ||
def test_get_number_family(test_input_number_str, test_input_mask, expected_result): | ||
"""Get the number family for a given number string `number_str` and a mask `mask`.""" | ||
# arrange | ||
from src.p051_prime_digit_replacements import _get_number_family | ||
|
||
# act | ||
actual_result = _get_number_family(test_input_number_str, test_input_mask) | ||
|
||
# assert | ||
assert actual_result == expected_result | ||
|
||
|
||
def test_get_number_families(): | ||
"""Get all number families for a given number `number`.""" | ||
# arrange | ||
from src.p051_prime_digit_replacements import _get_number_families | ||
|
||
# act | ||
actual_result_iter = _get_number_families(123) | ||
|
||
# assert | ||
expected_result = { '12*', '1*3', '1**', '*23', '*2*', '**3', '***' } | ||
assert set(actual_result_iter) == expected_result | ||
|
||
|
||
@pytest.mark.parametrize('test_input_target_prime_family_value,expected_result', [ | ||
(6, (13, '*3', [13, 23, 43, 53, 73, 83])), | ||
(7, (56003, '56**3', [56003, 56113, 56333, 56443, 56663, 56773, 56993])), | ||
]) | ||
def test_get_target_prime_family(test_input_target_prime_family_value, expected_result): | ||
"""Get a prime family for a given target value `target_prime_family_value`.""" | ||
# arrange | ||
from src.p051_prime_digit_replacements import get_target_prime_family | ||
|
||
# act | ||
actual_result = get_target_prime_family(test_input_target_prime_family_value) | ||
|
||
# assert | ||
assert actual_result == expected_result |