-
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
0c9e55b
commit b4912b5
Showing
7 changed files
with
197 additions
and
16 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,37 @@ | ||
""" | ||
Number spiral utilities. | ||
21 22 23 24 25 | ||
20 7 8 9 10 | ||
19 6 1 2 11 | ||
18 5 4 3 12 | ||
17 16 15 14 13 | ||
""" | ||
|
||
from typing import Iterable, Tuple | ||
|
||
|
||
def get_spiral_diagonal_values_with_size() -> Iterable[Tuple[int, int]]: | ||
""" | ||
Get the diagonal values of a number spiral. | ||
Return tuples of `(<diagonal_value>, <spiral_size>)`. | ||
""" | ||
value = 1 | ||
current_half_size = 0 | ||
yield value, (2 * current_half_size + 1) | ||
while True: | ||
current_half_size += 1 | ||
for _ in range(4): | ||
value += 2 * current_half_size | ||
yield value, (2 * current_half_size + 1) | ||
|
||
|
||
def get_spiral_diagonal_values_up_to_size(size: int) -> Iterable[int]: | ||
"""Get the diagonal values for a `size` by `size` spiral.""" | ||
if size < 1 or size % 2 == 0: | ||
raise ValueError('The size must be a positive odd number.') | ||
|
||
for current_value, current_size in get_spiral_diagonal_values_with_size(): | ||
if current_size > size: | ||
break | ||
yield current_value |
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,62 @@ | ||
""" | ||
Problem 58: Spiral primes | ||
https://projecteuler.net/problem=58 | ||
Starting with 1 and spiralling anticlockwise in the following way, | ||
a square spiral with side length 7 is formed. | ||
37 36 35 34 33 32 31 | ||
38 17 16 15 14 13 30 | ||
39 18 5 4 3 12 29 | ||
40 19 6 1 2 11 28 | ||
41 20 7 8 9 10 27 | ||
42 21 22 23 24 25 26 | ||
43 44 45 46 47 48 49 | ||
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 | ||
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 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 along both diagonals first falls below 10%? | ||
""" | ||
|
||
from typing import Iterable, Tuple | ||
|
||
from src.common.number_spiral import get_spiral_diagonal_values_with_size | ||
from src.common.primes import is_prime | ||
|
||
|
||
def get_spiral_diagonal_prime_ratios() -> Iterable[Tuple[int, int, int]]: | ||
""" | ||
For increasing number spiral sizes get the ratios of primes along the diagonals. | ||
Returns tuples `(<spiral_size>, <number_of_primes_along_diagonals>, <diagonal_numbers_count>)`. | ||
""" | ||
number_of_primes = 0 | ||
total_number = 0 | ||
for value, size in get_spiral_diagonal_values_with_size(): | ||
total_number += 1 | ||
if value == size * size: | ||
yield size, number_of_primes, total_number | ||
else: | ||
if is_prime(value): | ||
number_of_primes += 1 | ||
|
||
|
||
def main() -> None: | ||
"""Main function.""" | ||
threshold_inverse = 10 | ||
spiral_diagonal_prime_ratios_iter = get_spiral_diagonal_prime_ratios() | ||
next(spiral_diagonal_prime_ratios_iter) | ||
for size, number_of_primes, total_number in spiral_diagonal_prime_ratios_iter: | ||
if number_of_primes * threshold_inverse < total_number: | ||
print(f'The side length of the square spiral for which the ratio of primes ' \ | ||
f'along both diagonals first falls below 10% is {size:,}.') | ||
print(f'This ratio is {number_of_primes:,} / {total_number:,}.') | ||
break | ||
|
||
|
||
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,48 @@ | ||
""" | ||
Number spiral utilities. | ||
21 22 23 24 25 | ||
20 7 8 9 10 | ||
19 6 1 2 11 | ||
18 5 4 3 12 | ||
17 16 15 14 13 | ||
""" | ||
|
||
|
||
def test_get_spiral_diagonal_values_with_size(): | ||
# arrange | ||
from src.common.number_spiral import get_spiral_diagonal_values_with_size | ||
|
||
# act | ||
actual_result_iter = get_spiral_diagonal_values_with_size() | ||
|
||
# assert | ||
expected_result = [ | ||
(1, 1), | ||
(3, 3), | ||
(5, 3), | ||
(7, 3), | ||
(9, 3), | ||
(13, 5), | ||
(17, 5), | ||
(21, 5), | ||
(25, 5), | ||
(31, 7), | ||
(37, 7), | ||
(43, 7), | ||
(49, 7), | ||
] | ||
for expected_value in expected_result: | ||
assert next(actual_result_iter) == expected_value | ||
|
||
|
||
def test_get_spiral_diagonal_values_up_to_size(): | ||
# arrange | ||
from src.common.number_spiral import get_spiral_diagonal_values_up_to_size | ||
|
||
# act | ||
actual_result_iter = get_spiral_diagonal_values_up_to_size(7) | ||
|
||
# assert | ||
expected_result = [1, 3, 5, 7, 9, 13, 17, 21, 25, 31, 37, 43, 49] | ||
assert list(actual_result_iter) == 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 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,42 @@ | ||
""" | ||
Problem 58: Spiral primes | ||
https://projecteuler.net/problem=58 | ||
Starting with 1 and spiralling anticlockwise in the following way, | ||
a square spiral with side length 7 is formed. | ||
37 36 35 34 33 32 31 | ||
38 17 16 15 14 13 30 | ||
39 18 5 4 3 12 29 | ||
40 19 6 1 2 11 28 | ||
41 20 7 8 9 10 27 | ||
42 21 22 23 24 25 26 | ||
43 44 45 46 47 48 49 | ||
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 | ||
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 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 along both diagonals first falls below 10%? | ||
""" | ||
|
||
|
||
def test_get_spiral_diagonal_prime_ratios(): | ||
# arrange | ||
from src.p058_spiral_primes import get_spiral_diagonal_prime_ratios | ||
|
||
# act | ||
actual_result_iter = get_spiral_diagonal_prime_ratios() | ||
|
||
# assert | ||
expected_result = [ | ||
(1, 0, 1), | ||
(3, 3, 5), | ||
(5, 5, 9), | ||
(7, 8, 13), | ||
] | ||
for expected_value in expected_result: | ||
assert next(actual_result_iter) == expected_value |