# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1763: Clever spells

From New Scientist #2931, 24th August 2013 [link]

Eve said to me that she had in mind an even three-figure number that was divisible by 3. She also told me that she had spelled out the number in words and that she had counted the number of letters used. Knowing the number of letters would enable me to work out her number, she said.

Oddy said to me that he had in mind an odd three-figure number divisible by 3. He told me that he, too, had written the number in words and that he had counted the number of letters used. He said that knowing the number of letters would again enable me to work out his number.

Then the two of them had a little chat and announced that their numbers had no digit in common.

What were their numbers?

[enigma1763]

### 2 responses to “Enigma 1763: Clever spells”

1. Jim Randell 21 August 2013 at 6:19 pm

A straightforward approach in Python (using the int2words() function from the enigma.py library originally written for Enigma 1614) give the answer in a reasonable time. This code runs in 35ms.

```from collections import defaultdict
from itertools import product
from enigma import irange, int2words, printf

# accumulate results by parity and letter count
r = (defaultdict(list), defaultdict(list))
for n in irange(102, 999, step=3):
c = sum(1 for x in int2words(n) if x.isalpha())
r[n % 2][c].append(str(n))

# find unique even and odd numbers
ns = list(set(v[0] for (k, v) in r[p].items() if len(v) == 1) for p in (0, 1))

# and find (even, odd) pairs with no digit in common
for (even, odd) in product(*ns):
if set(even).intersection(odd): continue
printf("even = {even}, odd = {odd}")
```

Solution: Eve’s number was 378. Oddy’s number was 201.

2. Brian Gladman 21 August 2013 at 8:54 pm

Mine is pretty similar in principle:

```from int_as_words import int_as_words
from itertools import product

# dictionaries for the even and odd numbers
even, odd = {}, {}
# consider numbers divisible by three in 100 .. 1000
for n in range(102, 1000, 3):
# convert to words
length = len(int_as_words(n).replace(' ', ''))
# if a number of this length has already been seen in the even or
# odd directory, falsify the entry, otherwise add this number
if n % 2:
odd[length] = False if length in odd else n
else:
even[length] = False if length in even else n

# now find all combinations of Eve's and Oddy's numbers
for eve, odd in product( (nbr for ln, nbr in even.items() if nbr),
(nbr for ln, nbr in odd.items() if nbr) ):
# and find those that don't share any letters
if not (set(str(eve)) & set(str(odd))):
print('Their numbers were {:d} and {:d}.'.format(eve, odd))
```

but it uses my own ‘number_as_words’ routine:

```# convert number to word form for numbers less than 10 ** 36
l_lo = ( '', 'one', 'two', 'three', 'four', 'five', 'six', 'seven',
'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen',
'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen',
'nineteen' )
l_10 = ( 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy',
'eighty', 'ninety')
l_hi = ( ' thousand', ' m', ' b', ' tr', ' quadr', ' quint',
' sext', ' sept', ' oct', ' non', ' dec' )

def int_as_words(x, commas=True, l=0):
if x >= 10 ** 36:
raise NotImplementedError
if x < 0:
return 'minus ' + int_to_words(-x)
if x < 20:
return l_lo[x] if x else 'zero'
elif x < 100:
return (l_10[x // 10 - 2] + ('', ' ')[x % 10 > 0] + l_lo[x % 10])
elif x < 1000:
return (l_lo[x // 100] + ' hundred' +
('', ' and ' + int_as_words(x % 100, l))[x % 100 > 0])
else:
t = int_as_words(x // 1000, commas, l + 1)
u = ('', l_hi[l] + ('', 'illion')[l > 0])[(x // 1000) % 1000 > 0]
v = ('', ',')[commas] + (' ', ' and ')[l == 0 and x % 1000 < 100]
v = ('', v + int_as_words(x % 1000, commas, l))[x % 1000 > 0]
return t + u + v
```