# Enigmatic Code

Programming Enigma Puzzles

## Puzzle 81: Uncle Bungle and the vertical tear

From New Scientist #1132, 7th December 1978 [link]

It was, I’m afraid, typical of Uncle Bungle that he should have torn up the sheet of paper which gave particulars of the numbers of matches played, won, lost, drawn and so on of four local football teams who were eventually going to play each other once. Not only had he torn it up, but he had also thrown away more than half of it onto, I suspect, the fire, which seems to burn eternally in Uncle Bungle’s grate. The tear was a vertical one and the only things that were left were the “goals against” and the “points” — or rather most of the points, for those of the fourth team had also been torn off.

What was left was as follows:

(2 points are given for a win and 1 for a draw).

It will not surprise those who know my uncle to hear that one of the figures was wrong, but fortunately it was only one out (i.e. one more or one less than the correct figure).

Each side played at least one game, and not more than seven goals were scored in any match.

Calling the teams ABC and D in that order, find the score in each match.

[puzzle81]

### One response to “Puzzle 81: Uncle Bungle and the vertical tear”

1. Jim Randell 15 February 2017 at 9:45 am

There’s not enough of the table (and one of the entries is wrong anyway) to make it worthwhile to use the Football.substituted_table() solver from the enigma.py library. But we can use other routines in the Football() class.

This Python program runs in 250ms.

```from itertools import product
from enigma import Football, irange, update, join, printf

# scoring system
football = Football(points={ 'w': 2, 'd': 1 })

# possible scores in the matches (no match has more than 7 goals scores)
scores = {
'w': [
(1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0),
(2, 1), (3, 1), (4, 1), (5, 1), (6, 1),
(3, 2), (4, 2), (5, 2),
(4, 3),
],
'd': [(0, 0), (1, 1), (2, 2), (3, 3)],
'x': [None],
}
scores['l'] = list((b, a) for (a, b) in scores['w'])

# check discrepancy
# r = current discrepancy (d, label)
# x = computed value
# y = value given in the table
# s = label if this value differs
# discrepancy (abs(x - y)) should be d or less
# the new discrepancy value (or None) is returned
def check(r, x, y, s):
d = abs(x - y)
if d > r[0]: return None
if d == 0: return r
return (0, s)

# initial discrepancy
r0 = (1, None)

# choose outcomes for B's matches
for (AB, BC, BD) in football.games(repeat=3):
if AB == BC == BD == 'x': continue
B = football.table([AB, BC, BD], [1, 0, 0])
r1 = check(r0, B.points, 5, "points B")
if r1 is None: continue

# choose outcomes for C's remaining matchs
for (AC, CD) in football.games(repeat=2):
if AC == BC == CD == 'x': continue
C = football.table([AC, BC, CD], [1, 1, 0])
r2 = check(r1, C.points, 0, "points C")
if r2 is None: continue

# and the remaining match
if AB == AC == AD == 'x': continue
if AD == BD == CD == 'x': continue
A = football.table([AB, AC, AD], [0, 0, 0])
r3 = check(r2, A.points, 3, "points A")
if r3 is None: continue

# choose the scores for C
for (sAC, sBC, sCD) in product(scores[AC], scores[BC], scores[CD]):
# goals for/against C
(fC, aC) = football.goals([sAC, sBC, sCD], [1, 1, 0])
r4 = check(r3, aC, 0, "against C")
if r4 is None: continue

# choose remaining scores for B
for (sAB, sBD) in product(scores[AB], scores[BD]):
# goals for/against B
(fB, aB) = football.goals([sAB, sBC, sBD], [1, 0, 0])
r5 = check(r4, aB, 6, "against B")
if r5 is None: continue

# choose remaining score
# goals for/against A
(fA, aA) = football.goals([sAB, sAC, sAD], [0, 0, 0])
r6 = check(r5, aA, 5, "against A")
if r6 is None: continue

# goals for/against D
r7 = check(r6, aD, 7, "against D")
if r7 is None: continue

# but one of the digits must be wrong
if r7[0] > 0: continue

# output a solution
printf("\"{r7[1]}\" value is wrong")
fmt = lambda s: ('---' if s is None else join(s, sep='-'))
printf("A vs B = ({AB}) {s}", s=fmt(sAB))
printf("A vs C = ({AC}) {s}", s=fmt(sAC))
printf("B vs C = ({BC}) {s}", s=fmt(sBC))
printf("B vs D = ({BD}) {s}", s=fmt(sBD))
printf("C vs D = ({CD}) {s}", s=fmt(sCD))
printf()
```

Solution: The scores in the matches that have been played are: A v B = 3-3; A v D = 3-2; B v C = 1-0; B v D = 4-3.

The remaining matches are not yet played.

The incorrect figure is the “goals against” column for C. It should be 1 (not 0).

This is what the full table looks like:

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