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

### 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))
```