Brain-Teaser 696: The Browning version
From The Sunday Times, 17th November 1974 [link]
You see, Inspector, the combination of my safe is a six-figure number. In case anyone needed to get into it while I was away, I gave each of my clerks (Atkins, Browning and Clark) one of the two-figure numbers which make up the combination. I also told each the position in the combination of the number of another clerk, but not the number itself.
Browning must have overheard me telling a friend that it is a coincidence that two of these numbers are squares and if you put them together you get a four-figure number that equals the other clerk’s number squared. I remember I also said something about whether or not the combination is divisible by this clerk’s number.
When he was caught, Browning said, “I can’t understand why the alarm went off; I know Clark’s is the first number”. I later realised that what I’d told my friend about whether or not that other number was a factor was wrong, which was lucky for me as Browning had got his own number in the right place.
What was the combination?
This puzzle is included in the book The Sunday Times Book of Brain-Teasers: Book 1 (1980). The puzzle text above is taken from the book.
[teaser696]
Jim Randell 8:43 am on 2 March 2021 Permalink |
This Python program looks for candidate sets of numbers where two of the numbers are 2-digit squares, that when concatenated form a 4-digit square, that is the square of the third number. (I assumed none of the squares had leading zeros).
Once these are found we can construct a list of all possible scenarios, and then select those where B would be able to work out the combination with the information he has (even though one of the pieces of information is in fact incorrect).
Once we find B’s deduced combinations, we can look for actual scenarios that have B’s number in the correct place, but have the correct information, and this will give us the actual combination.
It runs in 49ms.
Run: [ @repl.it ]
from itertools import product from enigma import irange, is_square, subsets, nsplit, nconcat, filter_unique, unpack, printf # collect possible scenarios ss = list() # consider 2 digit numbers for one of the clerks numbers for x in irange(32, 99): # and the square of this gives the other 2 numbers (y, z) = nsplit(x * x, 2, base=100) # both of which are 2-digit squares if not all(n > 9 and is_square(n) for n in (y, z)): continue printf("[{x} -> {y} : {z}]") # consider possible actual combinations (s), and assignments of (x, y, z) to (A, B, C) for (s, (A, B, C)) in product(subsets((x, y, z), size=len, select="P"), repeat=2): ss.append((s, (nconcat(s, base=100) % x == 0), A, B, C)) # B knows his own number, the value of the flag, and that C's number is first # so we can find scenarios where B would think he knew the combination rs = filter_unique( # for all possibilities with C's number first ... filter(unpack(lambda s, f, A, B, C: s[0] == C), ss), # ... knowing B's number and the value of the flag ... unpack(lambda s, f, A, B, C: (B, f)), # ... let's you work out the combination unpack(lambda s, f, A, B, C: s), ).unique # consider possible scenarios for (s, f, A, B, C) in rs: # find the index of B's pair b = s.index(B) # look for candidates with B's number in index b, but flag is the opposite actual = set(s1 for (s1, f1, A1, B1, C1) in ss if s1[b] == B == B1 and f1 != f) # output solution(s) for x in sorted(actual): printf("actual = {x} [B={B} f={f} -> attempt = {s}]")Solution: The combination was 811641.
Fortunately there is only one candidate set of numbers, such that a 4-digit square is composed of the concatenation of two 2-digit squares.
That is: 41² = 1681 = 16:81.
So we know the safe’s combination is some ordering of the numbers (16, 41, 81).
And B overheard this construction, and also (so he thought) whether the combination is divisible by 41 or not.
There are 2 scenarios where B can think he is able to deduce the combination:
In both cases B got his own number in the correct position, but got the other two in the wrong positions, setting off the alarm.
So, in both cases, the actual combination is (81, 16, 41), and 181641 is not divisible by 41.
LikeLike
Frits 11:45 pm on 2 March 2021 Permalink |
from collections import defaultdict from itertools import permutations # 2-digit squares sqs = [x * x for x in range(4, 10)] cands = [] # consider 2 digit numbers for one of the clerks numbers for i in range(32, 100): # and the square of this gives the other 2 numbers i2 = i * i # view <i2> as abcd (ab, cd) = (i2 // 100, i2 % 100) # both of which are 2-digit squares if ab not in sqs or cd not in sqs: continue cands.append([i, ab, cd]) fnum = defaultdict(list) # store info for the first 2-digit number for cand in cands: # uvwxyz is a possible ordering of entries in <cand> for uv, wx, yz in permutations(cand): uvwxyz = 100 * (100 * uv + wx) + yz check = (uvwxyz % cand[0] == 0) # is there both a True and False combination per first 2-digit number? tf = check if uv not in fnum else fnum[uv][0][-1] ^ check fnum[uv].append([uvwxyz, check, tf]) # how many possible numbers are divisible by the first 2-digit number n_divisible = sum(1 for k, vs in fnum.items() for (_, div, _) in vs if div) if n_divisible < 3: print("Browning thinks the combination is divisible by", cand[0]) else: print("Browning thinks the combination is not divisible by", cand[0]) # collect first 2-digit numbers where one of the two 6-digit numbers # is divisible by <cand[0]> and the other isn't both_tf = list({k for k, vs in fnum.items() for (_, _, tf) in vs if tf}) if len(both_tf) == 2: # suppose the two 2-digit numbers in <both_tf> are <p> and <q> # if B was given number <p> and C was given the first number # B has to look at the 6-digit numbers with first digit number <q> for i, p in enumerate(both_tf): # B will choose the other entry for guess, div, _ in fnum[both_tf[1-i]]: # B chose <guess> which didn't open the safe # but B had got his own number <p> in the right place # so we have to switch the other 2-digit numbers if (div and n_divisible < 3) or (not div and n_divisible > 3): s = str(guess) comb = int(s[2:4] + s[:2] + s[4:]) if guess % 100 == p \ else int(s[4:] + s[2:4] + s[:2]) print(f"combination = {comb}, Brown guessed {guess} " f"if he was given number {p}")LikeLike