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,

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[0]}, {lu, p[1]}, {sl, p[2]}
  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[0]}, {an, q[1]}, 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)):
  # Alice and Gertrude admit sloth, Deborah and Emily admit lust
  if not (sl in p2s[A] and sl in p2s[G] and lu in p2s[D] and lu in p2s[E]):
  # Alice is not proud and Beatrice is not avaricious
  if pr in p2s[A] or av in p2s[B]:
  # Flavia is neither intemperate nor proud
  if p2s[F].intersection([it, pr]):
  # Deborah shows no anger; Constance and Deborah share a sin 
  if an in p2s[D] or not p2s[C] & p2s[D]:
  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))
  for n in range(7):
    print('{}: {}, {}'.format(nms[n], *(sns[s] for s in sorted(p2s[n]))))

Reply via email to