# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1109: All square in games

From New Scientist #2265, 18th November 2000

At tennis a set is won by the first player to win 6 games, except that if the score goes to 5 games all, the set is won either by 7 games to 5 or by 7 games to 6. The first person to win three sets wins the match.

Sometimes at the end of a match each player has won exactly the same number of games. This happened when André beat Boris in a match in which no two sets contained the same number of games.

You will have to work out whether André won by 3 sets to 1 or by 3 sets to 2, but if I told you how many games in total each player won you would be able to deduce with certainty the score in each of the sets that André won and in the set or each of the sets that Boris won.

What was the score in each of the sets that André won? (Give each set’s score in the form x-y, André’s score always comes first).

[enigma1109]

### 3 responses to “Enigma 1109: All square in games”

1. Jim Randell 26 June 2017 at 8:54 am

This Python program runs in 43ms.

```from itertools import combinations
from collections import namedtuple
from enigma import irange, diff, filter_unique, printf

# possible winning scores in a set
sets = set((6, x) for x in irange(0, 4)).union([(7, 5), (7, 6)])

# accumulate possible scores for A and B (and number of games won)
Result = namedtuple('Result', 'g A B')
r = list()

# A won 3 sets with different scores
for A in combinations(sets, 3):
# count the number of games A and B won
(gA1, gB1) = (sum(s) for s in zip(*A))
# consider sets that B won
for B in combinations(sets.difference(A).union([(0, 0)]), 2):
(gB2, gA2) = (sum(s) for s in zip(*B))
g = gA1 + gA2
if g == gB1 + gB2:
B = diff(B, [(0, 0)])
r.append(Result(g, A, B))
printf("games = {g} [A = {A}, B = {B}]")

# find solutions, unique by the number of games
(r, _) = filter_unique(r, (lambda t: t.g))
for (g, A, B) in r:
printf("A = {A}, B = {B}, games = {g}", A=sorted(A), B=sorted(B))
```

Solution: Andre won his sets 6-3, 6-4, 7-6.

Andre won 3 sets to 1. The score in the set Boris won was 0-6. So overall each player won 19 games.

2. geoffrounce 27 June 2017 at 12:05 pm

I tried a game simulation in MiniZinc with a 3-1 win for Able using a winning sequence of A, A, B, A for the game order. Other possible winning sequences would have been A, B, A, A or B, A, A, A

My programme gave three answers, each of which seemed to fulfill the conditions that each player won the same number of games in the match and that no two sets contained the same number of games.

The three solutions include Jim’s solution – but I am not sure how to carry out further filtering in MiniZinc to reduce the three solutions to one solution.

```% A Solution in MiniZinc
include "globals.mzn";

% Possible score domains for Able and Boris for each set
var 0..7:A1;  var 0..7:A2;  var 0..7:A3;  var 0..7:A4;  var 0..7:A5;
var 0..7:B1;  var 0..7:B2;  var 0..7:B3;  var 0..7:B4;  var 0..7:B5;

% Possible stated winning scores in one set of tennis are 6-0, 6-1, 6-2, 6-3, 6-4, 7-5 or 7-6
% Simulate a win for Able with set scores of 3-1 (3-2 is the other possibility)
% Possible order of set wins for a 3-1 win  by Able is AABA, ABAA or BAAA
% Try a winning sequence for Able as Able, Able, Boris, Able

% Set 1 - Able wins - all possible scores
constraint (A1 = 6 /\ B1 = 0) \/ (A1 = 6 /\ B1 = 1) \/ (A1 = 6 /\ B1 = 2)
\/ (A1 = 6 /\ B1 = 3) \/ (A1 = 6 /\ B1 = 4) \/ (A1 = 7 /\ B1 = 5) \/ (A1 = 7 /\ B1 = 6);

% Set 2 - Able wins  - all possible scores
constraint (A2 = 6 /\ B2 = 0) \/ (A2 = 6 /\ B2 = 1) \/ (A2 = 6 /\ B2 = 2)
\/ (A2 = 6 /\ B2 = 3) \/ (A2 = 6 /\ B2 = 4) \/ (A2 = 7 /\ B2 = 5) \/ (A2 = 7 /\ B2 = 6);

% Set 3 - Boris wins  - all possible scores
constraint (B3 = 6 /\ A3 = 0) \/ (B3 = 6 /\ A3 = 1) \/ (B3 = 6 /\ A3 = 2)
\/ (B3 = 6 /\ A3 = 3) \/ (B3 = 6 /\ A3 = 4) \/ (B3 = 7 /\ A3 = 5) \/ (B3 = 7 /\ A3 = 6);

% Set 4 - Able wins  - all possible scores
constraint (A4 = 6 /\ B4 = 0) \/ (A4 = 6 /\ B4 = 1) \/ (A4 = 6 /\ B4 = 2)
\/ (A4 = 6 /\ B4 = 3) \/ (A4 = 6 /\ B4 = 4) \/ (A4 = 7 /\ B4 = 5 ) \/ (A4 = 7 /\ B4 = 6 );

% No two sets contain the same number of games
constraint A1 + B1 != A2 + B2 /\ A1 + B1 != A3 + B3 /\ A1 + B1 != A4 + B4
/\ A2 + B2 != A3 + B3 /\ A2 + B2 != A4 + B4 /\ A3 + B3 != A4 + B4;

% Each player wins exactly the same number of games in the match
constraint A1 + A2 + A3 + A4 = B1 + B2 + B3 + B4;

solve satisfy;

output ["Able's scores: "  ++ show([A1, A2, A3, A4]) ++ " " ++  "Total = " ++ show(A1+A2+A3+A4)  ]
++ ["\n" ++ "Boris' scores: " ++  show([B1, B2, B3, B4]) ++ " " ++  "Total = " ++ show(B1+B2+B3+B4)];

% Simulated winning score sequence (3-1) is Able, Able, Boris, Able
% Three main equal scores are 21, 29 and 19 eg;

% Able's scores: [6, 7, 0, 7] Total = 20 - ie scores for Able are (6-3),(7-6),(0-6),(7-5)
% Boris' scores: [3, 6, 6, 5] Total = 20
% ----------
% Able's scores: [6, 7, 0, 6] Total = 19 - ie scores for Able are (6-3),(7-6),(0-6),(6-4) - Jim's answer
% Boris' scores: [3, 6, 6, 4] Total = 19
% ----------
% Able's scores: [6, 7, 1, 7] Total = 21 - ie scores for Able are (6-4),(7-5),(1-6),(7-6)
% Boris' scores: [4, 5, 6, 6] Total = 21
% ----------
% Finished in 81msec

```

Interesting that tie-breaks (leading to a 7-6 score) are not used in the final set in the Australian Open for singles, the French Open for singles, or Wimbledon (Wikipedia). This rule for Wimbledon led the longest men’s single in history in 2010 in a match (Isner v Mahut) when the fifth set score was 70 – 68!
Tie breaks seem very common in sets in ATP tennis.

• Jim Randell 27 June 2017 at 2:04 pm

@geoff: As you say there are three different ways that A can win 3-1, with each player winning 19, 20 or 21 games. But there are also 15 ways that A can win 3-2, and these have each player winning 20, 21, 22, 23, 24, 25 or 26 games.

Here are the different ways found by my program (ordered by the number of games each player wins):

games = 19 [A = ((6, 4), (6, 3), (7, 6)), B = ((6, 0),)]
games = 20 [A = ((6, 4), (6, 1), (6, 3)), B = ((6, 2), (6, 0))]
games = 20 [A = ((7, 5), (6, 3), (7, 6)), B = ((6, 0),)]
games = 21 [A = ((6, 4), (7, 5), (7, 6)), B = ((6, 1),)]
games = 21 [A = ((7, 5), (6, 1), (6, 3)), B = ((6, 2), (6, 0))]
games = 22 [A = ((6, 4), (6, 0), (7, 6)), B = ((6, 1), (6, 2))]
games = 22 [A = ((6, 4), (7, 5), (6, 1)), B = ((6, 3), (6, 0))]
games = 23 [A = ((6, 3), (6, 2), (7, 6)), B = ((6, 4), (6, 0))]
games = 23 [A = ((6, 4), (7, 5), (6, 2)), B = ((6, 3), (6, 1))]
games = 23 [A = ((7, 5), (6, 0), (7, 6)), B = ((6, 1), (6, 2))]
games = 24 [A = ((6, 3), (6, 2), (7, 6)), B = ((7, 5), (6, 0))]
games = 24 [A = ((6, 4), (6, 1), (7, 6)), B = ((7, 5), (6, 0))]
games = 24 [A = ((7, 5), (6, 1), (7, 6)), B = ((6, 4), (6, 0))]
games = 25 [A = ((6, 4), (6, 2), (7, 6)), B = ((6, 1), (7, 5))]
games = 25 [A = ((6, 4), (7, 5), (6, 3)), B = ((7, 6), (6, 0))]
games = 25 [A = ((7, 5), (6, 2), (7, 6)), B = ((6, 4), (6, 1))]
games = 26 [A = ((6, 4), (6, 3), (7, 6)), B = ((6, 2), (7, 5))]
games = 26 [A = ((7, 5), (6, 3), (7, 6)), B = ((6, 4), (6, 2))]

Of these, only for 19 games is there a unique outcome, so this gives us the solution.

Here’s a MiniZinc model that finds all 18 outcomes. (It uses the same convention I used in my Python program, that the 5th game is indicated by 0-0 if it was not played):

```%#! mzn-gecode -a

include "globals.mzn";

% winning scores in a set
predicate wins(var int: a, var int: b) =
(a == 6 /\ (b == 0 \/ b == 1 \/ b == 2 \/ b == 3 \/ b == 4)) \/
(a == 7 /\ (b == 5 \/ b == 6));

% A's winning games
var 6..7: A1;
var 0..6: B1;
var 6..7: A2;
var 0..6: B2;
var 6..7: A3;
var 0..6: B3;

% B's winning games
var 0..6: A4;
var 6..7: B4;
var 0..6: A5;
var {0, 6, 7}: B5;

% A wins 3 games
constraint wins(A1, B1) /\ wins(A2, B2) /\ wins(A3, B3);

% B wins 1 or 2 games
constraint wins(B4, A4) /\ (wins(B5, A5) \/ (A5 = 0 /\ B5 = 0));

% no two sets contain the same number of games
constraint all_different([A1 + B1, A2 + B2, A3 + B3, A4 + B4, A5 + B5]);

% each player won the same number of games in total
var int: g;
constraint sum([A1, A2, A3, A4, A5]) = g;
constraint sum([B1, B2, B3, B4, B5]) = g;

% order the games (to eliminate duplicate solutions)
constraint decreasing([A1 + B1, A2 + B2, A3 + B3]);
constraint decreasing([A4 + B4, A5 + B5]);

solve satisfy;
```

I don’t know if there’s an easy way to add a constraint in MiniZinc to find a unique solution amongst all viable solutions. Here I wrap the MiniZinc model in a Python program (using the minizinc.py wrapper) and use the filter_unique() function from the enigma.py library to select unique solutions:

```from enigma import filter_unique, printf
from minizinc import MiniZinc

# MiniZinc model
p = MiniZinc("enigma1109.mzn", solver="mzn-gecode -a")

# find unique solutions by the number of games
(ss, _) = filter_unique(p.solve(result="g A1 B1 A2 B2 A3 B3 A4 B4 A5 B5"), (lambda s: s.g))

# output unique solutions
for s in ss:
printf("games={s.g} A=({s.A1}-{s.B1}, {s.A2}-{s.B2}, {s.A3}-{s.B3}) B=({s.A4}-{s.B4}, {s.A5}-{s.B5})")
```