Brain-Teaser 930: All scores different
From The Sunday Times, 18th May 1980 [link]
The great thing about the new football method is that goals count whoever wins the match. With luck, this will create more excitement, and reward skills better than at present, for even a side losing heavily will have some incentive to attack.
In this new method 10 points are given for a win, five points to each side for a draw, and one point for each goal scored.
In a recent competition between four teams — A, B, C and D — who played each other once, the points were as follows:
A = 25
B = 34
C = 6
D = 20Each side scored at least one goal in each match, and — rather interestingly — the score was different in every match.
Find the score in each match.
This puzzle is included in the book The Sunday Times Book of Brainteasers (1994). The puzzle text above is taken from the book.
The setter is given as “the late Eric Emmet”, and it is noted in the 1994 book that Eric Emmet had died by the time this puzzle was published.
Eric Emmet also contributed the Puzzle series of puzzles to New Scientist, as well as several Enigma puzzles (including puzzles published as late as 1991).
[teaser930]






Jim Randell 6:57 am on 27 August 2023 Permalink |
See also: Enigma 599.
The total number of points awarded are: 25 + 34 + 6 + 20 = 85.
There are 6 matches in the tournament, and 10 points are awarded depending on the match outcomes, accounting for 60 points in total.
So there are 25 goals scored. Each side scored at least one goal in each match, so there are only 13 goals unaccounted for.
In order to get different scores in each match we need to allow at least 4, but no more than 6 goals to be scored (per team) in any match.
And we find a solution with up to 4 goals scored (per team) in a match.
The following run file executes in 79ms. (Internal runtime of the generated program is 19ms).
Run: [ @replit ]
#! python3 -m enigma -rr # matches are: # # A vs B = E - F # A vs C = G - H # A vs D = I - J # B vs C = K - L # B vs D = M - N # C vs D = P - Q SubstitutedExpression --distinct="" --digits="1-4" # points for X in match X vs Y, where the score is x - y --code="pts = lambda x, y: compare(x, y, (0, 5, 10)) + x" # points for A, B, C, D "pts(E, F) + pts(G, H) + pts(I, J) == 25" "pts(F, E) + pts(K, L) + pts(M, N) == 34" "pts(H, G) + pts(L, K) + pts(P, Q) == 6" "pts(J, I) + pts(N, M) + pts(Q, P) == 20" # all matches have different scores "seq_all_different(ordered(x, y) for (x, y) in [(E, F), (G, H), (I, J), (K, L), (M, N), (P, Q)])" # output match scores --header="" --template="AvB = {E}-{F}; AvC = {G}-{H}; AvD = {I}-{J}; BvC = {K}-{L}; BvD = {M}-{N}; CvD = {P}-{Q}" --solution=""Solution: The scores are: A vs B = 2-2; A vs C = 2-1; A vs D = 1-1; B vs C = 4-3; B vs D = 3-1; C vs D = 2-3.
LikeLike
Frits 1:01 pm on 28 August 2023 Permalink |
@Jim, please elaborate on “And we find a solution with up to 4 goals scored in a match”.
Did you add it because –digits=”1-6″ was rather slow?
LikeLike
Jim Randell 7:51 am on 29 August 2023 Permalink |
Limiting the digits to a maximum of 4 is enough to find a solution, and it runs quickly.
For an exhaustive search we can increase the maximum digit to 6. The runtime is increased, but it is still less than 1s.
But we can limit the total number of goals in any match (it cannot be more than 7), to reduce the runtime again. It complicates the recipe a little, but gives a complete solution that still runs quickly.
LikeLike
Frits 11:45 am on 30 August 2023 Permalink |
Based on Jim’s setup.
# points for X in match X vs Y, where the score is x - y pts = lambda x, y: x + 1 if x < y else x + 6 if x == y else x + 11 # decompose <t> into <k> numbers from <ns> so that sum(<k> numbers) equals <t> def solve(t, ns, k=12, s=[]): if k == 1: if t in ns: yield s + [t] else: # perform early checks # H, L, P are already known if k == 9 and sum(s) != 3: return # C must have had three losses # H, L, P, F, K, M are already known if k == 6: if sum(s) != 9: return # B didn't loose and had one draw if s[4] <= s[1]: return # C lost from B # H, L, P, F, K, M, E, N are already known if k == 4: # B: 2 wins and a draw so (F > E and M == N) or (F == E and M > N) if not((s[3] > s[6] and s[5] == s[7]) or (s[3] == s[6] and s[5] > s[7])): return # G > 0 and Q > 0 (and G + Q > 2) if sum(s) > 10: return # G > H and Q > P (and G + Q > 2) if k == 3 and s[-1] <= s[0]: return if k == 2 and (s[-1] <= s[2] or s[-2] + s[-1] <= 2): return for n in ns: if n > t: break yield from solve(t - n, ns, k - 1, s + [n]) # there are 25 goals scored and only 13 goals unaccounted for # B must have had two wins and one draw as otherwise one win and two draws # leads to two "1 - 2" losses for C (who had definitely had three losses) # matches are: # # A vs B = 1 + E - 1 + F # A vs C = 1 + G - 1 + H # A vs D = 1 + I - 1 + J # B vs C = 1 + K - 1 + L # B vs D = 1 + M - 1 + N # C vs D = 1 + P - 1 + Q # first unaccounted goals for C followed by unaccounted goals for B for H, L, P, F, K, M, E, N, G, Q, I, J in solve(13, range(6)): games = [(E, F), (G, H), (I, J), (K, L), (M, N), (P, Q)] # all matches have different scores if len(set(seq := [tuple(sorted(x)) for x in games])) != len(seq): continue # check number of points if pts(E, F) + pts(G, H) + pts(I, J) != 25: continue if pts(J, I) + pts(N, M) + pts(Q, P) != 20: continue if pts(J, I) + pts(N, M) + pts(Q, P) != 20: continue if pts(H, G) + pts(L, K) + pts(P, Q) != 6: continue desc = "AvB AvC AvD BvC BvD CvD".split() # add 1 to scores scores = [desc[i] + " = " + str(games[i][0] + 1) + "-" + str(games[i][1] + 1) for i in range(6)] print(', '.join(scores))LikeLike