# Enigmatic Code

Programming Enigma Puzzles

## Tantalizer 448: Love and hate

From New Scientist #999, 6th May 1976

To play this vaguely suggestive game you will need nine cards printed with the words:

LOVE AND HATE FEY GUY AGO TONY GUILT NIL.

You and your opponent take it in turns to pick a word until one of you has collected three with a letter in common. Whoever does so first is the winner.

You lose the toss and your opponent snaps up LOVE. Assuming him to be a master at the game, what must you take to stop him winning?

[tantalizer448]

### 5 responses to “Tantalizer 448: Love and hate”

1. Jim Randell 25 July 2018 at 8:56 am

This Python 3 program plays the game with appropriate strategies for the players.

Player 1 is a perfect player, and will prefer to make a play that guarantees him a win. If that is not possible he will try to make a play that guarantees the opponent cannot win.

Player 2’s strategy is to try and make a play that prevents Player 1 from winning.

The program explores all possible moves that conform to the above strategies, but we could simplify it so that the strategies determine a single “best” play in any situation, and not to track the actual sequence of moves.

As it is, this program executes in 755ms.

Run: [ @repl.it ]

```from itertools import combinations
from collections import defaultdict
from enigma import join, printf

# the collection of words
words = 'LOVE AND HATE FEY GUY AGO TONY GUILT NIL'.split()

# find sets of 3 words with a common letter
wins = list(set((x, y, z)) for (x, y, z) in combinations(words, 3) if set(x).intersection(y, z))

# is sequence <s> a winning sequence?
won = lambda s: any(w.issubset(s) for w in wins)

# how we designate outcomes
outcome = {
'1': 'player 1 wins',
'2': 'player 2 wins',
'X': 'draw',
}

# select keys from a dictionary where the value satisfy the specified function
def select(fn=lambda x: True):
return (lambda d: (k for (k, v) in d.items() if fn(v)))

# apply strategy functions in order
def strategy(d, fns=[]):

# play all possible outcomes if no functions work
fns.append(select())

# try each function in turn
sat = 0
for fn in fns:
# find plays that satisfy this function
for k in fn(d):
# and play them
yield from d[k]
sat = 1
if sat: break

# strategy for first player
def player1(d):
return strategy(d, [
# are there choices that ensure a player 1 win?
select(lambda v: all(w == '1' for (w, s) in v)),
# are there choices that exclude a player 2 win?
select(lambda v: all(w != '2' for (w, s) in v)),
])

# strategy for second player
def player2(d):
return strategy(d, [
# are there choices that exclude a player 1 win?
select(lambda v: all(w != '1' for (w, s) in v)),
])

# play the game
def play(s, ws):
# p = 0: player 2 has just played, it's player 1's go
# p = 1: player 1 has just played, it's player 2's go
p = (len(s) % 2)
if p == 1 and len(s) > 4 and won(s[0::2]):
# first player wins
yield ('1', s)
elif p == 0 and len(s) > 5 and won(s[1::2]):
# second player wins
yield ('2', s)
elif not ws:
# draw
yield ('X', s)
else:
# collect outcomes for each word
d = dict((w, list(play(s + [w], ws[:i] + ws[i + 1:]))) for (i, w) in enumerate(ws))
# choose words to play according to the appropriate strategy
fn = (player1, player2)[p]
yield from fn(d)

# play the game and collect outcomes by player 2's choice
r = defaultdict(lambda: defaultdict(int))
for (w, s) in play(words[:1], words[1:]):
printf("[{w} <- ({s})]", w=outcome[w], s=join(s, sep=" "))
r[s[1]][w] += 1

# output choices for player 2
for (k, d) in r.items():
printf("play {k}:")
# output outcomes for this choice
for (w, n) in d.items():
printf("  {w}: {n} games", w=outcome[w])
```

Solution: Player 2 must play TONY in order to stop Player 1 from winning.

There are 8 sets of 3 words that share a letter, and if we place the words on a grid, as below, and draw lines connecting the winning sets, we get:

We see that the game is equivalent to Noughts and Crosses (see [ https://en.wikipedia.org/wiki/Tic-tac-toe ]).

In the situation described in the puzzle, Player 1 chooses a corner square (LOVE), so the only situation in which Player 2 can force a draw (if Player 1 is a perfect player) is by playing the centre square (TONY).

If Player 2 plays an edge square next to Player 1 (say NIL, but playing FEY will play out similarly) then Player 1 will respond by playing the centre square (TONY). Player 2 must then play AGO in order to stop Player 1 from winning on the next move, and Player 1 can then play HATE to acquire 2 of the E words and 2 of the T words. Player 2 cannot stop Player 1 from acquiring one of the remaining words required to make a line, so always loses in this scenario.

If Player 2 plays one of the other edge squares (say AND, but GUY will play out similarly) the Player 1 responds with the centre square (TONY). Player 2 must play AGO, and Player 1 plays HATE, giving him the option of FEY and GUILT to win on E or T, and Player 2 cannot block both these. So Player 2 always loses in this scenario too.

If Player 2 played one of the remaining corner squares, then Player 1 can respond by playing a corner square and can force a win.

So the only scenario in which Player 2 can do better is to play the centre square (TONY) and force a draw.

As the program shows there are 82 possible games that start with LOVE and TONY and all end in a draw.

2. Jim Olson 25 July 2018 at 10:45 pm

Doesn’t Player 1 win with Love,Tony by playing the corners Guilt then Hate and finally Ago.

• Jim Randell 25 July 2018 at 11:17 pm

Player 1 can’t win by playing LOVE, GUILT, HATE, AGO, because no 3-subset of those 4 words have a letter in common.

Also, if the game sequence was 1=LOVE, 2=TONY, 1=GUILT, then Player 2 would be forced to play NIL (to stop Player 1 from completing the L line). If Player 1 then played one of the remaining corners (HATE or AGO), Player 2 could play AND to win along the N line.

• Jim Randell 26 July 2018 at 8:08 am

Or are you suggesting that if the game opens with Player 1 taking a corner, and Player 2 takes the centre square, then if Player 1 can acquire the remaining three corners, on his final go he will be guaranteed to make a line by playing the last edge square?

The flaw in this scheme is that while Player 1 is acquiring the corners, Player 2 is collecting the edge squares, and by the time he has the centre square and 2 or 3 edge squares he will have collected a line and won, so Player 1 will never get to make his final move.

• Jim Olson 26 July 2018 at 5:56 pm

Yes, the latter but you immediately demonstrated my error of not considering the obvious rules of the game. So I had the correct answer after all and was talking myself out of it.

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