# Enigmatic Code

Programming Enigma Puzzles

## Enigma 243C: Christmas Fare

From New Scientist #1389, 22nd December 1983 [link]

This completes the archive of puzzles from 1983, and brings the total number of Enigmas on the site to 756. This leaves 20 years of puzzles from 1984 to 2003 to solve.

[enigma243c] [enigma243]

### 2 responses to “Enigma 243C: Christmas Fare”

1. Jim Randell 15 December 2014 at 9:16 am

This Python program looks at all the possibilities. It runs in 62ms.

```from itertools import permutations
from enigma import printf

# the courses
starters = ('grapefruit sorbet', 'melon', 'pate', 'pumpkin soup')
mains = ('duck', 'goose', 'ham', 'turkey')
sauces = ('chestnut', 'cranberry', 'cumberland', 'madeira')
desserts = ('brandy snaps', 'christmas pudding', 'lemon snowballs', 'yule log')

# choose the desserts
for c4 in permutations(desserts):
if c4[2] != 'yule log': continue

# choose the mains
for c2 in permutations(mains):

# choose the sauces
for c3 in permutations(sauces):
# cumberland sauce goes with the duck
if c2[c3.index('cumberland')] != 'duck': continue
# chestnut sauce goes with one of the (other) poultry dishes
if c2[c3.index('chestnut')] not in ('goose', 'turkey'): continue

# choose the starters
for c1 in permutations(starters):
# each menu has fruit in it
if len(set((c1.index('melon'), c4.index('lemon snowballs'), c1.index('grapefruit sorbet'), c3.index('cranberry')))) != 4: continue
# each menu has a geographical dish
if len(set((c1.index('pate'), c3.index('cumberland'), c3.index('madeira'), c2.index('turkey')))) != 4: continue
# each menu has a seasonal dish
if len(set((c4.index('yule log'), c4.index('lemon snowballs'), c4.index('christmas pudding'), c1.index('pumpkin soup')))) != 4: continue

# count the alcoholic drink names in 1.1, 2.2, 3.3, 4.4
a = int(c1[0] == 'melon') + int(c2[1] == 'ham') + int(c3[2] == 'madeira') + int(c4[3] == 'brandy snaps')
if a < 3: continue

for m in zip(c1, c2, c3, c4):
print(m)
print()
```

Solution: The first menu consists of a Melon and Red Wine starter, Roast Duck with Cumberland Sauce and Christmas Pudding.

The recipes are:

1.1 = Melon and Red Wine
1.2 = Roast Duck
1.3 = Cumberland Sauce
1.4 = Christmas Pudding

2.1 = Pâté Provençal
2.2 = Goose
2.3 = Chestnut Sauce
2.4 = Lemon Snowballs

3.1 = Grapefruit Sorbet
3.2 = Ham à la Champagne
3.4 = Yule Log

4.1 = Pumpkin Soup
4.2 = Turkey
4.3 = Cranberry Sauce
4.4 = Brandy Snaps

You could argue that a snowball is an alcoholic drink, and that menus 2 and 4 can therefore be interchanged. The first menu remains unchanged however.

And there may well be the names of other cocktails hidden in there.

2. Jim Randell 17 December 2014 at 12:59 pm

Here’s a variation of my program. It’s a bit faster because it assigns the dishes to the menus, so is comparing integers instead of strings, and the variable names make it more readable. But then we need to assemble the menu at the end in a more complicated fashion. It runs in 47ms.

```from itertools import permutations
from collections import defaultdict
from enigma import printf

menus = (1, 2, 3, 4)

# choose menus to go with the desserts
for (snaps, pudding, snowballs, log) in permutations(menus):

# the yule log is on menu 3
if log != 3: continue

# choose menus to go with the mains
for (duck, goose, ham, turkey) in permutations(menus):

# choose menus to go with the sauces

# cumberland sauce goes with the duck
if cumberland != duck: continue

# chestnut sauce goes with one of the (other) poultry dishes
if chestnut != goose and chestnut != turkey: continue

# choose menus to go with the starters
for (sorbet, melon, pate, soup) in permutations(menus):

# each menu has fruit in it
if len(set((melon, snowballs, sorbet, cranberry))) != 4: continue

# each menu has a geographical dish
if len(set((pate, cumberland, madeira, turkey))) != 4: continue

# each menu has a seasonal dish
if len(set((log, snowballs, pudding, soup))) != 4: continue

# count the alcoholic drink names in 1.1, 2.2, 3.3, 4.4
a = sum(1 for (x, y) in zip(menus, (melon, ham, madeira, snaps)) if x == y)
if a < 3: continue

courses = (
((sorbet, melon, pate, soup), ('Grapefruit Sorbet', 'Melon and Red Wine', 'Pate Provencal', 'Pumpkin Soup')),
((duck, goose, ham, turkey), ('Roast Duck', 'Goose', 'Ham a la Champagne', 'Turkey')),
((chestnut, cranberry, cumberland, madeira), ('Chestnut Sauce', 'Cranberry Sauce', 'Cumberland Sauce', 'Madeira Sauce')),
((snaps, pudding, snowballs, log), ('Brandy Snaps', 'Christmas Pudding', 'Lemon Snowballs', 'Yule Log')),
)
for course in courses:
for (m, n) in zip(*course):