# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1331: Three into two

From New Scientist #2490, 12th March 2005

There are four football teams in our league, each playing each other once in a season. At the end of the season I worked out the league table (with teams in alphabetical order) and consistently replaced digits by letters in some of the entries to give the table below.

Unfortunately I was a bit confused and the points for Albion were based on two points for a win (and one for draw) whereas the others were based on the correct three points for a win.

Which team was top of the league and which was bottom? And which of those two teams (if either) won when they played each other?

[enigma1331]

### One response to “Enigma 1331: Three into two”

1. Jim Randell 18 April 2014 at 8:19 am

This Python program uses the Football() class from the enigma.py library. It runs in 196ms.

```from enigma import Football, irange, printf

# 3 points for a win scoring
football = Football(games='wdl', points={ 'w': 3, 'd': 1 })

# single digits
digits = set(irange(0, 9))

# possible match outcomes for C
for (AC, BC, CD) in football.games(repeat=3):
# compute the table C
C = football.table([AC, BC, CD], [1, 1, 0])
# drawn, lost and points are all different
(T, H, E) = (C.d, C.l, C.points)
if len(set((T, H, E))) != 3: continue

# possible remaining match outcomes for B
for (AB, BD) in football.games(repeat=2):
# compute the table for B
B = football.table([AB, BC, BD], [1, 0, 0])
# lost = T
if B.l != T: continue

# and the final match
for AD in football.games():
# compute the tables for A
A = football.table([AB, AC, AD], [0, 0, 0])
# lost is a new digit, and points - won = T
J = A.l
if J in (T, H, E) or A.points != T + A.w: continue

# compute the table for D
D = football.table([AD, BD, CD], [1, 1, 1])
# points is a new digit
W = D.points
ds1 = digits.difference((T, H, E, J, W))
if len(ds1) != 5: continue

# consider possible scorelines for C
for R in ds1:
for (sAC, sBC, sCD) in football.scores([AC, BC, CD], [1, 1, 0], R, E):

# consider possible scorelines for B
ds2 = ds1.difference([R])
for O in ds2:
for (sAB, sBD) in football.scores([AB, BD], [1, 0, 0], W, O, [sBC], [0]):

# consider possible remaining scorelines for D
ds3 = ds2.difference([O])
for N in ds3:
for (sAD,) in football.scores([AD], [1], N, O, [sBD, sCD], [1, 1]):

# compute the goals for A to find the remaining digits
(U, S) = football.goals([sAB, sAC, sAD], [0, 0, 0])
if len(ds3.difference([N, U, S])) > 0: continue

# sort teams by points
pts = { 'A': A.points, 'B': B.points, 'C': C.points, 'D': D.points }
order = sorted(pts.keys(), key=lambda x: pts[x], reverse=True)
(top, bottom) = (order[0], order[-1])
# check for ties at the top and bottom
assert pts[order[1]] < pts[top]
assert pts[bottom] < pts[order[-2]]

# determine top vs. bottom match outcome
matches = { 'AB': AB, 'AC': AC, 'AD': AD, 'BC': BC, 'BD': BD, 'CD': CD }
match = ''.join(sorted((top, bottom)))
outcome = matches[match]

printf("A={A}")
printf("B={B}")
printf("C={C}")
printf("D={D}")
printf("T={T} H={H} E={E} J={J} W={W} R={R} O={O} N={N} U={U} S={S}")
printf("top = {top} / bottom = {bottom} / {match[0]} vs. {match[1]} = {outcome}")
printf()
```

Solution: City was top of the league. Albion was bottom of the league. City won the match between the two teams.

There are six different sets of scores for the matches that all produce the same table. The outcomes of the matches (win, draw, lose) and the winning margin for each match are the same in each of the six cases, but the actual numbers of goals scored in each match differ.

The outcomes are: AvB, B wins by 1 goal; AvC, C wins by 1 goal; AvD, draw; BvC draw; BvD, D wins by 3 goals; CvD, C wins by 1 goal.

Albion does not win any matches, so the although the first line may have been produced assuming the “2 points for a win” rule the values in it are no different from those produced using the correct “3 points for a win” rule.

This site uses Akismet to reduce spam. Learn how your comment data is processed.