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

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.

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