Sunday Times Teaser 3144 – Beware The Jabbers’ Clock, My Son!
by Stephen Hogg
Published Sunday December 25 2022 (link)
On the NHS vaccine booking website, my queue position updated every minute. My initial position was an odd value in the 9000s. This value had four different digits, and its leftmost digit and just two others in it were factors of it. Curiously, these properties applied to each of the decreasing four-figure values after the next eight updates. I also noticed that no value had a digit in common with its predecessor, no zeroes occurred before the fourth update and no nines after this.
My son, told just the above, found all the possible values from which a complete set could be selected. From these he was certain of more than one of the nine queue positions.
Give these certain positions in displayed order.
-
Brian Gladman permalink123456789101112131415161718192021222324252627282930313233343536373839404142434445464748from itertools import permutationsfrom functools import reducefrom collections import defaultdict# <psd>: map of first digits of positions to positions mapped to# their digit sets; <n>: update number; <pseq> position sequencedef solve(psd, n=0, pseq=()):if n == 9:yield pseqelse:# consider positions and their digit sets for this roundfor ps, pd in psd[9 - n].items():# digit sets are disjoint for consecutive roundsif n and pd & psd[10 - n][pseq[-1]]:continue# no 0s until update 4, no 9s after update 4if n < 4 and 0 in pd or n > 4 and 9 in pd:continueyield from solve(psd, n + 1, pseq + (ps,))# map first digits of positions to a dictionary of positions# mapped to their digit setspsd = defaultdict(dict)# consider four different digits for the 4-digit queue positionsfor a, *bcd in permutations(range(10), 4):# the position can't share digits with its adjacent positionsif {a - 1, a + 1}.intersection(bcd):continue# make the 4-digit position ...ps = reduce(lambda x, y: 10 * x + y, [a] + bcd)# ... not with the first digit zero or with the first position (9xxx) even ...if a == 0 or a == 9 and not (bcd[2] & 1):continue# ... and which is divisible by its first digit and two othersif not ps % a and sum(ps % n == 0 for n in bcd if n) == 2:psd[ps // 1000][ps] = {a, *bcd}# collect sets of possible positions for each updatevals = defaultdict(set)# consider all posssible update sequencesfor s in solve(psd):# store the possible positions for the initial position and each updatefor j, n in enumerate(s):vals[j] |= {n}# output update positions where they are uniqueprint(*[v.pop() for k, v in vals.items() if len(v) == 1])