Enigmatic Code

Programming Enigma Puzzles

Enigma 362: On the face of it

From New Scientist #1511, 5th June 1986 [link]

I have a cube and on each face there is a different digit (written in modern digital style, so that, for example, a 2 would look the same either way up). My viewpoint from the front stays the same in all that follows; it is the cube which moves. By a “top twist” I mean that the front face in view moves to the top, by a “right twist” that the front face in view moves to the right, etc., each time bringing a new face into view.

I start by looking at the face in view. Bottom twist, look again, bottom twist, look again, bottom twist, look again. In all I have read off, quite correctly placed, a four-figure perfect square.

Left twist and ready to start again. Look at the face in view, left twist, look again, top twist, look again, top twist, right twist, look again. I have now read off, quite correctly placed, another four-figure perfect square.

Now for a fresh start. I look at a face, left twist, look again, left twist, look again, left twist, look again. I have read off, quite correctly placed, a four-figure number which is exactly twice a perfect square.

Top twist, top twist and ready to start again. Look at the face in view, left twist, look again, left twist, look again, left twist, look again. This time I have read off, quite correctly placed, a four-figure number which is not a perfect square.

What is that last number?

[enigma362]

Advertisements

3 responses to “Enigma 362: On the face of it

  1. Jim Randell 16 September 2016 at 6:46 am

    Of the digits 1-9 depicted on a 7-segment display, (0, 1, 2, 5, 8) read the same when inverted, (3, 4, 7) do not make digits when inverted and (6, 9) read as each other when inverted. None of the digits can be read when rotated through a quarter turn (in either direction). (Although I suppose you could argue that 0 can).

    I wasn’t sure from the description whether you were allowed to have a face with a 6 on, and a different face with a 9 on (which would let you construct numbers with two 6’s or two 9’s), or whether only one face was allowed the 6-segment pattern because it could be read as either a 6 or a 9 depending on the orientation.

    In the Python 3 program below I allow for both a 6 and a 9 to be present (because it talks about “different digits”, rather than “different patterns”). It runs in 58ms.

    from collections import defaultdict
    from enigma import irange, nsplit, nconcat, printf
    
    # there are 9 possible digits, but only 8 possible patterns (6 and 9
    # share a pattern), so we will consider the patterns 0 - 8, and the
    # corresponding digits in all possible rotations (quarter turns)
    
    X = None
    
    # map from <pattern> -> <rotation> -> <digit>
    digits = {
      #   0- 1- 2- 3-  quarter turns  
      0: (0, X, 0, X),
      1: (1, X, 1, X),
      2: (2, X, 2, X),
      3: (3, X, X, X),
      4: (4, X, X, X),
      5: (5, X, 5, X),
      6: (6, X, 9, X),
      7: (7, X, X, X),
      8: (8, X, 8, X),
      9: (9, X, 6, X), # remove this to disallow pattern "9"
    }
    
    # map from <digit> -> [ (<pattern>, <rotation>), ... ]
    pattern = defaultdict(list)
    for (p, ds) in digits.items():
      seen = dict()
      for (r, d) in enumerate(ds):
        if d is None or d in seen: continue
        pattern[d].append((p, r))
        seen[d] = 1
    
    # labelling the faces of the cube Front, Back, Left Right, Up, Down
    # and recording the affect of a transition as (<face>, <quarter-turns>)
    (U, D, L, R, F, B) = (0, 1, 2, 3, 4, 5)
    
    # there are only 4 valid twists:
    twists = [
      # U       D       L       R       F       B
      ((F, 2), (B, 2), (L, 3), (R, 1), (D, 0), (U, 0)), # U = "top twist"
      ((B, 0), (F, 0), (L, 1), (R, 3), (U, 2), (D, 2)), # D = "bottom twist"
      ((U, 1), (D, 3), (F, 0), (B, 0), (R, 0), (L, 0)), # L = "left twist"
      ((U, 3), (D, 1), (B, 0), (F, 0), (L, 0), (R, 0)), # R = "right twist"
    ]
    
    # sequences of moves to get each face to the front (in both orientations)
    seqs = (
      [D], [U, L, L], # U
      [U], [L, L, U], # D
      [], [L, L, U, U], # F
      [U, U], [L, L], # B
      [R], [L, U, U], # L
      [L], [R, U, U], # R
    )
    
    # apply twists <ts> to cube <cube>, return the updated cube
    def twist(cube, ts):
      # are we done?
      if not ts:
        return cube
      else:
        cube2 = list()
        for (f, r) in twists[ts[0]]:
          x = cube[f]
          cube2.append(None if x is None else (x[0], (x[1] + r) % 4))
        return twist(cube2, ts[1:])
    
    # update list <s>, placing value <v> at index <i>
    def update(s, i, v):
      s = list(s)
      s[i] = v
      return s
    
    # apply the moves <ms> to the cube <cube> and ensure the corresponding
    # front faces observed match the digits <ds> (a None element always matches)
    # the final cube and actual digits seen are returned
    def match(cube, ms, ds, s=[]):
      # is there a digit to check?
      if ds[0] is not None:
        # check the front face
        if cube[F] is None:
          # front face is currently empty, match it to the digit
          for (p, r) in pattern[ds[0]]:
            # skip patterns already used on the cube
            if any(x[0] == p for x in cube if x is not None): continue
            # update the cube (<pattern>, <orientation>)
            cube2 = update(cube, F, (p, r))
            # is this the last move?
            if not ms:
              yield (cube2, s + [ds[0]])
            else:
              # apply the next move
              yield from match(twist(cube2, ms[:1]), ms[1:], ds[1:], s + [ds[0]])
        else:
          # check the front face matches what we are looking for
          (p, r) = cube[F]
          if ds[0] == digits[p][r]:
            # is this the last move?
            if not ms:
              yield (cube, s + [ds[0]])
            else:
              # apply the next move
              yield from match(twist(cube, ms[:1]), ms[1:], ds[1:], s + [ds[0]])
      else:
        # read the front face
        if cube[F] is None:
          # front face is not defined
          d = None
        else:
          (p, r) = cube[F]
          d = digits[p][r]
        # is this the final move?
        if not ms:
          yield (cube, s + [d])
        else:
          # apply the next move
          yield from match(twist(cube, ms[:1]), ms[1:], ds[1:], s + [d])
    
    # 4-digit squares
    squares = list(i * i for i in irange(32, 99))
    
    # 4-digit numbers that are twice a perfect square
    square2s = list(2 * i * i for i in irange(23, 70))
    
    # initial cube
    c0 = [None] * 6
    
    # the first number is a square
    for n1 in squares:
      # apply the first sequence of moves to produce n1
      for (c1, s1) in match(c0, [D, D, D], nsplit(n1)):
        # apply a left twist
        c1 = twist(c1, [L])
    
        # the second number is a square
        for n2 in squares:
          n2s = list(nsplit(n2))
          n2s.insert(3, None) # we don't read between the 3rd and 4th moves
          # apply the second sequence of moves to produce n2
          for (c2, s2) in match(c1, [L, U, U, R], n2s):
    
            # start from a new face
            for s in seqs:
              c = twist(c2, s)
    
              # the third number is twice a square
              for n3 in square2s:
                for (c3, s3) in match(c, [L, L, L], nsplit(n3)):
                  # apply two top twists
                  c3 = twist(c3, [U, U])
    
                  # and read off the final number
                  for (c4, s4) in match(c3, [L, L, L], [None] * 4):
                    # and check n4 is not a perfect square
                    if nconcat(s4) in squares: continue
    
                    printf("{c4} -> {s1} {s2} {s3} {s4}")
    

    Solution: The final 4-digit number read off the cube is 5189.

    The first number read off the cube is 7921 = 89².

    The second number read off the cube is 5625 = 75² (actually the faces we see are 5, 6, 2, 1, 5, but the 4th digit is not recorded).

    The third number read off the cube is 1568 = 2×28².

    The faces of the cube (at the start) are (U, D) = (6, 1), (L, R) = (8, 5), (F, B) = (7, 2).

    The program produces two solutions one using the pattern “6” (one way up) and one using the pattern “9” (the other way up). If we didn’t allow pattern “9” (because it is the same as pattern “6”) the program would produce a single solution (you can remove the declaration for digits[9] at line 22 to see this).

    You can also modify the declaration for digits[0] to have it read 0 in any orientation, but that gives no additional solutions.

  2. Hugh Casement 16 September 2016 at 8:05 am

    I reckoned to have found a solution with a cube made up from this net:
    0
    1  8  9  5
    2
    (i.e. 0 on the top face, 2 on the bottom).

    The numbers that came up were 1521, 2601, 1568.
    Did I make a mistake somewhere?

    • Jim Randell 16 September 2016 at 11:42 pm

      @Hugh: I think this is quite a difficult puzzle, and it’s easy to get lost when following the instructions. I ended up making a paper cube to check I’d got a working solution.

      You should find four 4-digit numbers, not three, so one of them is missing somewhere.

      Also 1521 cannot be the first 4-digit number read off, as the sequence: “look; bottom twist; look; bottom twist; look; bottom twist; look” records faces: Front, Up, Back, Down, and as all the faces have different digits on we can’t record 1 from both the Front and Down faces (regardless of their orientation).

      The second 4-digit number does visit the same face twice, so 1521 could be that number, but if the cube you give is set up to give 1521 as the second number the first number read off would have to have been 0528, which isn’t a square (and also starts with a zero).

      So I think you must have gone wrong somewhere in your solution.

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: