Tagged: by: Phil Jackson Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 1:36 am on 10 November 2024 Permalink | Reply
    Tags: by: Phil Jackson   

    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's avatar

      Jim Randell 2:00 am on 10 November 2024 Permalink | Reply

      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 ]].

      Like

      • Jim Randell's avatar

        Jim Randell 11:56 am on 11 November 2024 Permalink | Reply

        Only certain rope lengths will work for this problem.

        Lengths that will work are squares of the following primes, and multiples of those squares:

        7, 17, 23, 31, 41, 47, 71, 73, 79, 89, 97, …

        which are the primes that have a residue of 1 or 7 modulo 8. (See: OEIS A001132).

        In the given puzzle: 289 = 17^2.

        Like

        • GeoffR's avatar

          GeoffR 9:17 pm on 12 November 2024 Permalink | Reply

          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

          Like

      • Jim Randell's avatar

        Jim Randell 4:51 pm on 13 November 2024 Permalink | Reply

        Here is a general solution that works by expressing the length of the rope R as:

        R = k.n^2

        (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}")
        

        Like

    • Frits's avatar

      Frits 5:56 am on 10 November 2024 Permalink | Reply

      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]))
      

      Like

      • Frits's avatar

        Frits 1:03 pm on 10 November 2024 Permalink | Reply

        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]))
        

        Like

    • GeoffR's avatar

      GeoffR 10:01 am on 10 November 2024 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      % Two triangles are abe with 'b' as  hypotenuse and cde with 'e' as hypotenuse
      % 'e' also is the distance between the two stakes
      var 10..289:a; var 10..289:b; var 10..289:c;
      var 10..289:d; var 10..289:e;
      
      constraint all_different ([a, b, c, d, e]);
      
      constraint a + b == 289 /\ c + d == 289;
      
      constraint a*a + e*e == b*b /\ c*c + d*d == e*e;
      
      array[1..5] of var int: unsorted = [a, b, c, d, e];
      array[1..5] of var int: sorted = sort(unsorted);
      
      solve satisfy;
      
      output [
        "Five lengths in increasing order: ", show(sorted)
      ];
      
      
      

      Like

    • GeoffR's avatar

      GeoffR 7:02 pm on 10 November 2024 Permalink | Reply

      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}")
      
      

      Like

  • Unknown's avatar

    Jim Randell 6:58 am on 28 July 2024 Permalink | Reply
    Tags: by: Phil Jackson   

    Teaser 3227: Chess club cupboard 

    From The Sunday Times, 28th July 2024 [link] [link]

    When installing the Chess Club cupboard in its new room, the members carelessly jammed it on the low ceiling and back wall, as shown from the side (not to scale).

    Measurements were duly taken and the following were noted. The floor and ceiling were level and the back wall was vertical. The cupboard was a rectangular cuboid. The ceiling height was just 2cm greater than the cupboard height. Also, the depth of the cupboard from front to back was 148 cm less than the cupboard height. Finally the point on the ceiling where the cupboard jammed was a distance from the back wall that was 125 cm less than the cupboard height.

    What is the cupboard height?

    [teaser3227]

     
    • Jim Randell's avatar

      Jim Randell 7:11 am on 28 July 2024 Permalink | Reply

      Originally I assumed some of the dimensions were whole numbers of centimetres, which allows you to find the answer, but we do not need to make this assumption.

      Here is a solution using the [[ Polynomial ]] class from the enigma.py library to generate a polynomial equation, and we can then look for positive real roots of the equation to determine the necessary dimensions.

      (Also, today is the 15th anniversary of the start of the enigma.py library).

      It runs in 73ms. (Internal runtime is 4.2ms).

      Run: [ @replit ]

      from enigma import (Polynomial, sq, printf)
      
      # let x = cupboard depth
      fx = Polynomial('x')
      
      # y = cupboard height
      fy = fx + 148
      
      # h = room height
      fh = fy + 2
      
      # d = distance top jam to top corner
      fd = fy - 125
      
      # if:
      #   a = height of upper triangle
      #   b = height of lower triangle
      # we have:
      #   h = a + b
      # and:
      #   a^2 = y^2 - d^2
      #   b = x.d/y
      #   a = h - b = (y.h - x.d)/y
      #   a^2 = (y.h - x.d)^2 / y^2 = y^2 - d^2
      #   y^2(y^2 - d^2) = (y.h - x.d)^2  # for x > 0
      f = (sq(fy) * (sq(fy) - sq(fd)) - sq(fy * fh - fx * fd)).scale()
      printf("[f(x) = {f}]", f=f.print())
      
      # look for positive real roots of f(x) = 0
      for x in f.roots(domain='F', include='+'):
        # output solution
        printf("cupboard = {x:g} x {y:g}; room height = {h:g}", y=fy(x), h=fh(x))
      

      Solution: The cupboard was 185 cm high.

      So the cupboard has dimensions: 37 cm × 185 cm, and the room is 187 cm high.

      The polynomial to determine the depth of the cupboard x is:

      f(x) = x^3 + 79x^2 − 1628x − 98568
      f(x) = (x − 37)(x^2 + 116x + 2664)

      The linear component has a positive root at:

      x = 37

      which provides the required answer for the depth of the cupboard.

      The quadratic component has two negative roots at:

      x = 10√7 − 58 ≈ −31.542
      x = −10√7 − 58 ≈ −84.458

      but these do not provide viable answers to the puzzle.

      Like

      • Jim Randell's avatar

        Jim Randell 9:09 am on 29 July 2024 Permalink | Reply

        Or the polynomial can be solved numerically, to give an approximate answer.

        And this is slightly faster. The following Python program has an internal runtime of 324µs).

        Run: [ @replit ]

        from enigma import (Polynomial, sq, find_zero, printf)
        
        # let x = cupboard depth
        # y = cupboard height
        # h = room height
        # d = distance top jam to top corner
        fx = Polynomial('x')
        fy = fx + 148
        fh = fy + 2
        fd = fy - 125
        
        # construct polynomial to solve
        f = (sq(fy) * (sq(fy) - sq(fd)) - sq(fy * fh - fx * fd)).scale()
        printf("[f(x) = {f}]", f=f.print())
        
        # find a solution numerically
        x = find_zero(f, 1, 100).v
        
        # output solution
        printf("cupboard = {x:.2f} x {y:.2f}; room height = {h:.2f}", y=fy(x), h=fh(x))
        

        Like

    • GeoffR's avatar

      GeoffR 12:21 pm on 28 July 2024 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..250:h; var 1..250:y1; var 1..100:b;
      
      % h = cupboard height
      % y1 = depth below ceiling of top cupboard jam point
      % b = distance of bottom jam point from vertical wall
      
      % Two triangles to solve by Pythagorus
      constraint h * h == (h - 125) * (h - 125) + (y1 * y1);
      
      constraint (h - 148 ) * (h - 148) == (b * b) + (h + 2 - y1) * (h + 2 - y1);
      
      solve satisfy;
      
      output ["Cupboard height = " ++ show(h) ++ "cm."];
      
      
      
      

      Like

    • GeoffR's avatar

      GeoffR 12:52 pm on 28 July 2024 Permalink | Reply

      I don’t suppose the setter intended it, but I found a second solution with a cupboard height of more than 400 cm higher than the presumed solution!

      Like

      • Jim Randell's avatar

        Jim Randell 2:32 pm on 28 July 2024 Permalink | Reply

        @GeoffR: Originally I thought there were further solutions involving cupboards with non-integer dimensions, or very large cupboards (and rooms). But now I have done the analysis I found that the depth of the cupboard is defined by a cubic equation that has one positive real root (which gives the required answer) and two negative real roots, so I don’t think there are any further solutions, even if the size of the cupboard/room are not restricted.

        Like

        • Frits's avatar

          Frits 2:54 pm on 28 July 2024 Permalink | Reply

          @Jim,

          The equations I noted down for this puzzle also had a solution 10 * (9 + sqrt(7)) but that was less than 148 cm.

          Like

          • Jim Randell's avatar

            Jim Randell 3:23 pm on 28 July 2024 Permalink | Reply

            @Frits: Presumably you were working in terms of the height of the cupboard. I was working in terms of the depth, so there was only one positive root.

            Like

        • GeoffR's avatar

          GeoffR 4:11 pm on 28 July 2024 Permalink | Reply

          @Jim: My original program gave the same outputs as your original solution.
          I increased the upper bounds of the variables to show the second solution I obtained with the second program below. Seems reasonable to use integers . Program is slow with the extra solution, but does it look OK?

          % A Solution in MiniZinc
          include "globals.mzn";
          
          var 1..1250:h; var 1..1250:y1; var 1..1000:b;
          
          % h = cupboard height, rht = room height (for output)
          % y1 = depth below ceiling of top cupboard jam point
          % b = distance of bottom jam point from vertical wall
          
          % Two triangles to solve by Pythagorus
          constraint h * h == (h - 125) * (h - 125) + (y1 * y1);
          
          constraint (h - 148 ) * (h - 148) == (b * b) + (h + 2 - y1) * (h + 2 - y1);
          
          solve satisfy;
          
          output ["Cupboard height = " ++ show(h) ++ "cm." ++ "\n" ++
          "[h, w, rht, y1, b ] = " ++ show( [h, h-148, h+2, y1, b ]  )];
          

          Like

          • Jim Randell's avatar

            Jim Randell 6:03 pm on 28 July 2024 Permalink | Reply

            @GeoffR: My very first program did not include a check that the upper and lower triangles were similar, which lead me to believe that there potentially multiple solutions without further constraints. But this allows cupboards that have a non-rectangular cross-section.

            However my subsequent analysis gives a single solution without further constraints. So we don’t need to limit the size of cupboard/room, and we don’t require measurements to have integer values.

            Liked by 1 person

    • Ruud's avatar

      Ruud 6:16 pm on 28 July 2024 Permalink | Reply

      I worked out by hand that the problem can be defined as finding the roots of the expression
      math.sqrt(250 *c -125*125)+((c-148)*(c-125)/c) – (c+2)
      I just put that in Wolfram Alpha as
      find roots of sqrt(250 *c -125*125)+((c-148)*(c-125)/c) – (c+2)
      to find the real solution (not revealed) and 10 (9 + sqrt(7)). The latter does not work here.

      Like

      • Frits's avatar

        Frits 6:55 pm on 28 July 2024 Permalink | Reply

        I did something similar with the same results.

        Adding the following to your code prevent multiple solutions:

          
        % same angles
        constraint h * b = (h - 148) * y1;
        

        Like

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel
Design a site like this with WordPress.com
Get started