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]

Advertisements

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):
        return self.suit in (Clubs, Spades)
    
      # 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.

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: