New Scientist Enigma 999 – Combined Celebrations
by Susan Denham
From Issue #2154, 3rd October 1998
To celebrate next week’s 1000th edition of Enigma, we each made up an Enigma. Each one consisted of four clues leading to its own unique positive whole number answer. In each case none of the four clues was redundant. To avoid duplication, Keith made up his Enigma first and showed it to Susan before she made up hers.
The two Enigmas were meant to be printed sidebyside but the publishers have made a (rare) error and printed the clues in a string:
(A) It is a threefigure number;
(B) It is less than a thousand;
(C) It is a perfect square;
(D) It is a perfect cube;
(E) It has no repeated digits;
(F) The sum of its digits is a perfect square;
(G) The sum of its digits is a perfect cube;
(H) The sum of all the digits which are odd in Keith’s
answer is the same as the sum of all the digits
which are odd in Susan’s.
Which four clues should have formed Keith’s Enigma, and what was the answer to Susan’s?

Brian Gladman permalink123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051from itertools import combinations# check that four given conditions result in only# one solution for numbers in the range 0..max_ndef solve(c, xc=None, max_n=1000):sol = Nonefor n in range(1, max_n):dgts = tuple(int(d) for d in str(n))sd = sum(dgts)if ('A' in c and not 100 <= n < 1000 or'B' in c and not n < 1000 or'C' in c and not round(n ** (1 / 2)) ** 2 == n or'D' in c and not round(n ** (1 / 3)) ** 3 == n or'E' in c and not len(dgts) == len(set(dgts)) or'F' in c and not round(sd ** (1 / 2)) ** 2 == sd or'G' in c and not round(sd ** (1 / 3)) ** 3 == sd or'H' in c and not xc == sum(d for d in dgts if d & 1)):continue# a solution already exists for this value so this set# of conditions does not give a single resultif sol:return Nonesol = (n, sum(d for d in dgts if d & 1))# the correct set of conditions give a single solutionreturn solfor ck in combinations('ABCDEFG', 4):# Keith has either clue 'A' or 'B' but not bothif ('A' in ck) == ('B' in ck):continue# find four clues for Keith that give one solutionsk = solve(ck)if sk:# all clues are needed so there cannot be a single solution# if any of the clues are omitted (note that if clue B or C# are omitted the numbers can be larger than 1000)if any(solve(tuple(c for c in ck if c != r), max_n=1100) for r in ck):continuenk, dk = sk# extract the clues for Susan and look for a solutioncs = tuple(c for c in 'ABCDEFGH' if c not in ck)ss = solve(cs, dk)if ss:# check that all the clues are necessaryif any(solve(tuple(c for c in cs if c != r), dk, 1100) for r in cs):continuens, ds = sscc, ss = f"{''.join(ck)} ==> {nk}", f"{''.join(cs)} ==> {ns}"print(f"Keith's clues are {cc}; Susan's clues are {ss}.")