diff --git a/project_euler/problem_112/__init__.py b/project_euler/problem_112/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/project_euler/problem_112/sol1.py b/project_euler/problem_112/sol1.py new file mode 100644 index 000000000..d8cb334c9 --- /dev/null +++ b/project_euler/problem_112/sol1.py @@ -0,0 +1,89 @@ +""" +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") + return "".join(sorted(str(n))) != str(n) and "".join(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)}")