Teaser 3242: Tynemouth Boating Lake
From The Sunday Times, 10th November 2024 [link] [link]
When Tynemouth Boating Lake was being constructed, the builder hammered in stakes at two points in the ground, tied the ends of a rope to the stakes, and with a stick keeping the rope taut, marked out an ellipse as shown (not to scale). He was surprised to find that at some points on the circumference, the rope formed two different right-angled triangles, both with sides a whole number of feet long. The free length of the rope was 289 feet.
In increasing order, what were the five lengths of the sides of the two triangles?
See: [ Google Maps ].
[teaser3242]


Jim Randell 2:00 am on 10 November 2024 Permalink |
The rope is attached to the posts, so two sides of each triangle are formed by the rope, and the remaining side is formed from the straight line between the two posts (the dashed line in the diagram). An alternative method of construction would be to form the rope into a loop which is placed over the posts, and then pulled tight to form a triangle where all three sides are formed by the rope, but this will construct a smaller ellipse).
Initially I thought some of the 289 ft of rope would be used to attach it to the posts, but I think the amount of (inextensible) rope between the posts needs to be exactly 289 ft after it has been attached in order for the puzzle to have a unique solution.
This Python program runs in 69ms. (Internal runtime is 209µs).
from enigma import (defaultdict, pythagorean_triples, subsets, printf) # collect pythagorean triples by perimeter d = defaultdict(list) for ss in pythagorean_triples(289): p = sum(ss) if any(p - s == 289 for s in ss): d[p].append(ss) # consider possible perimeters for p in sorted(d.keys()): # choose two triangles (x, y, z), (u, v, w) for ((x, y, z), (u, v, w)) in subsets(d[p], size=2, select='P'): # such that the hypotenuse of one is a non-hypotenuse of the other if w in {x, y}: R = u + v # length of the rope printf("R={R} w={w} -> {t1}, {t2} -> {ss}", t1=(x, y, z), t2=(u, v, w), ss=sorted([x, y, z, u, v]))Solution: The sides of the triangles are: 60, 85, 204, 221, 229 ft.
The triangles are: (60, 221, 229) and (85, 204, 221), and the posts were 221 ft apart.
The major and minor axes of the ellipse measure 255 and 186.23 (= 34√30) ft.
You can see the results when some of the rope is used in the attachments by changing the condition on line 7 to [[
p - s < 289]].LikeLike
Jim Randell 11:56 am on 11 November 2024 Permalink |
Only certain rope lengths will work for this problem.
Lengths that will work are squares of the following primes, and multiples of those squares:
which are the primes that have a residue of 1 or 7 modulo 8. (See: OEIS A001132).
In the given puzzle: 289 = 17^2.
LikeLike
GeoffR 9:17 pm on 12 November 2024 Permalink |
I tested my code with the squares of 7, 23 and 97 which all worked OK:
Five lengths = [12, 21, 28, 35, 37] – for 7 * 7 = 49
Five lengths = [120, 184, 345, 391, 409] – for 23 * 23 = 529
Five lengths = [1092, 1261, 8148, 8245, 8317] – for 97 * 97 = 9409
LikeLike
Jim Randell 4:51 pm on 13 November 2024 Permalink |
Here is a general solution that works by expressing the length of the rope R as:
(It doesn’t check that R is a multiple of p^2 for some prime p where p mod 8 = 1 or 7).
from enigma import (irange, ihypot, prime_factor, arg, printf) # solve for rope R = k.n^2 def solve(n, k=1): # solve the reduced problem R = n^2 R = n * n for i in irange(1, n - 1): # calculate the (u, v, w) triangle (w = hypotenuse) u = i * n v = R - u if u > v: break w = ihypot(u, v) if w is None: continue # calculate the (x, w, z) triangle (z = hypotenuse) x = u - i * i z = R - x # return the two triangles, scaled appropriately yield ((k * x, k * w, k * z), (k * u, k * v, k * w)) R = arg(289, 0, int) # express R as k.n^2 k = n = 1 for (p, e) in prime_factor(R): (d, r) = divmod(e, 2) if r > 0: k *= p n *= p**d printf("[{R} = {k} * {n}^2]") # solve the problem for (t1, t2) in solve(n, k): w = t1[1] ss = sorted(set(t1 + t2)) printf("R={R} w={w} -> {t1}, {t2} -> {ss}")LikeLike
Frits 5:56 am on 10 November 2024 Permalink |
from math import isqrt is_square = lambda n: n == isqrt(n) ** 2 L = 289 # RHS triangle a^2 + b^2 = c^2 # where c is the distance between the two focal points with a <= b for a in range(1, L // 2 + 1): if not is_square(c2 := a**2 + (b := L - a)**2): continue # LHS triangle c^2 + d^2 = (L - d)^2 if c2 % L: continue if (double_d := L - c2 // L) % 2: continue d = double_d // 2 print("answer:", sorted([a, b, int(c2**.5), d, L - d]))LikeLike
Frits 1:03 pm on 10 November 2024 Permalink |
A variation with 4 iterations of k (or only 2 if we use the parity of L).
from math import ceil L = 289 # 17^2 # as c2 % L = 0 then c^2 = multiplier * L # c^2 = k^2 * L as L is a square number # a^2 + (L - a)^2 = c^2 # a = (2.L +- sqrt(4 * L^2 - 8.L^2 + 8.c^2)) / 4 # discriminant: -4 * L^2 + 8 * c^2 >= 0 # c^2 >= L**2 / 2 --> k^2 >= L / 2 for k in range(ceil((L / 2)**.5), ceil(L**.5)): c2 = L * k**2 # c2 % L = 0 # as L is odd then k must be odd as well (we won't use that) if (double_d := L - k**2) % 2: continue d = double_d // 2 # check valid discriminant if (D := -4 * L**2 + 8 * c2) < 0: continue # a is the bigger non-hypothenuse side (using '+' in the formula) a, r = divmod(2 * L + D**.5, 4) if r: continue a = int(a) c = int((L * k**2)**.5) print("answer:", sorted([a, L - a, c, d, L - d]))LikeLike
GeoffR 10:01 am on 10 November 2024 Permalink |
LikeLike
GeoffR 7:02 pm on 10 November 2024 Permalink |
Faster than expected with all the looping.
def is_sq(n): if round(n ** 0.5) ** 2 == n: return True return False # 1st triangle is aeb with hypotenuse b # e is distance between the two stakes for a in range(10, 290): for e in range(a+1, 290): if is_sq(a ** 2 + e ** 2): b = int((a ** 2 + e ** 2) ** 0.5) if a + b != 289:continue # 2nd triangle is cde with hypotenuse e for c in range(10, 290): for d in range(c+1, 290): if c + d != 289:continue if c ** 2 + d ** 2 == e ** 2: L1 = [a, b, c, d, e] if len(L1) == len(set(L1)): sorted_list = sorted(L1) print(f"Five lengths = {sorted_list}")LikeLike