Enigmatic Code

Programming Enigma Puzzles

Enigma 1720: Tables seating four

From New Scientist #2887, 20th October 2012 [link]

Russian peasants were said to perform multiplication knowing only how to add, and to multiply and divide by 2. I showed my niece how to multiply 25 by 31 by this method, as shown in the first box.

In the left column, the numbers are divided by 2 successively, any resulting halves being ignored, until 1 is reached. The right column consists of an equal number of values, each after the initial 31 being double the previous one. A simple rule, which I left my niece to discover, tells us which of the values in the right column we must add to get the required total of 775.

My brother-in-law then sent me the following problem, which uses the above method to multiply p by P, and which, with the relevant addition, gives the correct result, ENIGMA, where each of these six letters represents a different non-zero digit. He has inserted a 4 wherever it occurs in the calculation, leaving all other place-holders unspecified, as shown in the second box.

What is ENIGMA?

Just to be clear: The left column starts with p (lower case), and the right column starts with P (upper case).

[enigma1720]

Advertisements

3 responses to “Enigma 1720: Tables seating four

  1. Jim Randell 17 October 2012 at 5:25 pm

    The following Python program runs in 48ms.

    from itertools import product
    from enigma import irange, printf
    
    # the 2nd column on the left is *4 = 10a + 4 for some digit a (not 0 or 4)
    # so p is 20a + 8 or 20a + 9
    
    # p is 3-digit, but p // 2 is 2-digit, so a > 4
    for (a, b) in product((5, 6, 7, 8, 9), (8, 9)):
      p = 20 * a + b
    
      # compute the repeated floor division by 2
      (ps, n) = ([], p)
      while True:
        ps.append(str(n))
        if n == 1: break
        n //= 2
    
      # check the digit count
      if tuple(len(n) for n in ps) != (3, 2, 2, 2, 1, 1, 1): continue
    
      # and there should be no 4s in any of them (except ps[1])
      if any('4' in n for (i, n) in enumerate(ps) if i != 1): continue
    
      # P is a 4 digit number (but 2P is 5-digit)
      for P in irange(5000, 9999):
        # ENIGMA = p * P
        ENIGMA = str(p * P)
        # ENIGMA is 6-digit
        if len(ENIGMA) > 6: break
        # and they are all different and non-zero
        if '0' in ENIGMA: continue
        if len(set(ENIGMA)) != 6: continue
    
        # create repeated multiples of 2
        Ps = list(str(P * 2 ** i) for i in range(len(ps)))
    
        # check the digit count
        if tuple(len(n) for n in Ps) != (4, 5, 5, 5, 6, 6, 6): continue
    
        # and there should be no 4s in any of them (except Ps[4])
        if Ps[4][4] != '4': continue
        if Ps[4][5] == '4' or '4' in Ps[4][0:4]: continue
        if any('4' in n for (i, n) in enumerate(Ps) if i != 4): continue
        
        printf("ENIGMA = {ENIGMA} [p={ps} P={Ps}]", ps=','.join(ps), Ps=','.join(Ps))
    

    Solution: ENIGMA = 862735.

  2. arthurvause 17 October 2012 at 6:48 pm

    That was a fiddly one

    BIGP=[]
    for P in range(6250,10000):
      OK = not ('4' in set(str(P)))
      test=P
      for n in range(6):
        test*=2
        OK = OK and ((n==3 and (test%100 in range(40,50)) and (test%10 != 4)
                      and not('4' in set(str(test//1000))))
             or (n!=3 and not('4' in set(str(test)))))
      if OK:
        BIGP.append(P)
    
    littlep=[] 
    for p in range(100,160):
      OK = not ('4' in set(str(p)))
      test=p
      for n in range(6):
        test//=2
        OK = OK and ((n==0 and not('4' in set(str(test//4))) and (test%10==4) )
             or (n!=0 and not('4' in set(str(test)))))
      if OK:
        littlep.append(p)
    
    for BP in BIGP:
      for lp in littlep:
        enigma=lp*BP
        if len(set(str(enigma)))==6 and enigma<1000000 and not ('0' in set(str(enigma))):
          print BP, lp, enigma
    
  3. Brian Gladman 17 October 2012 at 11:08 pm

    Here is my version:

    # The last (lowest) digit on the left has to be 1 so
    # working upwards the maximum starting number on the
    # left is 127.  To give the 4 in the second row this
    # number has to have an even 10's digit with a units
    # digit of 8 or 9.  Hence 108 or 109.
    for left_0 in (108, 109):
    # the initial left column number
    
      # to reach a six diigit number in 4 doublings
      # gives a minimum initial number in the right
      # hand column of 6250
      for right_0 in range(6250, 10000):
        left, right, total, cnt  = left_0, right_0, 0, 0
    
        # the loop for the Russian Peasant process
        while left:
    
          # check that there is only the one specified
          # 4 in the left column
          s = str(left)
          if cnt == 1:
            if s.count('4') != 1:
              break
          elif '4' in s:
            break
    
          # check that there is only the one specified
          # 4 in the right column
          s = str(right)
          if cnt == 4:
            if s.count('4') != 1 or s[-2] != '4':
              break
          elif '4' in s:
            break
    
          # add to total if the left number is odd
          if left & 1:
            total += right
          # compute the values for the next row
          left //= 2
          right += right
          cnt += 1
    
        else:
    
          # check that ENIGMA has six different non-zero digits
          s = str(total)
          if '0' not in s and len(set(s)) == 6:
            print('ENIGMA = {:d}'.format(total))
    

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: