From The Sunday Times, 25th May 1980 [link]
Large families often have problems, particularly when it comes to deciding who has first choice, etc.
My six brothers and I solved this particular one by devising our own dice game. Each of us in turn would roll a die four times and put the results together in that order to form a four-figure number. (So that, for example: 6 followed by 2, then 3 and 1, gives the number 6231). We would each do this and the one of us getting the highest four-figure number would be declared the winner.
One such game had some very strange results. Each of us got a different prime number, using the same four different digits. The average of the seven primes was a perfect square, to which Jon’s number was the nearest.
The difference between Ron’s and Don’s numbers, multiplied by one of the numbers from the die, gave the difference between Len’s and Ken’s numbers.
Omitting Ben’s score, the total could have been formed by throwing the die five times. And so could the total of the numbers thrown by Len, Ken, Ron and me.
What was my score, and who ate the biggest piece of apple pie?
The originally published version of this puzzle was flawed, so the version above was taken from the book Microteasers (1986), in which it was noted:
There is an interesting postscript to [this] puzzle. When it first appeared, the condition “each of us got a different prime number using the same four different digits” was given as “each of us got a different prime number; two digits never came up”. That allowed numbers like 5651, which was not the intention at all. The odd thing is that all the readers who sent in answers found the intended solution anyway. So perhaps, even if one relaxes the condition about all the primes using four different digits, the teaser still has a unique solution. The keener reader might like to adapt the program to take four digits in turn and see how many primes can be made from those four (but not necessarily using all four each time). Then you have to consider all possible sets of seven from those. We leave this much harder problem as an exercise.
However the original formulation of the puzzle does not give a unique solution.
[teaser931]
Jim Randell 10:18 am on 7 March 2023 Permalink |
I am assuming the point are allocated as: “3 points for a win, 1 point for a draw”. (Although the puzzle also seems to work if “2 points for a win” is used instead).
Each team plays their three opponents twice, so there are 12 matches in total.
There are not more than 5 goals scored in any match, so possible scores are:
This accounts for all 12 matches, so each score must be used.
And the final 2 matches are drawn, so there is exactly 1 draw in the first 10 matches.
Programming a constructive solution for this puzzle is quite involved. I hope that a manual solution is more fun. I used the [[
Football()]] helper class from the enigma.py library to save on some of the coding, but things are complicated a bit by the fact each pair of teams meet twice, and there is nothing to distinguish the two games, so to avoid duplicated solutions I store the results for the two games in order with the “best” game (from the first team’s point of view) given first.This Python program runs in 253ms.
from enigma import (Football, subsets, partitions, update, compare, ordered, rev, join, map2str, printf) football = Football(points=dict(w=3, d=1)) # possible scores, no game had more than 5 goals scores = dict() scores['d'] = [(0, 0), (1, 1), (2, 2)] scores['w'] = [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (5, 0)] scores['l'] = list(map(rev, scores['w'])) # label the matches (each label corresponds to 2 matches) teams = "ABCD" matches = list(x + y for (x, y) in subsets(teams, size=2)) # complete possible match pairs (additional win/lose outcomes) pairs = { '-': ['ww', 'wl', 'll'], 'x': ['wx', 'lx'], 'd': ['wd', 'dl'], } # swap pairs into canonical order _pair = { 'dw': 'wd', 'lw': 'wl', 'ld': 'dl' } pair = lambda x: _pair.get(x, x) # allocate win/lose outcomes to matches def allocate_matches(ks, ms): # are we done? if not ks: yield ms else: k = ks[0] v = ms.get(k, '-') if len(v) > 1: # skip this key yield from allocate_matches(ks[1:], ms) else: # allocate both outcomes for x in pairs[v]: yield from allocate_matches(ks[1:], update(ms, [(k, x)])) # allocate scores to matches def allocate_scores(ks, ms, used=set(), ss=dict()): # are we done? if not ks: yield (ss, used) else: k = ks[0] if k in ss: # skip this key yield from allocate_scores(ks[1:], ms, used, ss) else: # allocate both scores (a, b) = ms[k] for x in scores[a]: x_ = ordered(*x) if x_ in used: continue for y in scores[b]: y_ = ordered(*y) # remove duplicate solutions if (a == b and not x_ > y_) or y_ in used: continue yield from allocate_scores(ks[1:], ms, used.union({x_, y_}), update(ss, [(k, (x, y))])) # extract match/teams values from dict d def extract(d, t, fn): (gs, ts) = (list(), list()) for (k, v) in d.items(): if t in k: gs.extend(v) ts.extend([(0 if k[0] == t else 1)] * len(v)) return fn(gs, ts) # construct the table for team t, using matches in ms table = lambda ms, t: extract(ms, t, football.table) # goals for/against team t, using scores in ss goals = lambda ss, t: extract(ss, t, football.goals) # output the matches and scores def output_matches(ms, ss, **kw): def _process(d, fn): d_ = dict() for (k, (a, b)) in d.items(): d_[k] = a d_[rev(k)] = fn(b) return d_ football.output_matches(_process(ms, football.swap), _process(ss, rev), **kw) # does team <x> beat team <y> in the table <tbl> and match outcomes <ms>? def beats(x, y, tbl, ms): # a team does not beat itself if x == y: return 0 # can it be decided on points? r = compare(tbl[x].points, tbl[y].points) if r == 1: return 1 if r == -1: return 0 # can it be decided on the outcome of head-to-head games? (k, a, b) = ((x + y, 0, 1) if x < y else (y + x, 1, 0)) gs = ms[k] (X, Y) = (football.table(gs, [a, a]), football.table(gs, [b, b])) r = compare(X.points, Y.points) if r == 1: return 1 if r == -1: return 0 # there may be other ways to order the teams (e.g. goal difference # or goals scored), but these are not mentioned return 0 # check all possible final 2 games for required scenario def check(ms, f1, f2): # check conditions for teams A, B, C fB = fC = 0 for (g1, g2) in football.games('wdl', repeat=2): ms_ = update(ms, [(f1, pair(ms[f1][0] + g1)), (f2, pair(ms[f2][0] + g2))]) # calculate the final table tbl = dict((t, table(ms_, t)) for t in teams) # can A fail to qualify? (i.e. fail to beat at least 2 of the other teams) if not (sum(beats('A', t, tbl, ms_) for t in teams) >= 2): return False # can B come top? (i.e. beat the other 3 teams) if fB == 0 and sum(beats('B', t, tbl, ms_) for t in teams) == 3: fB = 1 # can C come top? (i.e. beat the other 3 teams) if fC == 0 and sum(beats('C', t, tbl, ms_) for t in teams) == 3: fC = 1 return (fB and fC) # find viable scenarios def generate(): # choose the final 2 matches (which are draws) for ((t1, t2), (t3, t4)) in partitions(teams, 2): (f1, f2) = (t1 + t2, t3 + t4) ms0 = { f1: 'x', f2: 'x' } # of the remaining matches exactly 1 of them is a draw for d in matches: ms1 = update(ms0, [(d, ('dx' if d in ms0 else 'd'))]) # choose win/lose outcomes for the remaining matches for ms2 in allocate_matches(matches, ms1): # calculate the table before the final 2 matches are played (A, B, C, D) = (table(ms2, t) for t in teams) if not (A.points > B.points > C.points > D.points): continue # in the final 2 games B or C _could_ gain the top spot # so A cannot be more than 3 points ahead of C if A.points > C.points + 3: continue # check all possible final 2 games if not check(ms2, f1, f2): continue # now include the final games (both are, in fact, drawn) ms3 = update(ms2, list((k, pair(ms2[k][0] + 'd')) for k in (f1, f2))) (A, B, C, D) = (table(ms3, t) for t in teams) # allocate scores for D (Ds, As) = (list(k for k in matches if t in k) for t in "DA") for (ss1, us1) in allocate_scores(Ds, ms3): # D has equal for and against (and scored more goals than any other team) (fD, aD) = goals(ss1, 'D') if fD != aD: continue # allocate remaining scores for A for (ss2, us2) in allocate_scores(As, ms3, us1, ss1): # A scored fewer goals than any other team (fA, aA) = goals(ss2, 'A') if not (fA < fD): continue # allocate remaining scores (B and C) for (ss3, us3) in allocate_scores(matches, ms3, us2, ss2): ((fB, aB), (fC, aC)) = (goals(ss3, t) for t in "BC") if not (fA < fB < fD and fA < fC < fD): continue # yield scenario (matches, scores, final2, goals for/against) yield (ms3, ss3, (f1, f2), ((fA, aA), (fB, aB), (fC, aC), (fD, aD))) # look for viable scenarios for (ms, ss, fs, gfa) in generate(): # output scenarios as we find them output_matches(ms, ss, end=None) printf("final games = {fs}", fs=join(fs, sep=", ")) printf("goals for/against = {gfa}", gfa=map2str(zip(teams, gfa), arr=": ", enc="")) BCs = ss['BC'] # answer is the scores in the B vs C matches printf("-> B vs C = {BCs}", BCs=join(BCs, sep=" ")) printf()Solution: The scores in the B vs. C games were: 4-1 and 1-1.
And the B vs C 1-1 draw was one of the two final games.
There are two possible scenarios. Here is one of them:
(with the two final draws indicated in brackets).
Before the final 2 games (A vs D, B vs C) are the points are:
If B wins their final game then they will have 12 points, and top the table (providing A does not win their final game).
If C wins their final game then they will have 10 points, and if A loses their final game they will also have 10 points, so the top position comes down to the result of the A vs C games. And these are a draw and a win for C, so C comes out on top.
A is guaranteed to finish higher than D, and unless C wins (and A loses) their final game also higher than C. But if C does win, then B must lose, and A will finish higher than B. So A is guaranteed to finish in the top 2 teams (and qualify for the next round).
When the final 2 games are played they are both drawn, and the results are:
So A and B go through to the next round.
The other scenario plays out similarly, but the games won 3-1 and 3-2 are swapped with each other. Although this second scenario could be eliminated if the puzzle text stated that D were the only team with the same number of goals for as goals against. (As B ends up with 10 goals for and 10 goals against).
We can use these 2 scenarios to construct further solutions where the order of the two matches played by pairs of teams are swapped over.
LikeLike