""" Problem 112: https://projecteuler.net/problem=112 Working from left-to-right if no digit is exceeded by the digit to its left it is called an increasing number; for example, 134468. Similarly if no digit is exceeded by the digit to its right it is called a decreasing number; for example, 66420. We shall call a positive integer that is neither increasing nor decreasing a "bouncy" number, for example, 155349. Clearly there cannot be any bouncy numbers below one-hundred, but just over half of the numbers below one-thousand (525) are bouncy. In fact, the least number for which the proportion of bouncy numbers first reaches 50% is 538. Surprisingly, bouncy numbers become more and more common and by the time we reach 21780 the proportion of bouncy numbers is equal to 90%. Find the least number for which the proportion of bouncy numbers is exactly 99%. """ def check_bouncy(n: int) -> bool: """ Returns True if number is bouncy, False otherwise >>> check_bouncy(6789) False >>> check_bouncy(-12345) False >>> check_bouncy(0) False >>> check_bouncy(6.74) Traceback (most recent call last): ... ValueError: check_bouncy() accepts only integer arguments >>> check_bouncy(132475) True >>> check_bouncy(34) False >>> check_bouncy(341) True >>> check_bouncy(47) False >>> check_bouncy(-12.54) Traceback (most recent call last): ... ValueError: check_bouncy() accepts only integer arguments >>> check_bouncy(-6548) True """ if not isinstance(n, int): raise ValueError("check_bouncy() accepts only integer arguments") str_n = str(n) sorted_str_n = "".join(sorted(str_n)) return sorted_str_n != str_n and sorted_str_n[::-1] != str_n def solution(percent: float = 99) -> int: """ Returns the least number for which the proportion of bouncy numbers is exactly 'percent' >>> solution(50) 538 >>> solution(90) 21780 >>> solution(80) 4770 >>> solution(105) Traceback (most recent call last): ... ValueError: solution() only accepts values from 0 to 100 >>> solution(100.011) Traceback (most recent call last): ... ValueError: solution() only accepts values from 0 to 100 """ if not 0 < percent < 100: raise ValueError("solution() only accepts values from 0 to 100") bouncy_num = 0 num = 1 while True: if check_bouncy(num): bouncy_num += 1 if (bouncy_num / num) * 100 >= percent: return num num += 1 if __name__ == "__main__": from doctest import testmod testmod() print(f"{solution(99)}")