|
| 1 | +""" |
| 2 | +In laser physics, a "white cell" is a mirror system that acts as a delay line for the |
| 3 | +laser beam. The beam enters the cell, bounces around on the mirrors, and eventually |
| 4 | +works its way back out. |
| 5 | +
|
| 6 | +The specific white cell we will be considering is an ellipse with the equation |
| 7 | +4x^2 + y^2 = 100 |
| 8 | +
|
| 9 | +The section corresponding to −0.01 ≤ x ≤ +0.01 at the top is missing, allowing the |
| 10 | +light to enter and exit through the hole. |
| 11 | + |
| 12 | +The light beam in this problem starts at the point (0.0,10.1) just outside the white |
| 13 | +cell, and the beam first impacts the mirror at (1.4,-9.6). |
| 14 | +
|
| 15 | +Each time the laser beam hits the surface of the ellipse, it follows the usual law of |
| 16 | +reflection "angle of incidence equals angle of reflection." That is, both the incident |
| 17 | +and reflected beams make the same angle with the normal line at the point of incidence. |
| 18 | +
|
| 19 | +In the figure on the left, the red line shows the first two points of contact between |
| 20 | +the laser beam and the wall of the white cell; the blue line shows the line tangent to |
| 21 | +the ellipse at the point of incidence of the first bounce. |
| 22 | +
|
| 23 | +The slope m of the tangent line at any point (x,y) of the given ellipse is: m = −4x/y |
| 24 | +
|
| 25 | +The normal line is perpendicular to this tangent line at the point of incidence. |
| 26 | +
|
| 27 | +The animation on the right shows the first 10 reflections of the beam. |
| 28 | +
|
| 29 | +How many times does the beam hit the internal surface of the white cell before exiting? |
| 30 | +""" |
| 31 | + |
| 32 | + |
| 33 | +from math import isclose, sqrt |
| 34 | + |
| 35 | + |
| 36 | +def next_point( |
| 37 | + point_x: float, point_y: float, incoming_gradient: float |
| 38 | +) -> tuple[float, float, float]: |
| 39 | + """ |
| 40 | + Given that a laser beam hits the interior of the white cell at point |
| 41 | + (point_x, point_y) with gradient incoming_gradient, return a tuple (x,y,m1) |
| 42 | + where the next point of contact with the interior is (x,y) with gradient m1. |
| 43 | + >>> next_point(5.0, 0.0, 0.0) |
| 44 | + (-5.0, 0.0, 0.0) |
| 45 | + >>> next_point(5.0, 0.0, -2.0) |
| 46 | + (0.0, -10.0, 2.0) |
| 47 | + """ |
| 48 | + # normal_gradient = gradient of line through which the beam is reflected |
| 49 | + # outgoing_gradient = gradient of reflected line |
| 50 | + normal_gradient = point_y / 4 / point_x |
| 51 | + s2 = 2 * normal_gradient / (1 + normal_gradient * normal_gradient) |
| 52 | + c2 = (1 - normal_gradient * normal_gradient) / ( |
| 53 | + 1 + normal_gradient * normal_gradient |
| 54 | + ) |
| 55 | + outgoing_gradient = (s2 - c2 * incoming_gradient) / (c2 + s2 * incoming_gradient) |
| 56 | + |
| 57 | + # to find the next point, solve the simultaeneous equations: |
| 58 | + # y^2 + 4x^2 = 100 |
| 59 | + # y - b = m * (x - a) |
| 60 | + # ==> A x^2 + B x + C = 0 |
| 61 | + quadratic_term = outgoing_gradient ** 2 + 4 |
| 62 | + linear_term = 2 * outgoing_gradient * (point_y - outgoing_gradient * point_x) |
| 63 | + constant_term = (point_y - outgoing_gradient * point_x) ** 2 - 100 |
| 64 | + |
| 65 | + x_minus = ( |
| 66 | + -linear_term - sqrt(linear_term ** 2 - 4 * quadratic_term * constant_term) |
| 67 | + ) / (2 * quadratic_term) |
| 68 | + x_plus = ( |
| 69 | + -linear_term + sqrt(linear_term ** 2 - 4 * quadratic_term * constant_term) |
| 70 | + ) / (2 * quadratic_term) |
| 71 | + |
| 72 | + # two solutions, one of which is our input point |
| 73 | + next_x = x_minus if isclose(x_plus, point_x) else x_plus |
| 74 | + next_y = point_y + outgoing_gradient * (next_x - point_x) |
| 75 | + |
| 76 | + return next_x, next_y, outgoing_gradient |
| 77 | + |
| 78 | + |
| 79 | +def solution(first_x_coord: float = 1.4, first_y_coord: float = -9.6) -> int: |
| 80 | + """ |
| 81 | + Return the number of times that the beam hits the interior wall of the |
| 82 | + cell before exiting. |
| 83 | + >>> solution(0.00001,-10) |
| 84 | + 1 |
| 85 | + >>> solution(5, 0) |
| 86 | + 287 |
| 87 | + """ |
| 88 | + num_reflections: int = 0 |
| 89 | + point_x: float = first_x_coord |
| 90 | + point_y: float = first_y_coord |
| 91 | + gradient: float = (10.1 - point_y) / (0.0 - point_x) |
| 92 | + |
| 93 | + while not (-0.01 <= point_x <= 0.01 and point_y > 0): |
| 94 | + point_x, point_y, gradient = next_point(point_x, point_y, gradient) |
| 95 | + num_reflections += 1 |
| 96 | + |
| 97 | + return num_reflections |
| 98 | + |
| 99 | + |
| 100 | +if __name__ == "__main__": |
| 101 | + print(f"{solution() = }") |
0 commit comments