# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1743: Order, order!

From New Scientist #2911, 6th April 2013 [link]

I have written down a list of four positive whole numbers in increasing order. They are all less than 100, and no two of them have a common factor greater than 1. If I write the numbers in words, then each begins with a different letter of the alphabet and my list is also in alphabetical order. If I tripled the numbers, then the answers would be in reverse alphabetical order when written in words. If I then doubled those answers, the resulting numbers, when written in words, would be in alphabetical order once again.

What is my list of numbers?

Enigma 1388 is also called “Order, order!”

[enigma1743]

### 3 responses to “Enigma 1743: Order, order!”

1. Jim Randell 3 April 2013 at 6:48 pm

This Python program runs in 409ms. It uses the [[ `number_to_words()` ]] function written for Enigma 1614.

```from enigma import factor

numbers = {
0: 'zero',
1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine',
10: 'ten', 11: 'eleven', 12: 'twelve', 13: 'thirteen', 15: 'fifteen', 18: 'eighteen'
}

tens = {
1: 'teen', 2: 'twenty', 3: 'thirty', 4: 'forty', 5: 'fifty', 6: 'sixty', 7: 'seventy', 8: 'eighty', 9: 'ninety'
}

def number_to_words(n):
if n in numbers:
return numbers[n]
if n < 20:
return numbers[n % 10] + tens
if n < 100:
(d, r) = divmod(n, 10)
x = tens[d]
return x + ' ' + numbers[r] if r else x
if n < 1000:
(d, r) = divmod(n, 100)
x = number_to_words(d) + ' hundred'
return x + ' and ' + number_to_words(r) if r else x
raise NotImplementedError

# generate a sequence of <s> numbers from <a> to <b>
# that share no factors, and written as words are in
# alphabetical order and share no initial letters
# s - length of sequence
# a, b - range of numbers (from a up to, but not including b)
# ft - factors already used
# wt - last word (if defined)
def generate(s, a, b, ft, wt):
if s == 0:
yield []
else:
for n in range(a, b):
f = set(factor(n))
if f.intersection(ft): continue
w = number_to_words(n)
if wt and not(w > wt and w > wt): continue
for ns in generate(s - 1, n + 1, b, ft.union(f), w):
yield [n] + ns

# find a sequence of 4 numbers satisfying the conditions
for s in generate(4, 1, 100, set(), None):
# 3x the numbers are in reverse alphabetical order
s3 = list(number_to_words(3 * x) for x in s)
if s3 != sorted(s3, reverse=True): continue
# and 6x the numbers are in normal alphabetical order
s6 = list(number_to_words(6 * x) for x in s)
if s6 != sorted(s6): continue

print(s, s3, s6)
```

Solution: The original list of numbers is 8, 15, 19, 29.

• Jim Randell 4 April 2013 at 9:51 pm

I’ve added my [[ `numbers_to_words()` ]] function to the enigma.py library (renamed as [[ `int2words()` ]]), so here’s a fully recursive program that uses that.

```from enigma import factor, int2words

# generate a sequence of <s> numbers from <a> to <b>
# that share no factors, and written as words are in
# alphabetical order and share no initial letters
# s - length of sequence
# a, b - range of numbers (from a up to, but not including b)
# ft - factors already used
# wt, w3t, w6t - last words (if defined)
def generate(s, a, b, ft, wt=None, w3t=None, w6t=None):
if s == 0:
yield []
else:
for n in range(a, b):
f = set(factor(n))
if f.intersection(ft): continue
w = int2words(n)
if wt and not(w > wt and w > wt): continue
w3 = int2words(3 * n)
if w3t and not(w3 < w3t): continue
w6 = int2words(6 * n)
if w6t and not(w6 > w6t): continue
for ns in generate(s - 1, n + 1, b, ft.union(f), w, w3, w6):
yield [n] + ns

# find a sequence of 4 numbers satisfying the conditions
for s in generate(4, 1, 100, set()):
print(s)
```
2. Brian Gladman 4 April 2013 at 8:44 am

Here is my version:

```# greatest common divisor
def gcd(a, b):
while b > 0:
a, b = b, a % b
return a

# convert number to word form for numbers less than one thousand
l_d1 = ( '', 'one', 'two', 'three', 'four', 'five', 'six',
'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve' )
l_d2 = ( 'thir', 'four', 'fif', 'six', 'seven', 'eigh', 'nine' )
l_d3 = ( 'twen', 'thir', 'for', 'fif', 'six', 'seven', 'eigh', 'nine')

def nbr_to_words(x):
if x < 13:
return l_d1[x] if x else 'zero'
elif x < 20:
return l_d2[x - 13] + 'teen'
elif x < 100:
return l_d3[x // 10 - 2] + 'ty ' + l_d1[x % 10]
else:
return (l_d1[x // 100] + ' hundred' + (' and ' +
nbr_to_words(x % 100) if x % 100 else ''))

# the numbers are a, b, c and d with a < b < c < d
for a in range(100):
# convert multiples of 1, 3 and 6 to words
a1, a3, a6 = tuple(nbr_to_words(m * a) for m in (1, 3, 6))

for b in range(a + 1, 100):
# convert multiples of 1, 3 and 6 to words
b1, b3, b6 = tuple(nbr_to_words(m * b) for m in (1, 3, 6))

# the numbers must be coprime, have different leading letters
# and have multiples with the specified alphabetical orders
if (gcd(b, a) == 1 and b1 != a1
and a1 < b1 and  a3 > b3 and a6 < b6):

for c in range(b + 1, 100):
# convert multiples of 1, 3 and 6 to words
c1, c3, c6 = tuple(nbr_to_words(m * c) for m in (1, 3, 6))

# the numbers must be coprime, have different leading letters
# and have multiples with the specified alphabetical orders
if (gcd(c, a) == gcd(c, b) == 1 and c1 not in (a1, b1)
and b1 < c1 and b3 > c3 and b6 < c6):

# the forth number (d)
for d in range(c + 1, 100):
# convert multiples of 1, 3 and 6 to words
d1, d3, d6 = tuple(nbr_to_words(m * d) for m in (1, 3, 6))

# the numbers must be coprime, have different leading letters
# and have multiples with the specified alphabetical orders
if (gcd(d, a) == gcd(d, b) == gcd(d, c) == 1
and d1 not in (a1, b1, c1)
and c1 < d1 and c3 > d3 and c6 < d6):

# output the numbers and the multiples in words
print((a, b, c, d))
print((a1, b1, c1, d1))
print((a3, b3, c3, d3))
print((a6, b6, c6, d6))
```

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