Enigmatic Code

Programming Enigma Puzzles

Enigma 1060: In order to solve…

From New Scientist #2216, 11th December 1999 [link]

I have a row of 8 boxes labelled A, B, C, …, H. Each box contains a card with a number on it. The contents of the boxes are one of the following 17 possibilities:

13683641, (that is, 1 in A, 3 in B, 6 in C, …, 1 in H)
14187438,
15286227,
22832116,
24216228,
27255464,
33717335,
47644974,
51368742,
58161493,
61236227,
66787332,
75592512,
78893173,
82625966,
85371799,
93612651.

And here are four more facts:

P. Given the above facts, if I now tell you the number in box A then you can work out the number in box D.

Q. Given the above facts, if I now tell you the number in box B then you can work out the number in box H.

R. Given the above facts, if I now tell you the number in box F then you can work out the number in box C.

S. Given the above facts, if I now tell you the number in box G then you can work out the number in box E.

Unfortunately, I have forgotten what order the for facts P, Q, R, S should be in. I do remember that when they are in the right order you can work out the contents of the boxes. Also that there is only one order that allows you to do that.

What order should the four facts be in? And what are the contents of the boxes?

[enigma1060]

2 responses to “Enigma 1060: In order to solve…

  1. Jim Randell 28 May 2018 at 9:08 am

    We can use the filter_unique() function from the enigma.py library to solve this puzzle.

    This Python program runs in 77ms.

    Run: [ @repl.it ]

    from itertools import permutations
    from enigma import filter_unique, printf
    
    candidates = [
      (1, 3, 6, 8, 3, 6, 4, 1),
      (1, 4, 1, 8, 7, 4, 3, 8),
      (1, 5, 2, 8, 6, 2, 2, 7),
      (2, 2, 8, 3, 2, 1, 1, 6),
      (2, 4, 2, 1, 6, 2, 2, 8),
      (2, 7, 2, 5, 5, 4, 6, 4),
      (3, 3, 7, 1, 7, 3, 3, 5),
      (4, 7, 6, 4, 4, 9, 7, 4),
      (5, 1, 3, 6, 8, 7, 4, 2),
      (5, 8, 1, 6, 1, 4, 9, 3),
      (6, 1, 2, 3, 6, 2, 2, 7),
      (6, 6, 7, 8, 7, 3, 3, 2),
      (7, 5, 5, 9, 2, 5, 1, 2),
      (7, 8, 8, 9, 3, 1, 7, 3),
      (8, 2, 6, 2, 5, 9, 6, 6),
      (8, 5, 3, 7, 1, 7, 9, 9),
      (9, 3, 6, 1, 2, 6, 5, 1),
    ]
    
    # facts P, Q, R, S (as indices (i, j) "i implies j")
    facts = dict(P=(0, 3), Q=(1, 7), R=(5, 2), S=(6, 4))
    
    # selector function for element i of a sequence
    select = lambda i: (lambda x: x[i])
    
    # check candidates against the sequence of facts fs
    def check(fs, cs=candidates):
      for f in fs:
        (i, j) = facts[f]
        (cs, _) = filter_unique(cs, select(i), select(j))
        if not cs: return
      return cs
    
    # consider possible orderings of the facts
    # and record (order, boxes) pairs
    rs = list()
    for fs in permutations(facts.keys()):
      cs = check(fs)
      # if we get a single candidate
      if cs and len(cs) == 1:
        # record output orderings, and box contents
        printf("[order = {fs}, boxes = {cs[0]}]")
        rs.append((fs, cs[0]))
    
    # but there is only one ordering that gives a unique solution
    # so if we knew the contents of the boxes we could determine the ordering
    (rs, _) = filter_unique(rs, select(1), select(0))
    
    # output solutions
    for (fs, boxes) in rs:
      printf("order = {fs}, boxes = {boxes}")
    

    Solution: The facts should be in order R, P, Q, S. The contents of the 8 boxes are: A=5, B=1, C=3, D=6, E=8, F=7, G=4, H=2.

    There are three other orderings that narrow the candidates down to a single possibility:

    order: S, Q, R, P; boxes: A=8, B=2, C=6, D=2, E=5, F=9, G=6, H=6
    order: S, R, Q, P; boxes: A=8, B=2, C=6, D=2, E=5, F=9, G=6, H=6
    order: R, S, Q, P; boxes: A=8, B=2, C=6, D=2, E=5, F=9, G=6, H=6

    But these all narrow the candidate list down to the same possibility, so can be discarded, as in the correct scenario there is only a single order that works.

    • Jim Randell 29 May 2018 at 3:44 pm

      Here’s a simple program to demonstrate that considering the statements in the order R, P, Q, S, does indeed give a single answer:

      # a demonstration of the solution
      
      from enigma import filter_unique, printf
      
      candidates = [
        (1, 3, 6, 8, 3, 6, 4, 1),
        (1, 4, 1, 8, 7, 4, 3, 8),
        (1, 5, 2, 8, 6, 2, 2, 7),
        (2, 2, 8, 3, 2, 1, 1, 6),
        (2, 4, 2, 1, 6, 2, 2, 8),
        (2, 7, 2, 5, 5, 4, 6, 4),
        (3, 3, 7, 1, 7, 3, 3, 5),
        (4, 7, 6, 4, 4, 9, 7, 4),
        (5, 1, 3, 6, 8, 7, 4, 2),
        (5, 8, 1, 6, 1, 4, 9, 3),
        (6, 1, 2, 3, 6, 2, 2, 7),
        (6, 6, 7, 8, 7, 3, 3, 2),
        (7, 5, 5, 9, 2, 5, 1, 2),
        (7, 8, 8, 9, 3, 1, 7, 3),
        (8, 2, 6, 2, 5, 9, 6, 6),
        (8, 5, 3, 7, 1, 7, 9, 9),
        (9, 3, 6, 1, 2, 6, 5, 1),
      ]
      
      # selector function for element i of a sequence
      select = lambda i: (lambda x: x[i])
      
      def statement(n, i, j, rs):
        before = len(rs)
        (rs, _) = filter_unique(rs, select(i), select(j))
        after = len(rs)
        letters = "ABCDEFGH"
        printf("[statement {n}: \"{i} -> {j}\", candidates: {before} -> {after}]", i=letters[i], j=letters[j])
        return rs
      
      # start with the full candidate list
      rs = candidates
      
      # 1. (R): "F -> C"
      rs = statement("R", 5, 2, rs)
      
      # 2. (P): "A -> D"
      rs = statement("P", 0, 3, rs)
      
      # 3. (Q): "B -> H"
      rs = statement("Q", 1, 7, rs)
      
      # 4. (S): "G -> E"
      rs = statement("S", 6, 4, rs)
      
      # output solutions
      for boxes in rs:
        printf("boxes = {boxes}")
      

      From the initial 17 candidates, statement R narrows the list down to 14. Then statement P further narrows it down to 8. Statement Q to 3. And finally statement S to a single answer.

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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: