Teaser 3288: Todd’s password
From The Sunday Times, 28th September 2025 [link] [link]
Todd privately tells each of four of his friends a letter of the password to his phone. All their letters have a different position in the password, but they do not know the position of their letter. He gives them all a list of 12 possible passwords, one of which is correct:
STEW, BOYS, PANS, STIG, NILE, LEER, STEM, WERE, GEMS, STAB, TEST, SPOT.
He asks them all in turn if they know the password, and they all say no. He repeats this and gets the same response a number of times until the first friend to be asked says yes, and the rest no. Upon announcing that the first friend’s letter is in the second half of the alphabet, they all say yes.
What is Todd’s password?
[teaser3288]









Jim Randell 8:06 am on 28 September 2025 Permalink |
I found the logic for this puzzle quite involved, in order to ensure all the given conditions are met.
If the password contains a letter that appears in only one of the candidate words, then whoever is given that letter will be able to declare the password immediately. And if the password is declared, the other friends will know it is one of the candidates that contains a unique letter, and if the letter they have been given appears in only one of the uniquely identifiable words, then they too will be able to declare the password.
This Python 3 program runs in 61ms. (Internal runtime is 192µs).
from enigma import (defaultdict, irange, inf, multiset, singleton, diff, printf) # possible passwords passwords = [ "STEW", "BOYS", "PANS", "STIG", "NILE", "LEER", "STEM", "WERE", "GEMS", "STAB", "TEST", "SPOT" ] # count the number of steps in the process for n in irange(1, inf): # collect passwords by letters involved d = defaultdict(list) for pw in passwords: for x in set(pw): d[x].append(pw) # collect candidates identified by a unique letter ks = set(vs[0] for vs in d.values() if len(vs) == 1) if not ks: break printf("[{n}] {ks} can be deduced") # there must be multiple passwords that can be deduced # (or everyone can declare); and the process is repeated # "a number of times", so lets say more than 2 if len(ks) > 1 and n > 2: # consider possible passwords that can be declared ss = list() for k in ks: # just one friend can deduce the password j = singleton(j for (j, x) in enumerate(k) if len(d[x]) == 1) if j is not None: ss.append((k, j)) printf("[{n}] only friend {j} can deduce {k!r}; friend was told {k[j]!r}") # letters other than that told to the declared friend must be ambiguous if len(ss) > 1: # collect how many passwords use the other letters m = multiset() for (k, j) in ss: m.update_from_seq(set(k).difference({k[j]})) # check all are ambiguous if all(v > 1 for v in m.values()): # knowing the letter told to the declared friend is in N-Z gives a unique solution r = singleton((k, j) for (k, j) in ss if k[j] > 'M') if r is not None: # output solution (k, j) = r printf("SOLUTION: password = {k!r} [friend {j} was told {k[j]!r}]") # remove the candidates passwords = diff(passwords, ks)Solution: Todd’s password is: STEW.
A manual analysis:
At step 1 BOYS can be uniquely identified by the letter Y. So if any friend had been told Y they would be able to deduce the password. And if they did declare they knew the password, then all the others could would also know the password, as it is the only candidate that can be declared at step 1.
But this doesn’t happen, so BOYS can be removed from the list of candidate passwords.
At step 2, from the remaining candidate passwords, both SPOT and STAB can be uniquely identified (by O and B respectively). And if one of the friends did declare they knew the password, then if it was SPOT, whoever had been told P would also be able to declare; and if it was STAB, whoever had been told A could declare. The friends that had been told S and T still would not know which it was. Although if they were told the first friend to declare had been told a letter in the second half of the alphabet, they could them both declare SPOT.
But this doesn’t happen, so SPOT and STAB can be removed from the list.
At step 3, PANS can be uniquely identified (by the letters P and A). So two friends could declare immediately, and the other two could then follow.
But this doesn’t happen, so PANS can be removed from the list.
At step 4, NILE can be identified (by the letter N). So one friend can declare immediately, and the other friends can then follow.
But this doesn’t happen, so NILE can be removed from the list.
At step 5, both STIG and LEER can be uniquely identified (by I and L respectively). And if one friend declares at this stage, the other friends were told (S, T, G) or (E, E, R). None of the letters are ambiguous between the choices, and so all the other friends could immediately follow.
But this doesn’t happen, so STIG and LEER can be removed from the list.
At step 6, both GEMS and WERE can be identified (by G and R respectively). And if one friend declares at this stage, the other friends were told (E, M, S) or (W, E, E). So the friends that were told a letter other than E can also declare. If this leads to two friends declaring, the one remaining friend (who was told E) can also declare for GEMS; but if only one additional friend declares, the two remaining friends (who were told E) can declare for WERE.
But this doesn’t happen, so GEMS and WERE can be removed from the list.
At step 7, the remaining candidates are: STEW, STEM, TEST. Both STEW and STEM can be uniquely identified (by W and M respectively). And if one friend declares, then the other friends must have been told (S, T, E) in either case, so there can be no further immediate declarations.
This does match the situation described, and then Todd reveals that the friend who declared was told a letter in the second half of the alphabet, and so the password must be STEW, and the other friends can declare.
So this is a viable situation, and leads to an answer to the puzzle.
But if this doesn’t happen, STEW and STEM can be removed from the list.
At step 8, the only remaining candidate is TEST, and so all friends can declare immediately.
But this doesn’t happen.
So the only viable solution is if the password is STEW and the first declaration occurs at step 7, by the friend who was told W.
LikeLike
Frits 7:11 am on 4 October 2025 Permalink |
from itertools import combinations pws = {'STEW', 'BOYS', 'PANS', 'STIG', 'NILE', 'LEER', 'STEM', 'WERE', 'GEMS', 'STAB', 'TEST', 'SPOT'} ltrs = sorted(set(''.join(pws))) rnd = 1 # while there are passwords with a unique letter while (uniq := [(x, y[0]) for x in ltrs if len(y := [pw for pw in pws if x in pw]) == 1]): uniq_ltrs, uniq_pws = [x for x, y in uniq], [y for x, y in uniq] # the process is repeated "a number of times", so lets say more than 2 # we need at least 2 different passwords for people not to be sure # only one missing letter in the second half identifies the password if (rnd > 3 and len(set(uniq_pws)) > 1 and (uniq_ltrs[-2] < 'N' and uniq_ltrs[-1] > 'M')): ans = uniq_pws[-1] # the answer may not contain more than one unique letter if uniq_pws.count(ans) > 1: continue oltrs = {x for x in ans if x != uniq_ltrs[-1]} opws = ''.join(uniq_pws[:-1]) # all non-unique letters in answer must be found in other passwords if all(ltr in opws for ltr in oltrs): print("answer:", ans) print(f"eliminate {(ws := set(uniq_pws))}, remaining:", pws := pws - ws) rnd += 1LikeLike