Teaser 3314: Number unobtainable!
From The Sunday Times, 29th March 2026ย [link] [link]
Dyall recalls six-digit phone numbers as a sequence of two three-figure values. His wife, Belle, recalls them as a sequence of three two-figure values. Their courting-days’ phone numbers had no zeroes. For each of their numbers, Dyall recalled that the two three-figure values in order made a descending set of primes, while Belle recalled that the three two-figure values in order made a descending set of primes. Back then their town’s residential numbers never began with 7, 8 or 9.
Dyall told Tim these things, but not the numbers. He then stated that choosing a digit at random to be told its value would give a one in three chance of Tim being able to work out Dyallโs old phone number with certainty. In Belle’s case the chance was greater still.
Give Belle’s old phone number.
[teaser3314]



Jim Randell 12:38 am on 29 March 2026 Permalink |
This Python program uses the [[
SubstitutedExpression]] solver from the enigma.py library to find candidate phone numbers.It runs in 82ms. (Internal runtime is 5.8ms).
from enigma import (SubstitutedExpression, irange, multiset, unzip, printf) # generate candidate phone numbers def generate(): # consider the 6-digit phone number: ABCDEF exprs = [ # AB CD EF form a descending sequence of primes "is_prime(AB)", "is_prime(CD)", "is_prime(EF)", "AB > CD", "CD > EF", # ABC DEF form a descending sequence of primes "is_prime(ABC)", "is_prime(DEF)", "ABC > DEF", ] p = SubstitutedExpression( exprs, distinct="", # numbers never contained 0 digits=irange(1, 9), # numbers never began with 7, 8, 9 d2i={7: "A", 8: "A", 9: "A"}, # return the sequence of digits answer="(A, B, C, D, E, F)", ) return p.answers(verbose=0) # find candidate numbers nss = list(generate()) # count digits by position pos = list(multiset.from_seq(cols) for cols in unzip(nss)) # for each number how many of the digits allow it to be uniquely identified? for ns in nss: k = sum(pos[i].count(d) == 1 for (i, d) in enumerate(ns)) # identify numbers p = ("[Dyall]" if k == 2 else "[Belle]" if k > 2 else "") printf("{ns} -> {k}/6 {p}")Solution: Belle’s number was: 431311.
And Dyall’s number was: 593113.
The are 6 candidate numbers that give a descending sequence of primes when group by 2 digits or by 3 digits.
Here is a list, along with the number of digits that uniquely identify the number:
So, if you were told the 1st digit of Dyall’s number is 5, or the 2nd digit is 9, you could determine the entire number with certainty (2/6 digits = 1/3 chance).
And for Belle’s number if you were told the 3rd digit is 1, the 4th digit is 3, or the 6th digit is 1, you could determine the entire number with certainty (3/6 digits = 1/2 chance).
LikeLike
Jim Randell 12:43 pm on 29 March 2026 Permalink |
Or, without using [[
SubstitutedExpression]].This Python program has an internal runtime of 323ยตs.
from enigma import (primes, subsets, multiset, unzip, printf) # [optional] calculate primes < 700 primes.expand(699) # generate candidate phone numbers def generate(): # AB CD EF form a descending sequence of primes with AB < 70 for (EF, CD, AB) in subsets(primes.between(11, 69), size=3): # the digits will necessarily be non-zero, and A < 7 (C, D) = divmod(CD, 10) # ABC DEF form a descending sequence of primes (ABC, DEF) = (10*AB + C, 100*D + EF) if not (ABC > DEF and DEF in primes and ABC in primes): continue # return the phone number as a sequence of digits yield divmod(AB, 10) + (C, D) + divmod(EF, 10) # find candidate numbers nss = list(generate()) # count digits by position pos = list(multiset.from_seq(cols) for cols in unzip(nss)) # for each number how many of the digits allow it to be uniquely identified? for ns in nss: k = sum(pos[i].count(d) == 1 for (i, d) in enumerate(ns)) # identify numbers p = ("[Dyall]" if k == 2 else "[Belle]" if k > 2 else "") printf("{ns} -> {k}/6 {p}")LikeLiked by 1 person
GeoffR 11:16 am on 29 March 2026 Permalink |
Claude AI optimised its own solution when requested to produce a fast solution – 3.5 msec on my I9 Desktop PC. Seemed quite a complex list comprehension for the candidates.
# ST 3314 by Claude AI import time def sieve(n): is_prime = bytearray([1]) * (n + 1) is_prime[0] = is_prime[1] = 0 for i in range(2, int(n**0.5) + 1): if is_prime[i]: is_prime[i*i::i] = bytearray(len(is_prime[i*i::i])) return is_prime t0 = time.perf_counter() is_prime = sieve(999) p3 = [p for p in range(101, 1000) if is_prime[p] and '0' not in str(p)] candidates = [ s for a in p3 for b in p3 if a > b and str(a)[0] not in "789" and '0' not in (s := f"{a}{b}") and int(s[:2]) > int(s[2:4]) > int(s[4:]) and all(is_prime[int(s[i:i+2])] for i in (0, 2, 4)) ] det = lambda n: sum(sum(c[i] == n[i] for c in candidates) == 1 for i in range(6)) belle = next(n for n in candidates if det(n) > 2) print(f"Belle's old phone number was {belle} [{(time.perf_counter()-t0)*1000:.2f} ms]")LikeLike
Frits 5:03 pm on 29 March 2026 Permalink |
from itertools import combinations, compress from functools import reduce def primesbelow(n): # rwh_primes1v2(n): """ Returns a list of primes < n for n > 2 """ sieve = bytearray([True]) * (n // 2 + 1) for i in range(1, int(n ** 0.5) // 2 + 1): if sieve[i]: sieve[2 * i * (i + 1)::2 * i + 1] = \ bytearray((n // 2 - 2 * i * (i + 1)) // (2 * i + 1) + 1) return [2, *compress(range(3, n, 2), sieve[1:])] P = primesbelow(1000) P2 = [p for p in P if 9 < p < 70] P3 = {p for p in P if 99 < p < 700} # positions cols = [[] for _ in range(6)] ns = [] # Dyall and Belle's numbers have to look like pqrstu or .ooo.o where o is odd for pq, rs in combinations(P2[::-1][:-1], 2): r, s = divmod(rs, 10) if r % 2 == 0: continue if 10 * s >= pq: continue if (pqr := 10 * pq + r) not in P3: continue s100 = 100 * s for tu in P2: if tu >= rs: break if (stu := s100 + tu) not in P3: continue if pqr <= stu: continue # store possible phone numbers ns.append(dgts := [y for x in [pq, rs, tu] for y in divmod(x, 10)]) for i, c in enumerate(dgts): cols[i] += [c] # for how many positions can Tim work out the phone number cnts = [sum([col.count(col[r]) == 1 for col in cols]) for r in range(len(ns))] assert 2 in cnts # Dyall # print Belle's number print(f"answer: {' or '.join(str(''.join(str(x) for x in ns[i])) for i, c in enumerate(cnts) if c > 2)}")LikeLike