Enigmatic Code

Programming Enigma Puzzles

Enigma 273: Moral choices

From New Scientist #1420, 6th September 1984 [link]

The campaign to Brace Up Moral Standards is run by a six-person committee, who elect a president from among themselves. Each person casts three votes. On the last occasion each voted for three persons and each person totalled a different number of votes.

Lord Luvaduck Love finished higher than Miss Marriage, who voted for herself. Tansy Tickell, the romantic novelist, fared better than the Reverend Cuthbert Custard, who did not vote for himself. Peregrine Prunes voted for Miss Marriage. Sylvia Slap, the agony aunt, voted for herself. Love did not vote for Tickell. No one votes for Love and Marriage; no one for Slap and Tickell; and no one for Prunes and Custard.

How many votes did each of these bracing persons receive?



3 responses to “Enigma 273: Moral choices

  1. Jim Randell 15 April 2015 at 8:49 am

    This Python program examines all possible combinations of votes. It runs in 1.3s.

    from itertools import product
    from collections import Counter
    from enigma import irange, concat, printf
    # no-one votes for (L and M) or (S and T) or (P and C),
    # so every one votes for (L or M) and (S or T) and (P and C)
    (L, M, S, T, P, C) = names = 'LMSTPC'
    # accumulate results
    r = Counter()
    for votes in product(product(L + M, S + T, P + C), repeat=6):
      # determine the votes
      votes = dict((x, concat(*v)) for (x, v) in zip(names, votes))
      # M voted for herself
      if M not in votes[M]: continue
      # C did not vote for himself
      if C in votes[C]: continue
      # P voted for M
      if M not in votes[P]: continue
      # S voted for herself
      if S not in votes[S]: continue
      # L did not vote for T
      if T in votes[L]: continue
      # determine the totals
      totals = dict((x, sum(1 for v in votes.values() if x in v)) for x in names)
      # L got more votes than M
      if not(totals[L] > totals[M]): continue
      # T got more votes than C
      if not(totals[T] > totals[C]): continue
      # totals are distinct
      if not(len(set(totals.values())) == 6): continue
      # record the results
      r[tuple(totals[x] for x in names)] += 1
      printf("[votes: {votes}, totals: {totals}]", votes=' '.join(x + '=' + votes[x] for x in names), totals=' '.join(x + '=' + str(totals[x]) for x in names))
    # output the results
    for (k, v) in r.most_common():
      printf("{k} [{v} solutions]", k=' '.join(x + '=' + str(y) for (x, y) in zip(names, k)))

    Solution: Prunes received 6 votes. Slap received 5 votes. Love received 4 votes. Marriage received 2 votes. Tickell received 1 vote. Custard received no votes.

    There are 4 possible voting patterns: L voted for L+S+P; M voted for M+P; S voted for L+S+P; T voted for L+P; P voted for M+P; C voted for L+P. Then from the remaining votes cast by M, T, P and C, one of them voted for T and the rest of them voted for S.

    • Jim Randell 15 April 2015 at 9:04 am

      Here’s the problem expressed as a set of constraints in a MiniZinc model. It runs finds the four solutions in 77ms (mzn-gecode -a enigma273.mzn).

      include "globals.mzn";
      % identify the candidates
      set of int: Candidates = 1..6;
      int: L = 1;
      int: M = 2;
      int: S = 3;
      int: T = 4;
      int: P = 5;
      int: C = 6;
      array[Candidates] of string: name = [ "L", "M", "S", "T", "P", "C" ];
      % votes
      array[Candidates, Candidates] of var bool: votes;
      % each person casts three votes
      constraint forall (i in Candidates) (sum (j in Candidates) (votes[i, j]) == 3);
      % totals
      array[Candidates] of var 0..6: total;
      constraint forall (i in Candidates) (total[i] == sum (j in Candidates) (votes[j, i]));
      % the totals are all different
      constraint alldifferent(total);
      % L got more votes than M
      constraint total[L] > total[M];
      % M voted for herself
      constraint votes[M, M] == true;
      % T got more votes than C
      constraint total[T] > total[C];
      % C did not vote for himself
      constraint votes[C, C] == false;
      % P voted for M
      constraint votes[P, M] == true;
      % S voted for herself
      constraint votes[S, S] == true;
      % L did not vote for T
      constraint votes[L, T] == false;
      % no-one votes for L and M
      constraint forall (i in Candidates) (not (votes[i, L] /\ votes[i, M]));
      % no-one votes for S and T
      constraint forall (i in Candidates) (not (votes[i, S] /\ votes[i, T]));
      % no-one votes for P and C
      constraint forall (i in Candidates) (not (votes[i, P] /\ votes[i, C]));
      % solve the problem
      solve satisfy;
      % output the solution
      output [
       "L: " ++ show([votes[L, i] | i in Candidates]) ++ "\n" ++
       "M: " ++ show([votes[M, i] | i in Candidates]) ++ "\n" ++
       "S: " ++ show([votes[S, i] | i in Candidates]) ++ "\n" ++
       "T: " ++ show([votes[T, i] | i in Candidates]) ++ "\n" ++
       "P: " ++ show([votes[P, i] | i in Candidates]) ++ "\n" ++
       "C: " ++ show([votes[C, i] | i in Candidates]) ++ "\n" ++
       "total: " ++ show(total)
  2. arthurvause 18 April 2015 at 10:37 pm

    From the puzzle constraints, it is easy to deduce that
    totals for the candidates have to be 0,1,2,4,5,6
    L+M = S+T = P+C = 6

    So, some code:

    from itertools import product, permutations
    for p in permutations( ( (0,6),(1,5),(2,4) ) ):
      for L,S,P in product(*p):
        M,T,C = 6-L,6-S,6-P
        if 6>L>M>1 and 5>T>C and S>0 :
          print L, M, S, T, P, C

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: