# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1438: Soccer stats

From New Scientist #2599, 14th April 2007

There are five teams in our local league, and each team plays each of the others once a season. Below is the league table at the end of last season.

Unfortunately three of those numerical entries are incorrect. What were the scores in Arnsley’s four games?

[enigma1438]

### One response to “Enigma 1438: Soccer stats”

1. Jim Randell 22 April 2013 at 2:23 pm

A bit of analysis tells us in which part of the table the errors must lie, and this Python program does the rest. It’s a bit messy, but it runs in 71ms.

```# consider the sums of the columns:
# won = 8, drawn = 7, lost = 5, for = 7, against = 7
#
# each won game for one team is lost for another team, so
# it should be that "won" = "lost", but they are different
# hence there is at least one error in the "won" and "lost"
# columns.
#
# also each drawn game is drawn for two teams, so "drawn" should
# be a multiple of 2, and it isn't so there is at least one
# error in the "drawn" column.
#
# each goal scored for a team is scored against another team
# so these columns should be equal - and they are, so if there
# was an error in one column there would have to be an error
# in the other column to bring the values back into line, hence
# there cannot be exactly one error in the "for" and "against"
# columns (which is the maximum possibility), so these columns
# must contain no errors.
#
# hence all three errors are in the "won", "lost", "drawn" columns.

from collections import namedtuple
from itertools import product
from enigma import irange, printf

# the 10 matches are:
# AvB AvC AvD AvE BvC BvD BvE CvD CvE DvE
# each is either won, lost or drawn ('d')

Table = namedtuple('Table', 'w l d')

# generate the "won", "drawn", "lost" entries in the table
def table(t, games):
w, l, d = 0, 0, 0
for g in games:
if g == 'd':
d += 1
elif g == t:
w += 1
else:
l += 1
return Table(w, d, l)

# generate possible scores for team <t> in games <games>
# with total goals for <f> and total goals against <a>
def scores(t, games, f, a):
if len(games) == 0:
if f == a == 0: yield []
else:
g = games[0]
if g == 'd':
for n in irange(0, min(f, a)):
for s in scores(t, games[1:], f - n, a - n):
yield [(n, n)] + s
elif g == t:
for n in irange(1, f):
for m in irange(0, min(n - 1, a)):
for s in scores(t, games[1:], f - n, a - m):
yield [(n, m)] + s
else:
for n in irange(0, f):
for m in irange(n + 1, a):
for s in scores(t, games[1:], f - n, a - m):
yield [(n, m)] + s

# make the table for A
A = table('A', (AB, AC, AD, AE))
# count the discrepancies
dA = sum(1 for (p, q) in zip(A, (2, 1, 1)) if p != q)
# make the table for B
for (BC, BD, BE) in product('BCd', 'BDd', 'BEd'):
B = table('B', (AB, BC, BD, BE))
# count the discrepancies
dB = sum(1 for (p, q) in zip(B, (3, 1, 0)) if p != q)
if dA + dB > 3: continue
# table for C
for (CD, CE) in product('CDd', 'CEd'):
C = table('C', (AC, BC, CD, CE))
dC = sum(1 for (p, q) in zip(C, (1, 3, 0)) if p != q)
if dA + dB + dC > 3: continue
# table for D and E
for DE in 'DEd':
D = table('D', (AD, BD, CD, DE))
E = table('E', (AE, BE, CE, DE))
dD = sum(1 for (p, q) in zip(D, (1, 2, 1)) if p != q)
dE = sum(1 for (p, q) in zip(E, (1, 0, 3)) if p != q)
d = dA + dB + dC + dD + dE
if d != 3: continue

# generate scores that match up to the "for" against "columns"
for (sAB, sAC, sAD, sAE) in scores('A', [AB, AC, AD, AE], 2, 2):
for (sBC, sBD, sBE) in scores('B', [BC, BD, BE], 2 - sAB[1], 1 - sAB[0]):
for (sCD, sCE) in scores('C', [CD, CE], 1 - sAC[1] - sBC[1], 0 - sAC[0] - sBC[0]):
for (sDE,) in scores('D', [DE], 1 - sAD[1] - sBD[1] - sCD[1], 1 - sAD[0] - sBD[0] - sCD[0]):
if (sAE[1] + sBE[1] + sCE[1] + sDE[1], sAE[0] + sBE[0] + sCE[0] + sDE[0]) != (1, 3): continue

printf("AvB: {sAB}, AvC: {sAC}, AvD: {sAD}, AvE: {sAE}")
printf("BvC: {sBC}, BvD: {sBD}, BvE: {sBE}")
printf("CvD: {sCD}, CvE: {sCE}")
printf("DvE: {sDE}")
print('')
```

Solution: The scores in Arnsley’s four games were – Arnsley vs. Boldham: 0 – 2; Arnsley vs. Cleeds: 0 – 0; Arnsley vs. Drochdale: 1 – 0; Arnsley vs. Erby: 1 – 0.

The incorrect values are the “won”, “drawn” and “lost” values for Boldham.