diff --git a/python/e057.py b/python/e057.py index 0e834fc..df0e6e2 100644 --- a/python/e057.py +++ b/python/e057.py @@ -1,8 +1,31 @@ +from lib_misc import gcd +from lib_misc import get_digit_count + + +def add_fractions(n1, d1, n2, d2): + d = d1 * d2 + n1 = n1 * (d // d1) + n2 = n2 * (d // d2) + n = n1 + n2 + p = gcd(n, d) + return (n // p, d // p) + + +def next_expension(n, d): + n, d = add_fractions(1, 1, n, d) + return add_fractions(1, 1, d, n) + def euler_057(): - return 0 + c = 0 + n, d = (3, 2) + for i in range(1000): + if get_digit_count(n) > get_digit_count(d): + c += 1 + n, d = next_expension(n, d) + return c if __name__ == "__main__": print("e057.py: " + str(euler_057())) - assert(euler_057() == 0) + assert(euler_057() == 153) diff --git a/python/e058.py b/python/e058.py index 243ff51..bad1118 100644 --- a/python/e058.py +++ b/python/e058.py @@ -1,8 +1,33 @@ +from lib_prime import is_prime + + +def get_corner_values(side_length): + def get_last_corner_value(side_length): + return side_length * side_length + + if side_length == 1: + return [1] + return [get_last_corner_value(side_length) - i * (side_length - 1) + for i in range(0, 4)][::-1] + def euler_058(): - return 0 + n = 1 + count_primes = 0 + count_total = 0 + while True: + for v in get_corner_values(n): + count_total += 1 + if is_prime(v): + count_primes += 1 + ratio = count_primes / count_total + if ratio != 0 and ratio < 0.10: + # print("n: {} count_total: {} count_primes: {} ratio: {}" + # .format(n, count_total, count_primes, ratio)) + return n + n += 2 if __name__ == "__main__": print("e058.py: " + str(euler_058())) - assert(euler_058() == 0) + assert(euler_058() == 26241) diff --git a/python/e059.py b/python/e059.py index c7c3f12..a6ec244 100644 --- a/python/e059.py +++ b/python/e059.py @@ -1,8 +1,61 @@ +def get_encrypted_msg(): + with open("../txt/EulerProblem059.txt", "r") as f: + msg = [int(d) for d in f.read().split(',')] + return msg + + +def get_words(): + with open("../txt/EulerProblem042.txt", "r") as f: + words = [w.strip('"') for w in f.read().split(",")] + return set(words) + + +def generate_keys(): + alphabet = list(map(chr, range(97, 123))) + return [(ord(a), ord(b), ord(c)) + for a in alphabet + for b in alphabet + for c in alphabet] + + +def to_string(msg): + return "".join(map(chr, msg)) + + +def to_ascii(msg): + return list(map(ord, msg)) + + +def decrypt_msg(key, msg): + return [d ^ key[i % len(key)] for i, d in enumerate(msg)] + + +def clean_word(word): + return word.strip('').strip(",").strip(".").strip("!").strip("?").upper() + + +def test_key(key, msg, word_list): + msg = to_string(decrypt_msg(key, msg)) + word_count = 0 + words = msg.split(" ") + for word in words: + if clean_word(word) in word_list: + word_count += 1 + return word_count / len(words) + + def euler_059(): - return 0 + msg = get_encrypted_msg() + word_list = get_words() + keys = generate_keys() + ss = [(test_key(key, msg, word_list), key) for key in keys] + s = sorted(ss, reverse=True)[0] + key = s[1] + s = sum(decrypt_msg(key, msg)) + return s if __name__ == "__main__": print("e059.py: " + str(euler_059())) - assert(euler_059() == 0) + assert(euler_059() == 107359) diff --git a/python/e060.py b/python/e060.py index 8f41242..fa07e2e 100644 --- a/python/e060.py +++ b/python/e060.py @@ -1,8 +1,55 @@ +from itertools import combinations +from lib_prime import primes, is_prime + + +def concatenate_all(numbers): + result = [] + for a, b in combinations(numbers, 2): + result.append([a, b]) + result.append([b, a]) + return result + + +def concatentation_is_prime(a, b): + ab = int(str(a) + str(b)) + ba = int(str(b) + str(a)) + if is_prime(ab) and is_prime(ba): + return True + else: + return False + def euler_060(): - return 0 + """ Hahaha. I have no idea what I was thinking + when writing this code. Beautiful! """ + potentials = [] + new_potentials = [] + done = False + for p in primes(100000): + if done: + break + potentials += new_potentials + new_potentials = [] + for potential in potentials: + all_concatenations_prime = True + for prime in potential: + if not concatentation_is_prime(p, prime): + all_concatenations_prime = False + break + if all_concatenations_prime: + new_potential = list(potential) + new_potential.append(p) + if len(new_potential) > 4: + # print(new_potential) + s = sum(new_potential) + done = True + break + new_potentials.append(new_potential) + if p < 15: + potentials.append([p]) + return s if __name__ == "__main__": print("e060.py: " + str(euler_060())) - assert(euler_060() == 0) + assert(euler_060() == 26033) diff --git a/python/e061.py b/python/e061.py index 0907f9d..5a7e495 100644 --- a/python/e061.py +++ b/python/e061.py @@ -1,8 +1,59 @@ +def get_four_digit_numbers(function): + r = [] + n = 1 + f = function + while f(n) < 10000: + if f(n) > 999: + r.append(f(n)) + n += 1 + return r + + +def search_solution(aggregator, polygonals): + if not polygonals: + if is_cyclic(aggregator[-1], aggregator[0]): + return aggregator + else: + return [] + + if not aggregator: + for polygonal in polygonals: + for number in polygonal: + aggregator.append(number) + s = search_solution( + aggregator, [p for p in polygonals if p != polygonal]) + if s: + return s + aggregator.pop() + + for polygonal in polygonals: + for number in polygonal: + if is_cyclic(aggregator[-1], number) and number not in aggregator: + aggregator.append(number) + s = search_solution( + aggregator, [p for p in polygonals if p != polygonal]) + if s: + return s + aggregator.pop() + return [] + + +def is_cyclic(a, b): + return str(a)[-2:] == str(b)[:2] + def euler_061(): - return 0 + triangles = get_four_digit_numbers(lambda n: n * (n + 1) // 2) + squares = get_four_digit_numbers(lambda n: n**2) + pentas = get_four_digit_numbers(lambda n: n * (3 * n - 1) // 2) + hexas = get_four_digit_numbers(lambda n: n * (2 * n - 1)) + heptas = get_four_digit_numbers(lambda n: n * (5 * n - 3) // 2) + octas = get_four_digit_numbers(lambda n: n * (3 * n - 2)) + s = search_solution([], [triangles, squares, pentas, hexas, heptas, octas]) + s = sum(s) + return s if __name__ == "__main__": print("e061.py: " + str(euler_061())) - assert(euler_061() == 0) + assert(euler_061() == 28684) diff --git a/python/e062.py b/python/e062.py index 5fe0d8e..0abc17c 100644 --- a/python/e062.py +++ b/python/e062.py @@ -1,8 +1,20 @@ def euler_062(): - return 0 + solutions = {} + for n in range(1, 10000): + cube = n * n * n + try: + key = "".join(sorted(str(cube))) + solutions[key].append(cube) + if len(solutions[key]) > 4: + # print(solutions[key]) + s = solutions[key][0] + break + except KeyError: + solutions[key] = [cube] + return s if __name__ == "__main__": print("e062.py: " + str(euler_062())) - assert(euler_062() == 0) + assert(euler_062() == 127035954683) diff --git a/python/e063.py b/python/e063.py index b466e87..e82b2d1 100644 --- a/python/e063.py +++ b/python/e063.py @@ -1,8 +1,22 @@ +from lib_misc import get_digit_count + + +def get_n_digit_positive_integers(n): + r = [] + i = 1 + while True: + if get_digit_count(i ** n) == n: + r.append(i ** n) + if get_digit_count(i ** n) > n: + return r + i += 1 + def euler_063(): - return 0 + s = sum([len(get_n_digit_positive_integers(n)) for n in range(1, 1000)]) + return s if __name__ == "__main__": print("e063.py: " + str(euler_063())) - assert(euler_063() == 0) + assert(euler_063() == 49) diff --git a/python/e064.py b/python/e064.py index c2d28af..4e6da06 100644 --- a/python/e064.py +++ b/python/e064.py @@ -1,8 +1,69 @@ +import math + + +def get_floor_sqrt(n): + return math.floor(math.sqrt(n)) + + +def next_expansion(current_a, current_nominator, + current_denominator, original_number): + # Less typing + cn = current_nominator + cd = current_denominator + + # Step 1: Multiply the fraction so that we can use the third binomial + # formula. Make sure we can reduce the nominator. + assert((original_number - cd * cd) % cn == 0) + # The new nominator is the denominator since we multiply with (x + cd) and + # then reduce the previous nominator. The new denominator is calculated by + # applying the third binomial formula and then by divided by the previous + # nominator. + cn, cd = cd, (original_number - cd * cd) // cn + + # Step 2: Calculate the next a by finding the next floor square root. + next_a = math.floor((math.sqrt(original_number) + cn) // cd) + + # Step 3: Remove next a from the fraction by substracting it. + cn = cn - next_a * cd + cn *= -1 + + return next_a, cn, cd + + +def get_continued_fraction_sequence(n): + + # If number is a square number we return it. + floor_sqrt = get_floor_sqrt(n) + if n == floor_sqrt * floor_sqrt: + return ((floor_sqrt), []) + + # Otherwise, we calculate the next expansion till we + # encounter a step a second time. + a = floor_sqrt + cn = a + cd = 1 + sequence = [] + previous_steps = [] + + while not (a, cn, cd) in previous_steps: + # print("a: {} cn: {} cd: {}".format(a, cn, cd)) + previous_steps.append((a, cn, cd)) + a, cn, cd = next_expansion(a, cd, cn, n) + sequence.append(a) + sequence.pop() + return ((floor_sqrt), sequence) + + +def get_period(n): + _, sequence = get_continued_fraction_sequence(n) + return len(sequence) + def euler_064(): - return 0 + s = len([n for n in range(1, 10001) if get_period(n) % 2 != 0]) + return s if __name__ == "__main__": print("e064.py: " + str(euler_064())) - assert(euler_064() == 0) + assert(euler_064() == 1322) diff --git a/python/e065.py b/python/e065.py index 25fd749..b445959 100644 --- a/python/e065.py +++ b/python/e065.py @@ -1,8 +1,21 @@ +from e057 import add_fractions + + +def next_expansion(previous_numerator, previous_denumerator, value): + if previous_numerator == 0: + return (value, 1) + return add_fractions(previous_denumerator, previous_numerator, value, 1) + def euler_065(): - return 0 + e_sequence = [2] + [n for i in range(2, 1000, 2) for n in (1, i, 1)] + n, d = 0, 1 + for i in range(100, 0, -1): + n, d = next_expansion(n, d, e_sequence[i - 1]) + s = sum([int(l) for l in str(n)]) + return s if __name__ == "__main__": print("e065.py: " + str(euler_065())) - assert(euler_065() == 0) + assert(euler_065() == 272) diff --git a/python/e066.py b/python/e066.py index 8b3dd50..a691171 100644 --- a/python/e066.py +++ b/python/e066.py @@ -1,8 +1,97 @@ +import math +from e057 import add_fractions + + +def get_floor_sqrt(n): + return math.floor(math.sqrt(n)) + + +def next_expansion_1(current_a, current_nominator, + current_denominator, original_number): + cn = current_nominator + cd = current_denominator + cn, cd = cd, (original_number - cd * cd) // cn + next_a = math.floor((math.sqrt(original_number) + cn) // cd) + cn = cn - next_a * cd + cn *= -1 + + return next_a, cn, cd + + +def get_continued_fraction_sequence(n): + + # If number is a square number we return it. + floor_sqrt = get_floor_sqrt(n) + if n == floor_sqrt * floor_sqrt: + return ((floor_sqrt), []) + + # Otherwise, we calculate the next expansion till we + # encounter a step a second time. + a = floor_sqrt + cn = a + cd = 1 + sequence = [] + previous_steps = [] + + while not (a, cn, cd) in previous_steps: + # print("a: {} cn: {} cd: {}".format(a, cn, cd)) + previous_steps.append((a, cn, cd)) + a, cn, cd = next_expansion_1(a, cd, cn, n) + sequence.append(a) + sequence.pop() + return ((floor_sqrt), sequence) + + +def next_expansion_2(previous_numerator, previous_denumerator, value): + if previous_numerator == 0: + return (value, 1) + return add_fractions(previous_denumerator, previous_numerator, value, 1) + + +def get_fractions(n, x): + # print("get_fractions(n={}, x={})".format(n, x)) + # Get sequence of a_x + first_value, sequence = get_continued_fraction_sequence(n) + sequence = [first_value] + math.ceil(x / len(sequence)) * sequence + sequence = sequence[:x + 1] + sequence = sequence[::-1] + + n, d = 0, 1 + for s in sequence: + n, d = next_expansion_2(n, d, s) + return (n, d) + + +def get_minimal_solution(d): + for i in range(0, 100): + x, y = get_fractions(d, i) + if x * x - d * y * y == 1: + return((x, y)) + + +def is_square(n): + return math.sqrt(n).is_integer() + def euler_066(): - return 0 + # XXX: This seems really long and complicated. We can do better. + x_max = 0 + d_max = 0 + + for d in range(2, 1001): + if is_square(d): + continue + + x, y = get_minimal_solution(d) + if x > x_max: + x_max = x + d_max = d + + print("d: {} x: {}".format(d_max, x_max)) + s = d_max + return s if __name__ == "__main__": print("e066.py: " + str(euler_066())) - assert(euler_066() == 0) + assert(euler_066() == 661) diff --git a/python/e068.py b/python/e068.py index 660c15c..75bf6a1 100644 --- a/python/e068.py +++ b/python/e068.py @@ -1,5 +1,5 @@ - def euler_068(): + # XXX: continue here return 0 diff --git a/python/lib_misc.py b/python/lib_misc.py index dd81b27..7b2ccbe 100644 --- a/python/lib_misc.py +++ b/python/lib_misc.py @@ -196,7 +196,13 @@ def permutations(iterable): def gcd(a, b): - """ Returns the greatest commond divisor of a and b. """ - if b == 0: - return a - return gcd(b, a % b) + while a % b != 0: + a, b = b, a % b + return b + + +def get_digit_count(n): + """ + Returns the number of digits for n. + """ + return len(str(n)) diff --git a/python/lib_misc_tests.py b/python/lib_misc_tests.py index 34c2723..8e16e97 100644 --- a/python/lib_misc_tests.py +++ b/python/lib_misc_tests.py @@ -13,6 +13,7 @@ try: from .lib_misc import proper_divisors, sum_proper_divisors from .lib_misc import permutations from .lib_misc import gcd + from .lib_misc import get_digit_count except ModuleNotFoundError: from lib_misc import is_palindrome_integer from lib_misc import is_palindrome_string @@ -27,6 +28,7 @@ except ModuleNotFoundError: from lib_misc import proper_divisors, sum_proper_divisors from lib_misc import permutations from lib_misc import gcd + from lib_misc import get_digit_count class TestPrimeMethods(unittest.TestCase): @@ -131,6 +133,10 @@ class TestPrimeMethods(unittest.TestCase): self.assertEqual(gcd(15, 6), 3) self.assertEqual(gcd(6, 15), 3) + def test_get_digit_count(self): + self.assertEqual(get_digit_count(1), 1) + self.assertEqual(get_digit_count(1234567890), 10) + if __name__ == '__main__': unittest.main()