from math import sqrt, pi, atan def get_intersection(n: int) -> tuple[int, int]: """Compute the point where the line intersects the circle for a given number of circles `n`. Equation for circle: y = 1 - sqrt(2*x - x**2) Equation for line: y = (1/n) * x """ # Computed via Wolfram alpha; could be derived by setting the curves equal, # isolating the root, and then applying the quadratic formula. x_int = (-sqrt(2) * n ** (3 / 2) + n**2 + n) / (n**2 + 1) y_int = x_int / n return (x_int, y_int) def get_ratio_orange(n: int) -> float: """Compute the ratio between the orange and the blue section. The blue section is the L-section meaning the area outside of the quarter circle. The orange area is the concave triangle created by the diagonal line.""" x, y = get_intersection(n) area_blue = 1 - (pi / 4) theta = atan((1 - x) / (1 - y)) # angle of concave triangle circle part area_sector = theta / 2 # area of sector of concave triangle circle part # area_orange = area triangle + area_rectangle + area_triangle - area_sector area_orange = (0.5 * x * y) + ((1 - x) * y) + (0.5 * (1 - x) * (1 - y)) area_orange -= area_sector return area_orange / area_blue def get_less_than(percentage: float) -> int: ratio = percentage / 100 n_min, n_max = 1, 10000 while n_max - n_min > 1: n_mid = (n_max + n_min) // 2 ratio_n = get_ratio_orange(n_mid) if ratio_n < ratio: n_max = n_mid else: n_min = n_mid return n_max def euler_587(): assert get_ratio_orange(1) == 0.5 assert abs(get_ratio_orange(2) - 0.3646) <= 0.0001 assert get_less_than(10) == 15 return get_less_than(0.1) if __name__ == "__main__": solution = euler_587() print(f"e587.py: {solution}") assert solution == 2240