Enigmatic Code

Programming Enigma Puzzles

Teaser 2503

From The Sunday Times, 12th September 2010 [link]

George has placed two vertical mirrors touching each other, with an angle between them. He has also placed a small cube between the mirrors and counted how many images there are of it in the mirrors. (For example, if the mirrors had 90 degrees between them, there would be three images). He wrote down two whole numbers – the angle between the mirrors, in degrees, and the number of images of the cube. When Martha saw the two numbers, she commented that their product, appropriately, was a perfect cube.

What was the angle between the mirrors?

Note: After much discussion of this puzzle, regular solvers of The Sunday Times Teaser puzzles have decided that the puzzle is flawed, and there is not enough information given to arrive at a unique solution. Nevertheless the puzzle has some interesting aspects to it.

[teaser2503]

2 responses to “Teaser 2503

  1. Jim Randell 29 August 2018 at 8:12 am

    At the time this puzzle was published in The Sunday Times (12th September 2010) it caused much discussion on a group dedicated to Sunday Times Teasers. (The discussion is here: [link]). And it was agreed that there was more than one possible answer, and that the published solution was over simplified.

    I became aware of it when this puzzle surfaced again on the current discussion group for Sunday Times Teasers (which is here: [link]), and posted my thoughts on the subject. Here is a more detailed discussion, (with diagrams):

    My experience with previous puzzles involving reflections (like Enigma 1532) is that rather than think about how the light is reflected by the mirrors, it is easier to think of the mirror as creating a reflected universe on the other side of it, and allowing the light to pass through in a straight line.

    So, my reasoning is that the mirrors divide a circle into sectors. If we place the mirrors so they enclose the “southern point” of the circle, and place the observer due south of the join, then we can colour the SW enclosed segment red and the SE enclosed segment blue, then we can mirror these red and blue segments in pairs northwards until we reach the “northern point” of the circle. If the mirrored segments don’t fit exactly we have a “partial pair” at the top.

    Any point (so I’m considering very small objects) in one of the “real” segments enclosed by the mirrors will be mirrored into all the similarly coloured segments. Whether it appears in a partial segment depends on its position in the “real” segment. So every full red/blue pair has an image of the point in (one is the real point, and the rest are images in the mirrors) that could potentially be seen by an observer, and the point may appear in a partial pair.

    In this program the [[ images() ]] function calculates the appropriate number of complete mirrored regions, along with a flag indicating if there is an additional partial region, for angles between 1° and 179°. It runs in 69ms.

    Run: [ @repl.it ]

    from enigma import irange, is_cube, printf
    
    # return (<number>, <partial>)
    # partial is set if there is an additional portion of the enclosed
    # area imaged (so there may be an additional reflection of an object
    # if it is placed in the appropriate area)
    def images(a):
      # number of objects (real and virtual)
      (n, r) = divmod(360, a)
      return (n - 1, (r > 0))
    
    # consider possible integers for the angle between mirrors
    for a in irange(1, 179):
      (n, p) = images(a)
    
      # check the given example
      assert (n == 3 or n + p == 3 if a == 90 else True)
    
      if p:
        # there is a partial reflection
        if is_cube(n * a):
          printf("angle = {a} degrees, full images = {n} (no object in partial reflection)")
        if is_cube((n + p) * a):    
          printf("angle = {a} degrees, full images = {n} (+1 additional object in partial reflection)")
      else:
        # there is no partial reflection
        if is_cube(n * a):
          printf("angle = {a} degrees, full images = {n} (no partial reflection)")
    

    Solution: There are three possible angles: 49°, 108° 125°.

    So, for a “southern” observer, where the object may be placed anywhere between the mirrors, there are several possible solutions:

    49°: 6 full reflections, +1 object in the partial reflection. (7 × 49 = 7³)
    108°: 2 full reflections, no object in the partial reflection. (2 × 108 = 6³)
    125°: 1 full reflection, no object in the partial reflection. (1 × 125 = 5³)

    In each case there is a partially reflected region (none of the angles exactly divides 360°), so the object will have to be placed appropriately to achieve the desired number of reflections. The 125° solution will be difficult to achieve as the partially reflected area is almost complete, but with a small enough cube it should be possible.

    There would be further solutions with a single reflection if the mirrors are allowed to make an angle of 180° or more:

    216°: 0 full reflections, +1 object in partial reflection. (1 × 216 = 6³)
    343°: 0 full reflections, +1 object in partial reflection. (1 × 343 = 7³)

    I also wrote a program to actually plot a diagram to illustrate my analysis above:

    (The thick black lines represent the mirrors (and their reflections). The lighter coloured sectors of the circle indicate partially reflected regions. The small black dots represent an object and its reflections, situated to provide the desired number of reflected images. I can make the program available if anyone wants to see it).

    I also added code to show “sight lines” from the appropriately placed object and its reflections to an observer:

    (The lines exiting the bottom of the diagram show the number of images. There is one for the original object, and one for each of the reflections).

    The 49° solution:

    The 108° solution:

    The 125° solution:

    This all seems very convincing, but I hadn’t tried it in real life. To this end, I bought some mirrored acrylic sheet and constructed the situations given above in real life:

    The 49° solution:

    The 108° solution:

    The 125° solution:

    This confirms the analysis, and each of these situations gives rise to a viable solution. Although in my opinion the 108° solution is the most pleasing.

    But having played around with the mirrors, the above analysis seems to work OK if the mirrors are viewed from “due south”, but it is possible to place the object and observer in such a way that we can achieve different numbers of objects than the above analysis suggests (e.g. 3 reflections and an angle of 72° (3 × 72 = 6³), or 4 reflections at an angle of 54° (4 × 54 = 6³)) giving rise to further solutions.

    In the general case, where the observer is not necessarily due south, I think the circle is split into the “red sector” to the left of the observer, and the “blue sector” to the right of the observer, and these sectors can then be reflected around the circle until we reach the line that passes from the observer through the join in the mirrors. So without knowing where the observer is it is difficult to determine the exact number of potentially reflected objects (we also have the problem that the observer can be placed such that some of the reflections are not visible – either masked by being in line with another object (real or reflected), or it could fall outside the bounds of the mirror and not be reflected at all.

    So the puzzle, as published, seems to be too open ended to allow a single solution.

    If the observer and the object are both on the “southern meridian”, then for 49° there will be 6 reflections (not a solution), for 108° there will be 2 reflections (which does give a solution), and for 125° there are also 2 reflections (not a solution). So 108° is still my preferred solution.

    The published solution, apparently claimed that: “In general the number of images with angle A is the highest integer less than 360/A”, and so gave an answer 49°. So it seems the setter was taking a somewhat simplified view of the situation.

    • Jim Randell 29 August 2018 at 8:25 am

      I reworked my code, so that it allows viewing angles other than from the bisector line between the mirrors.

      The following code considers integer mirror angles of between 1° and 179°, and then all viewing angles at half-degree intervals between them. For each mirror angle and viewing angle combination it calculates the number of images (including the original object) for objects placed at half-degree intervals between the mirrors. If the product of the mirror angle and the number of reflections is a perfect cube, a line is printed giving the regions that the object can be placed in to achieve this.

      By operating in units of half-degrees we can do all the calculations using integers.

      Run time is 1.84s (using PyPy).

      from collections import Counter
      from enigma import irange, is_cube, join, sprintf as f
      
      # let's do everything in half-degrees
      
      # m = mirror angle
      # e = observer line
      def solve(m, e):
      
        # reflect in increments of i (+/- 1) from x
        # collecting object angles in c
        def reflect(c, i, x):
          for _ in irange(1, 359):
            x += i
            if abs(x) == m:
              i = -i
            else:
              c[x] += 1
      
        # start with the observer
        c = Counter([e])
        reflect(c, +1, e) # left half
        reflect(c, -1, e) # right right
        return c
      
      # turn a sequence of values into a sequence of ranges
      def ranges(vs):
        rs = list()
        a = b = None
        for v in sorted(vs):
          if a is None:
            a = b = v
          elif v == b + 1:
            b = v
          else:
            rs.append((a, b))
            a = b = None
        if a is not None: rs.append((a, b))
        return rs
      
      # turn half degrees into whole degrees
      deg = lambda x: 0.5 * x
      
      # format a sequence of values (using function d to express degrees)
      def fmt(vs, d=deg):
        rs = ranges(vs)
        fmt = lambda a, b: (f("{a}..{b}", a=d(a), b=d(b)) if a != b else f("{a}", a=d(a)))
        return "[" + join((fmt(a, b) for (a, b) in rs), sep=", ") + "]"
      
      # collect results (mirror angle, reflections)
      rs = set()
      
      # consider mirror angles (1 to 180 degrees)
      for m in irange(1, 179):
        # consider observer angles (half degrees)
        for e in irange(0, m - 1):
          c = solve(m, e)
          # consider number of visible objects
          for v in sorted(set(c.values())):
            n = v - 1 # only count reflections
            if is_cube(n * m):
              # output viewing information
              ks = (k for (k, x) in c.items() if x == v)
              print(f("[mirror angle = {m}, observer angle = {e}, object angle = {ks}, reflections = {n}]", e=deg(e), ks=fmt(ks)))
              rs.add((m, n))
      
      # output results
      for (m, n) in sorted(rs):
        print(f("mirror angle = {m} degrees, reflections = {n}"))
      

      Assuming each possible reflection is visible, the following 5 solutions are viable:

      mirror angle = 7°, reflections = 49, (7 × 49 = 7³)
      mirror angle = 49°, reflections = 7, (49 × 7 = 7³)
      mirror angle = 72°, reflections = 3, (72 × 3 = 6³)
      mirror angle = 108°, reflections = 2, (108 × 2 = 6³)
      mirror angle = 125°, reflections = 1, (125 × 1 = 5³)

      The 49° 108° and 125° angles give solutions with a viewing angle of 0°, but 7° and 72° do not.

      I have verified these practically (apart from the 7° solution, where the mirrors are too close together).

      The 72° solution is interesting because 72 divides 360. Here’s a diagram of it:

      And here it is in real life:

      And here’s a diagram of the 7° solution (although it’s a bit busy):

      For completeness I should also mention that angles of 216° and 343° with 1 reflection are also viable solutions (if angles greater than 180° are allowed).

      We can consider a variant on the problem where instead of only counting the number of reflections, we count all the visible objects (i.e. we include the real object as well), and if we restrict the observer to being at 0°, then there is a unique answer of 49°, and this works with the object also placed at 0° (although it can be placed elsewhere). So this is a way of rescuing the puzzle (although it’s probably not what the setter had in mind, as for an angle between the mirrors of 90° there would be 4 visible objects, not just the three reflections).

      This variant is easily solved programatically by a program similar to the one I posted above (in [[ images() ]] we return n objects, instead of (n – 1)).

      However, even in this variant, if the angle of the observer is allowed to vary, then there are further solutions:

      mirror angle = 49°, objects = 7, (49 × 7 = 7³)
      mirror angle = 108°, objects = 2, (108 × 2 = 6³)
      mirror angle = 128°, objects = 4, (128 × 4 = 8³)

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: