Teaser 2440: [Safe combination]
From The Sunday Times, 28th June 2009 [link]
George and Martha’s safe was broken into. The combination had six digits: they remembered it as two three-figure numbers, the second being the first multiplied by their single-digit house number. All seven digits were different and non-zero. The burglar knew these facts and worked out the code. Their new combination has eight digits, remembered as four-figure numbers, the second being the first multiplied by their lucky digit. All nine digits are different and non-zero. The last three digits are the same as in the original.
What is their new combination?
This puzzle was originally published with no title.
[teaser2440]







Jim Randell 1:23 pm on 15 April 2026 Permalink |
We don’t know the house number, but the burglar does, and we can look for situations where knowing the house number allows you to work out a unique combination.
The following Python program uses the [[
SubstitutedExpression]] solver from the enigma.py library to generate candidate combinations are house numbers, and then uses the [[filter_unique()]] function to identify viable situations.We can then look for possible second combinations where the final 3 digits are the same as those in the first combination.
It runs in 74ms. (Internal runtime is 7.2ms).
from enigma import (SubstitutedExpression, irange, filter_unique, item, nsplit, printf) # suppose the first combination is: ABC DEF, and the house number G p1 = SubstitutedExpression( [ "{ABC} * {G} = {DEF}" ], digits=irange(1, 9), answer="({ABC}, {DEF}, {G})", ) # knowing the house number, the burglar could work out the code rs = filter_unique(p1.answers(verbose=0), f=item(2)) for (ABC, DEF, G) in rs.unique: # find the second combination: HIJK LMNP, and the lucky number Q # and the last 3 digits are the same as in the first combination p2 = SubstitutedExpression( [ "{HIJK} * {Q} = {LMNP}" ], digits=irange(1, 9), s2d=dict(zip("MNP", nsplit(DEF))), answer="({HIJK}, {LMNP}, {Q})", ) for (HIJK, LMNP, Q) in p2.answers(verbose=0): # output solution printf("code 1 = {ABC} {DEF} (house = {G}); code 2 = {HIJK} {LMNP} (lucky = {Q})")Solution: The new combination is: 1738 6952.
And their lucky number is 4.
The original code was: 136 952. And the house number is 7.
There is another candidate for the old combination that can be determined knowing the house number. This is: 157 942 (house number = 6), but this does not permit a second combination to be made sharing the final 3 digits.
LikeLike
Ruud 2:30 pm on 15 April 2026 Permalink |
import peek import istr collect = {i: [] for i in istr.range(1, 10)} for digit, f0, f1, f2 in istr.permutations(range(1, 10), 4): first = f0 | f1 | f2 second = first * digit if len(second) == 3 and (first | second | digit).all_distinct(): collect[digit].append(second) for digit, second3s in collect.items(): if len(second3s) == 1: house_number = digit second3 = second3s[0] for lucky_digit, f0, f1, f2, f3 in istr.permutations(range(1, 10), 5): first = f0 | f1 | f2 | f3 second = first * lucky_digit if len(second) == 4 and (first | second | lucky_digit).all_distinct(): if second[1:] == second3: peek(first, second, lucky_digit, house_number)LikeLike
Jim Randell 3:41 pm on 15 April 2026 Permalink |
@Ruud: You need to ensure: “All seven digits were different and non-zero”.
LikeLike
Ruud 3:49 pm on 15 April 2026 Permalink |
@Jim
Yes, I missed the non zero condition. This one does:
import peek import istr collect = {i: [] for i in istr.range(1, 10)} for digit, f0, f1, f2 in istr.permutations(range(1, 10), 4): first = f0 | f1 | f2 second = first * digit if len(second) == 3 and not '0' in second and (first | second | digit).all_distinct(): collect[digit].append(second) for digit, second3s in collect.items(): if len(second3s) == 1: house_number = digit second3 = second3s[0] for lucky_digit, f0, f1, f2, f3 in istr.permutations(range(1, 10), 5): first = f0 | f1 | f2 | f3 second = first * lucky_digit if len(second) == 4 and not '0' in second and (first | second | lucky_digit).all_distinct(): if second[1:] == second3: peek(first, second, lucky_digit, house_number)LikeLike
Jim Randell 4:53 pm on 15 April 2026 Permalink |
And I think the final loop (lines 15-20) should fall under the
ifstatement at line 11, otherwise you are only checking the final candidatesecond3to be found (or the program will abort if none are found).LikeLike
Ruud 4:40 am on 16 April 2026 Permalink |
Ok.
import peek import istr collect = {i: [] for i in istr.range(1, 10)} for digit, f0, f1, f2 in istr.permutations(range(1, 10), 4): first = f0 | f1 | f2 second = first * digit if len(second) == 3 and not '0' in second and (first | second | digit).all_distinct(): collect[digit].append(second) for digit, second3s in collect.items(): if len(second3s) == 1: house_number = digit second3 = second3s[0] for lucky_digit, f0, f1, f2, f3 in istr.permutations(range(1, 10), 5): first = f0 | f1 | f2 | f3 second = first * lucky_digit if len(second) == 4 and not '0' in second and (first | second | lucky_digit).all_distinct(): if second[1:] == second3: peek(first, second, lucky_digit, house_number)LikeLike