Teaser 3215: Darts league
From The Sunday Times, 5th May 2024 [link] [link]
In our darts league, each team plays each other once. The result of each match is decided by the number of legs won, and each match involves the same number of legs. If both teams win the same number of legs, the match is drawn. The final league table shows the games won, drawn or lost, and the number of legs won for and against the team. The Dog suffered the most humiliating defeat, winning only one leg of that match. Curiously, no two matches had the same score.
What was the score in the match between The Crown and The Eagle?
[teaser3215]

Jim Randell 4:30 pm on 3 May 2024 Permalink |
Each team plays 4 matches and 80 legs, so each match has 20 legs. A and B draw, so their match is 10-10.
D has a 1-19 match, so the scores in the other matches are between 2 and 18 (excluding 10), which is 16 values distributed between 16 different slots, so each value appears exactly once.
Here is a solution using the [[
SubstitutedExpression]] solver from the enigma.py library.The following run file executes in 83ms. (Internal runtime is 4.4ms).
Run: [ @replit ]
#! python3 -m enigma -rr SubstitutedExpression # suppose the matches (X v Y) and scores for X are: # # A v B = Q # A v C = R # A v D = S # A v E = T # B v C = U # B v D = V # B v E = W # C v D = X # C v E = Y # D v F = Z --base=20 # allow scores of 1-19 --digits="1-19" --code="v = lambda x: 20 - x" # opponent's score # scores for each match for each team --macro="@A = [Q, R, S, T]" --macro="@B = [v(Q), U, V, W]" --macro="@C = [v(R), v(U), X, Y]" --macro="@D = [v(S), v(V), v(X), Z]" --macro="@E = [v(T), v(W), v(Y), v(Z)]" # total legs for each team "sum(@A) == 55" # A "sum(@B) == 43" # B "sum(@C) == 37" # C "sum(@D) == 41" # D "sum(@E) == 24" # E # A and B drew (10-10) --assign="Q,10" # all matches have different scores "seq_all_different(ordered(x, v(x)) for x in [Q, R, S, T, U, V, W, X, Y, Z])" # D won 1 leg in one game, and this was the worst score "1 in { v(S), v(V), v(X), Z }" --invalid="1|19,RTUWY" # won, drawn, lost --code=""" def wdl(ss): vs = list(compare(s, 10) for s in ss) return (vs.count(1), vs.count(0), vs.count(-1)) """ "wdl(@A) == (2, 1, 1)" # A "wdl(@B) == (1, 1, 2)" # B "wdl(@C) == (2, 0, 2)" # C "wdl(@D) == (3, 0, 1)" # D "wdl(@E) == (1, 0, 3)" # E # answer is the score in CE --answer="(Y, v(Y))" --template=""Solution: The score in the Crown vs Eagle match was 16-4.
There are two possible sets of scores in the matches:
LikeLike
Frits 2:48 pm on 4 May 2024 Permalink |
Another idea would be to start the first variables Q, R, S and T with “D vs …” so we can use base=19 and digits=”1-18″.
LikeLike
Frits 7:40 pm on 3 May 2024 Permalink |
# decompose number <t> into <k> increasing numbers (between <mn> and <mx>) # so that sum(<k> numbers) equals <t> def decompose(t, k=4, mn=2, mx=19, s=[]): if k == 1: if s[-1] < t <= mx: yield s + [t] else: for n in range(mn if not s else s[-1] + 1, mx + 1): if 2 * k * n + k * (k - 1) > 2 * t: break yield from decompose(t - n, k - 1, mn, mx, s + [n]) # general checks def check(s, grp): s_ = set(s) - {10} # all matches have different scores (we have not won/lost from ourselves) if any(20 - x in s for x in s_) : return False # different scores (except draw) if any(s_.intersection(g) for g in grp): return False # we have not played more than once against the same opponent return all(sum(20 - x in g for x in s) < 2 for g in grp) sols = set() # points for The Dog (three victories) for D in decompose(41 - 1, 3, 11): D += [1] # winning only one leg of that match # points for The Anchor for A in decompose(55): if A[1] != 10: continue # A: 2W/1D/1L if not check(A, [D]): continue # points for Eddy for E in decompose(24): if 10 in E or E[2] > 10 or E[3] < 11: continue # E: 1W/3L if not check(E, [D, A]): continue # points for The Crown for C in decompose(37): if 10 in C or C[1] > 10 or C[2] < 10: continue # C: 2W/2L if not check(C, [D, A, E]): continue # now we know points for The Bull B = set(range(1, 20)).difference(D + A + E + C) | {10} if not check(B, [D, A, E, C]): continue # collect score in the match between The Crown and The Eagle for c in C: if 20 - c in E: sols.add(c) for c in sols: print(f"answer: {c} vs {20 - c}")LikeLike
Frits 3:04 pm on 5 May 2024 Permalink |
More compact but less efficient.
from itertools import permutations # wins/draws/losses wdl = lambda s: [w := 4 - (l := sum(x < 10 for x in s)) - (10 in s), 4 - w - l, l] v = lambda x: 20 - x # opponent's score AB, AC, AD, AE, DB, DC, DE, EB, EC, BC = [0] * 10 vars = lambda k: [AB, AC, AD, AE, DB, DC, DE, EB, EC, BC][:k] # general checks def check(t, v3, scores, vs): # check wins/draws/losses if wdl([v := t - sum(v3)] + v3) != scores: return False # all matches have different scores if (min(ms := set(tuple(sorted([x, 20 - x])) for x in vs + [v])) >= (1, 19) and len(set(ms)) == len(vs) + 1): return v sols = set() AB = 10 for AC, AD in permutations(range(2, 20), 2): if not(AE := check(55, [AB, AC, AD], [2, 1, 1], vars(3))): continue for DB, DC in permutations(range(1, 19), 2): if not(DE := check(41, [v(AD), DB, DC], [3, 0, 1], vars(6))): continue if 1 not in {v(AD), DB, DC, DE}: continue # winning only one leg ... for EB in range(2, 19): if not(EC := check(24, [v(AE), v(DE), EB], [1, 0, 3], vars(8))): continue if not(check(43, [v(AB), v(DB), v(EB)], [1, 1, 2], vars(9))): continue sols.add(EC) for s in sols: print(f"C vs E: {v(s)} - {s}")LikeLike