# Enigma (Tantaliser 482)

```Hi Jim,

I woke up this morning realising that my published code for this
tantaliser is not very good.

I would hence be most grateful if you could substitute the attached version.

best regards,

Brian
-------------- next part --------------

from itertools import combinations, permutations, product

# enumerate the names
A, B, C, D, E, F, G = range(7)
nms = dict(enumerate(('Alice', 'Beatrice', 'Constance', 'Deborah',
'Emily', 'Flavia', 'Gertrude')))
# enumerate the sins
an, av, en, it, lu, pr, sl = range(7)
sns = dict(enumerate(('anger', 'avarice', 'envy', 'intemperance',
'lust', 'pride', 'sloth')))

# all seven sins occur among Beatrice, Deborah, Emily, Gertrude so
# we have the following arrangement of unknown sins (*), which must
# be permutations of anger, avarice, envy, intemperance and pride
#   Beatrice: *, *
#   Deborah: lust, *
#   Emily: lust, *
#   Gertrude: sloth, *
s1 = {an, av, en, it, pr}
sol_g1 = set()
for p in permutations(s1, 3):
# the set of sins for Beatrice, Deborah, Emily and Gertrude
tb, td, te, tg = s1.difference(p), {lu, p}, {lu, p}, {sl, p}
sol_g1.add(tuple(frozenset(x) for x in (tb, td, te, tg)))

# the arrangement of unknown sins among Alice, Constance and Flavia is:
#   Alice: sloth, *
#   Constance: anger, *
#   Flavia: *, *
# since each sin occurs against two names, there are 14 sins among all
# seven names; the first group above has all seven sins plus lust, so
# this group must have all seven sins minus lust; so the four unknowns
# here must be permutations of avarice, envy, intemperance and pride
s2 = {av, en, it, pr}
sol_g2 = set()
for q in permutations(s2, 2):
# the set of sins for Alice, Constance and Flavia
ta, tc, tf = {sl, q}, {an, q}, s2.difference(q)
sol_g2.add(tuple(frozenset(x) for x in (ta, tc, tf)))

for (tb, td, te, tg), (ta, tc, tf) in product(sol_g1, sol_g2):
# map names to pairs of sins
p2s = dict(zip(range(7), (ta, tb, tc, td, te, tf, tg)))

# Constance, Emily and Flavia have no sin shared by any pair
if any(p2s[x] & p2s[y] for x, y in combinations((C, E, F), 2)):
continue

if not (sl in p2s[A] and sl in p2s[G] and lu in p2s[D] and lu in p2s[E]):
continue

# Alice is not proud and Beatrice is not avaricious
if pr in p2s[A] or av in p2s[B]:
continue

# Flavia is neither intemperate nor proud
if p2s[F].intersection([it, pr]):
continue

# Deborah shows no anger; Constance and Deborah share a sin
if an in p2s[D] or not p2s[C] & p2s[D]:
continue

u = [nms[x] for x in range(7) if it in p2s[x]]
v = [nms[x] for x in range(7) if en in p2s[x]]
print('Intemperance: {} and {}; Envy: {} and {}.'.format(*u, *v))
print()
for n in range(7):
print('{}: {}, {}'.format(nms[n], *(sns[s] for s in sorted(p2s[n]))))

```