Enigmatic Code

Programming Enigma Puzzles

Tantalizer 496: Anky panky

From New Scientist #1047, 14th April 1977 [link]

Having unearthed a thriving protection racket in the nursery class, Miss Marple summoned the mothers of the six boys concerned to a friendly little chat. She settled the embarrassed ladies equidistantly round a circular table, while she herself paced about lecturing them.

The seating is what concerns us. On Pam’s right sat Mrs Fagin, mother of Yvor. Xerxes’ mum had Ulrich’s mum, Rhona, on her right and Sylvia on her left. Vince’s mum was on Pam’s left and opposite Sylvia. Willy’s mum was opposite Queenie, who sat on Mrs Armstrong’s right. Zacharia’s mother was opposite Mrs Capone. Tess sat opposite Mrs Ellis. Olive was on Mrs Diamond’s left.

Only Mrs Borgia had the guts to blame the whole thing on the school. Can you discover her first name?

[tantalizer496]

Advertisements

2 responses to “Tantalizer 496: Anky panky

  1. Jim Randell 14 December 2016 at 7:59 am

    I made a CircularList() class that behaves like a list, but it’s elements are accessed mod n (where n is the length of the list). Then we don’t have to worry about wrapping around the indices ourselves, and from s[i] we can move left to s[i + 1], right to s[i − 1] and opposite to s[i + 3] (for a circular list of length 6).

    This Python program considers all possible arrangements and runs in 196ms.

    from itertools import permutations
    from enigma import printf
    
    # implement a circular list
    class CircularList(list):
    
      def __getitem__(self, i):
        return list.__getitem__(self, i % len(self))
    
    
    # the last names
    last = tuple('ABCDEF')
    
    # the mum's first names
    mums = tuple('OPQRST')
    
    # the boy's first names
    boys = tuple('UVWXYZ')
    
    # consider possible positions for last names
    for ls in permutations(last[1:]):
      ls = CircularList(last[:1] + ls)
    
      # consider possible positions for the boys's names
      for bs in permutations(boys):
        bs = CircularList(bs)
    
        # "Mrs F is mother of Y"
        if ls[bs.index('Y')] != 'F': continue
    
        # "X's mum had U's mum on her right"
        if bs[bs.index('X') - 1] != 'U': continue
    
        # "Z's mother was opposite Mrs C"
        if ls[bs.index('Z') + 3] != 'C': continue
    
        # consider possible positions for the mum's names
        for ms in permutations(mums):
          ms = CircularList(ms)
    
          # "On P's right sat Mrs F"
          if ls[ms.index('P') - 1] != 'F': continue
    
          # "U's mum is R"
          if ms[bs.index('U')] != 'R': continue
    
          # "X's mum had S on her left"
          if ms[bs.index('X') + 1] != 'S': continue
    
          # "V's mum was on P's left and opposite S"
          if bs[ms.index('P') + 1] != 'V': continue
          if bs[ms.index('S') + 3] != 'V': continue
    
          # "W's mum was opposite Q"
          if ms[bs.index('W') + 3] != 'Q': continue
    
          # "Q sat on Mrs. A's right"
          if ms[ls.index('A') - 1] != 'Q': continue
    
          # "T sat opposite Mrs E"
          if ms[ls.index('E') + 3] != 'T': continue
    
          # "O was on Mrs. D's left"
          if ms[ls.index('D') + 1] != 'O': continue
    
          # accumulate solution as a list of (<last>, <first>, <child>)
          r = list(zip(ls, ms, bs))
          # and determine the first name of B
          f = list(x[1] for x in r if x[0] == 'B')[0]
          printf("Mrs B = {f} {r}")
    

    Solution: Mrs Borgia’s first name is Queenie.

    There are two arrangements that work, these are (going round the table in clockwise order, starting with Mrs Armstrong):

    Rhona Armstrong, mother of Ulrich,
    Tess Capone, mother of Xerxes,
    Sylvia Diamond, mother of Willy,
    Olive Fagin, mother of Yvor,
    Pam Ellis, mother of Zacharia,
    Queenie Borgia, mother of Vince.

    and:

    Sylvia Armstrong, mother of Zacharia,
    Tess Fagin, mother of Yvor,
    Pam Diamond, mother of Willy,
    Olive Capone, mother of Vince,
    Rhona Ellis, mother Ulrich,
    Queenie Borgia, mother of Xerxes.

  2. Jim Randell 14 December 2016 at 1:48 pm

    And here’s a solution using a MiniZinc model.

    include "globals.mzn";
    
    % label the positions 0 to 5
    
    % last names
    var 0..5: A;
    var 0..5: B;
    var 0..5: C;
    var 0..5: D;
    var 0..5: E;
    var 0..5: F;
    
    constraint all_different([A, B, C, D, E, F]);
    
    
    % mum's first names
    var 0..5: O;
    var 0..5: P;
    var 0..5: Q;
    var 0..5: R;
    var 0..5: S;
    var 0..5: T;
    
    constraint all_different([O, P, Q, R, S, T]);
    
    
    % boy's first names
    var 0..5: U;
    var 0..5: V;
    var 0..5: W;
    var 0..5: X;
    var 0..5: Y;
    var 0..5: Z;
    
    constraint all_different([U, V, W, X, Y, Z]);
    
    % place Mrs A in position 1
    constraint A == 1;
    
    % "On P's right sat Mrs. F, mother of Y
    constraint (F + 1) mod 6 == P;
    constraint F == Y;
    
    % "X's mum has U's mum, R, on her right and S on her left"
    constraint (U + 1) mod 6 == X;
    constraint U == R;
    constraint (X + 1) mod 6 == S;
    
    % "V's mum was on P's left and opposite S"
    constraint (P + 1) mod 6 == V;
    constraint (V + 3) mod 6 == S;
    
    % "W's mum was opposite Q, who sat on Mrs A's right"
    constraint (W + 3) mod 6 == Q;
    constraint (Q + 1) mod 6 == A;
    
    % "Z's mother was opposite Mrs C"
    constraint (Z + 3) mod 6 == C;
    
    % "T sat opposite Mrs E"
    constraint (T + 3) mod 6 == E;
    
    % "O was on Mrs D's left"
    constraint (D + 1) mod 6 == O;
    
    solve satisfy;
    

    It can be run directly as a MiniZinc model, or you can using the minizinc.py wrapper to provide formatting of the solutions from Python. The following program runs in 153ms.

    from enigma import irange, printf
    from minizinc import MiniZinc
    
    # create the minizinc model
    m = MiniZinc("tantalizer496.mzn")
    
    # solve it
    for s in m.solve():
      # accumulate (<last>, <mum>, <boy>) by position
      r = list(sorted(k for (k, v) in s.items() if v == i) for i in irange(0, 5))
      # and determine the first name of B
      f = list(x[1] for x in r if x[0] == 'B')[0]
      printf("Mrs B = {f} {r}")
    

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: