# Enigmatic Code

Programming Enigma Puzzles

## Enigma 264: Courting couple

From New Scientist #1411, 24th May 1984 [link]

Here is a small test of reasoning, for which you need the Kings, Queens and Jacks from a pack of cards. As usual, cards of the same face value rank in the order Spades, Hearts, Diamonds, Clubs. All you have to do is select two cards, one at a time, so that all ten of these statements shall be true.

1. If the first card is black, the second is a Jack.
2. The first is a Queen, only if the second is a Diamond.
3. The first is a Heart, only if the second is black.
4. The first is a King, if the second is a Spade.
5. The first is a Club, if the second is a King.
6. The first is a Heart, if the second is a Heart.
7. If the higher is a Queen, the lower is a Heart.
8. The lower is a Jack, only if the higher is a Heart.
9. If the lower is red, the second is a Spade.
10. The higher is red, only if the first is not a King.

Bearing in mind that “if” does not mean the same as “only if”, can you specify the two cards in their right order?

[enigma264]

### 3 responses to “Enigma 264: Courting couple”

1. Jim Randell 10 March 2015 at 8:01 am

Programatically it is straightforward to examine all possible selections of cards. This Python program runs in 34ms.

```from itertools import product, permutations
from collections import namedtuple
from enigma import printf

Card = namedtuple('Card', 'value suit')

# possible cards
(black, red) = ('SC', 'HD')
cards = (Card(v, s) for (v, s) in product('KQJ', black + red))

values = {
# value
'K': 30, 'Q': 20, 'J': 10,
# suit
'S': 4, 'H': 3, 'D': 2, 'C': 1,
}

# score a card
def score(c):
return values[c[0]] + values[c[1]]

# select two cards
for (c1, c2) in permutations(cards, 2):

# 1. "if the first is black, the second is a jack'
if c1.suit in black and c2.value != 'J': continue

# 2. "the first is a queen, only if the second is a diamond"
if c1.value == 'Q' and c2.suit != 'D': continue

# 3. "the first is a heart, only if the second is black"
if c1.suit == 'H' and c2.suit not in black: continue

# 4. "the first is a king if the second is a spade"
if c2.suit == 'S' and c1.value != 'K': continue

# 5. "the first is a club if the second is a king"
if c2.value == 'K' and c1.suit != 'C': continue

# 6. "the first is a heart if the second is a heart"
if c2.suit == 'H' and c1.suit != 'H': continue

# 7. "if the higher is a queen, the lower is a heart"
(hi, lo) = sorted((c1, c2), key=score, reverse=True)
if hi.value == 'Q' and lo.suit != 'H': continue

# 8. "the lower is a jack, only if the higher is a heart"
if lo.value == 'J' and hi.suit != 'H': continue

# 9. "if the lower is red, the second is a spade"
if lo.suit in red and c2.suit != 'S': continue

# 10. "the higher is red, only if the first is not a king"
if hi.suit in red and c1.value == 'K': continue

printf("card1 = {c1}, card2 = {c2}", c1=''.join(c1), c2=''.join(c2))
```

Solution:The first card is the Jack of Hearts. The second card is the Jack of Clubs.

2. Brian Gladman 11 March 2015 at 5:18 pm

The same logic (not surprising) but I thought it would be nice to try a different implementation approach. It runs in 1ms on my machine using profile based timing.

```from itertools import permutations, product

# the card faces and their names
faces = Jack, Queen, King = range(3)
fname = 'Jack', 'Queen', 'King'

# the four suits and their names
suits = Clubs, Diamonds, Hearts, Spades = range(4)
sname = 'Clubs', 'Diamonds', 'Hearts', 'Spades'

# Use a class to represent the cards
class Card(object):

# card atttributes: face value and suit
def __init__(self, face, suit):
self.face, self.suit = face, suit

# return a pair of cards in rank order
def sort(self, y):
return (self, y) if (self.face < y.face or
self.face == y.face and self.suit < y.suit) else (y, self)

@property
def is_red(self):
return self.suit in (Diamonds, Hearts)

@property
def is_black(self):

# output a card as a string value
def __repr__(self):
return ' of '.join((fname[self.face], sname[self.suit]))

# the pack of cards
pack = (Card(f, s) for f, s in product(faces, suits))

# consider all permutations of two cards
for first, second in permutations(pack, 2):

# 1. If the first card is black, the second is a Jack
if first.is_black and second.face != Jack:
continue

# 2. The first is a Queen, only if the second is a Diamond
if first.face == Queen and second.suit != Diamonds:
continue

# 3. The first is a Heart, only if the second is black
if first.suit == Hearts and second.is_red:
continue

# 4. The first is a King, if the second is a Spade
if first.face != King and second.suit == Spades:
continue

# 5. The first is a Club, if the second is a King
if first.suit != Clubs and second.face == King:
continue

# 6. The first is a Heart, if the second is a Heart
if first.suit != Hearts and second.suit == Hearts:
continue

# find lower and higher ranking cards
lower, higher = Card.sort(first, second)

# 7. If the higher is a Queen, the lower is a Heart
if higher.face == Queen and lower.suit != Hearts:
continue

# 8. The lower is a Jack, only if the higher is a Heart
if lower.face == Jack and higher.suit != Hearts:
continue

# 9. If the lower is red, the second is a Spade
if lower.is_red and second.suit != Spades:
continue

# 10. The higher is red, only if the first is not a King
if higher.is_red and first.face == King:
continue

print('The {} and the {}.'.format(first, second))
```
3. Hugh Casement 16 March 2015 at 3:59 pm

I imagine one could use Excel here, as Tessa pointed out for no. 260.
What a pity that Microsoft, having helpfully included logical operators in Excel, keeps so very quiet about them. It’s hard to find out from other sources, too, how to use them in practice.