예제 #1
0
def pandigital_products(digits: Iterable[int]) -> Iterable[int]:
    digits = set(digits)
    digits_count = len(digits)
    multipliers_digits_counts_sum = ceil(digits_count / 2)
    product_multiplier_digits_count = digits_count - multipliers_digits_counts_sum
    max_left_multipliers_digits_count = ceil((multipliers_digits_counts_sum - 1) / 2)
    for left_multiplier_digits_count in range(1, max_left_multipliers_digits_count + 1):
        right_multiplier_digits_count = (multipliers_digits_counts_sum
                                         - left_multiplier_digits_count)
        left_multipliers_digits = permutations(digits,
                                               r=left_multiplier_digits_count)
        for left_multiplier_digits in left_multipliers_digits:
            allowed_right_multipliers_digits = digits - set(left_multiplier_digits)
            right_multipliers_digits = permutations(allowed_right_multipliers_digits,
                                                    r=right_multiplier_digits_count)
            for right_multiplier_digits in right_multipliers_digits:
                allowed_products_digits = (allowed_right_multipliers_digits
                                           - set(right_multiplier_digits))
                products_digits = permutations(allowed_products_digits,
                                               r=product_multiplier_digits_count)
                for product_digits in products_digits:
                    left_multiplier = digits_to_number(left_multiplier_digits)
                    right_multiplier = digits_to_number(right_multiplier_digits)
                    product = digits_to_number(product_digits)
                    if left_multiplier * right_multiplier == product:
                        yield product
예제 #2
0
def curious_fractions(numbers: Iterable[int]) -> Iterable[Fraction]:
    fractions_parts = permutations(numbers, r=2)
    filtered_fractions_parts = star_filter(
        non_trivial_fraction, star_filter(operator.lt, fractions_parts))
    for numerator, denominator in filtered_fractions_parts:
        numerator_digits = list(number_to_digits(numerator))
        denominator_digits = list(number_to_digits(denominator))
        try:
            common_digit, = set(numerator_digits) & set(denominator_digits)
        except ValueError:
            continue
        else:
            cancelled_numerator_digits = numerator_digits[:]
            cancelled_numerator_digits.remove(common_digit)

            cancelled_denominator_digits = denominator_digits[:]
            cancelled_denominator_digits.remove(common_digit)

            cancelled_numerator = digits_to_number(cancelled_numerator_digits)
            cancelled_denominator = digits_to_number(
                cancelled_denominator_digits)

            fraction = Fraction(numerator, denominator)
            cancelled_fraction = Fraction(cancelled_numerator,
                                          cancelled_denominator)
            fraction_is_curious = fraction == cancelled_fraction
            if fraction_is_curious:
                yield fraction
예제 #3
0
def pandigital_multiples(digits: Collection[int]) -> Iterator[int]:
    position_stop = ceil(len(digits) / 2)
    for digits in permutations(digits):
        for position in range(1, position_stop):
            base_digits = digits[:position]
            base = digits_to_number(base_digits)
            base_digits_set = set(base_digits)
            tail_start = position
            for multiplier in range(2, 10):
                tail = ''.join(map(str, digits[tail_start:]))
                if not tail:
                    continue
                step = base * multiplier
                step_digits = list(number_to_digits(step))
                step_digits_set = set(step_digits)
                step_digits_count = len(step_digits)
                if step_digits_count < len(step_digits_set):
                    break
                if step_digits_set & base_digits_set:
                    break
                if not tail.startswith(str(step)):
                    break
                tail_start += step_digits_count
            else:
                yield digits_to_number(digits)
예제 #4
0
def sub_string_divisible_numbers(*,
                                 digits: Iterable[int],
                                 slicers_by_divisors: Dict[int, slice]
                                 ) -> Iterable[int]:
    for digits in permutations(digits):
        number = digits_to_number(digits)
        digits = list(number_to_digits(number))
        for divisor, slicer in slicers_by_divisors.items():
            digits_slice = digits[slicer]
            sliced_number = digits_to_number(digits_slice)
            if sliced_number % divisor:
                break
        else:
            yield number
예제 #5
0
def truncatable_primes(digits: Tuple[int] = ()) -> Iterable[int]:
    candidate_digits_count = len(digits) + 1
    for digit in possible_digits:
        candidate_digits = (digit,) + digits
        candidate_number = digits_to_number(candidate_digits)
        if not prime(candidate_number):
            continue

        if (candidate_digits_count > 1 and
                all(prime(digits_to_number(candidate_digits[:position]))
                    for position in range(1, candidate_digits_count))):
            yield candidate_number

        yield from truncatable_primes(candidate_digits)
예제 #6
0
from utils import (prime_numbers, digits_to_number, number_to_digits)

pandigits = {digit: set(range(1, digit + 1)) for digit in range(1, 10)}


def is_pandigital(number: int) -> bool:
    digits = list(number_to_digits(number))
    digits_set = set(digits)
    if len(digits) > len(digits_set):
        return False
    max_digit = max(digits_set)
    return not (pandigits[max_digit] ^ digits_set)


pandigital_primes = filter(
    is_pandigital,
    # 9-digit pandigital prime doesn't exist
    # since
    # 1 + 2 + ... + 9 = 45
    # => it will be always divided by 3 and 9
    prime_numbers(digits_to_number(range(8, 0, -1)), reverse=True))

assert next(pandigital_primes) == 7_652_413
예제 #7
0
def lychrel(number: int) -> bool:
    for _ in range(MAX_ITERATIONS_COUNT):
        number += digits_to_number(reversed(list(number_to_digits(number))))
        if is_palindrome(str(number)):
            return False
    return True