Enigmatic Code

Programming Enigma Puzzles

Enigma 1430: Doubt and fury

From New Scientist #2591, 17th February 2007

The latest creation acquired by our local art gallery consists of six separate squares with labels such as “Doubt” and “Fury”, each of a different colour, including yellow and purple.  The six squares have to be arranged at the gallery into a rectangle consisting of two rows with three squares in each row.

The curator remembered that “Charm” is above the red square (which is not “Angst”), that the blue square is between “Belief” and the orange square, and that the green square has no edge in common with “Envy”.  He also remembered that the three labels in the top row are in alphabetical order, but in the bottom row neither the labels nor the colours are in alphabetical order.

So he arranged the squares satisfying all these conditions, but unfortunately he still got it wrong, thus infuriating the artist.

What (in alphabetical order of the labels) were the colours of the squares?

[enigma1430]

3 responses to “Enigma 1430: Doubt and fury

  1. Jim Randell 15 October 2012 at 10:03 pm

    This Python program runs in 206ms. It’s a direct interpretation of the problem statement and checks the conditions over every possible permutation of the labels and colours, then looks for arrangements that have ambiguous orders.

    from itertools import permutations, product
    from collections import defaultdict
    
    labels  = ( 'A', 'B', 'C', 'D', 'E', 'F' )
    colours = ( 'b', 'g', 'o', 'p', 'r', 'y' )
    
    # adjacency matrix (squares that share edges)
    adj = ( (1, 3), (0, 2, 4), (1, 5), (0, 4), (1, 3, 5), (2, 4) )
    
    # count the results
    r = defaultdict(list)
    
    # arrange the labels and colours
    for (l, c) in product(permutations(labels), permutations(colours)):
    
      # "Charm is above the Red square (which is not Angst)"
      i = c.index('r') # index of Red
      if i < 3: continue # Red must be in the bottom row
      if l[i] == 'A': continue # Red is not Angst
      if l[i - 3] != 'C': continue # Charm must be above Red
    
      # "the Blue square is between Belief and the Orange square"
      i = c.index('b') # index of Blue
      if i not in (1, 4): continue # Blue must be in the central column
      # and Blue is between Belief and Orange
      if not((l[i - 1] == 'B' and c[i + 1] == 'o') or
             (l[i + 1] == 'B' and c[i - 1] == 'o')): continue
    
      # "the Green square has no edge in common with Envy"
      i = c.index('g') # index of Green
      j = l.index('E') # index of Envy
      if i == j or j in adj[i]: continue
      
      # "labels in the top row are in alphabetical order"
      if not(l[0] < l[1] < l[2]): continue
    
      # "in the bottom row neither the labels nor the colours are in alphabetical order"
      if l[3] < l[4] < l[5]: continue
      if c[3] < c[4] < c[5]: continue
    
      # colours of the squares, in order of the labels
      s = tuple(c[l.index(i)] for i in labels)
    
      r[s].append((l, c))
    
    for (k, v) in r.items():
      if len(v) < 2: continue
      print(k, v)
    

    Solution: The squares, in alphabetical order of the labels are: Green, Yellow, Blue, Orange, Purple and Red.

    • Jim Randell 16 October 2012 at 10:34 pm

      If you rearrange so the tests are in a different order to that stated in the puzzle text you can get the run time down to 77ms.

      from itertools import permutations
      from collections import defaultdict
      
      labels  = ( 'A', 'B', 'C', 'D', 'E', 'F' )
      colours = ( 'b', 'g', 'o', 'p', 'r', 'y' )
      
      # adjacency matrix (squares that share edges)
      adj = ( (1, 3), (0, 2, 4), (1, 5), (0, 4), (1, 3, 5), (2, 4) )
      
      # count the results
      r = defaultdict(list)
      
      # arrange the labels
      for l in permutations(labels):
      
        # "labels in the top row are in alphabetical order"
        if not(l[0] < l[1] < l[2]): continue
      
        # "in the bottom row neither the labels nor the colours are in alphabetical order"
        if l[3] < l[4] < l[5]: continue
      
        # "the Blue square is between Belief and the Orange square"
        # so Belief cannot be in the central column
        if 'B' in (l[1], l[4]): continue
      
        # and now arrange the colours
        for c in permutations(colours):
      
          # "in the bottom row neither the labels nor the colours are in alphabetical order"
          if c[3] < c[4] < c[5]: continue
      
          # "Charm is above the Red square (which is not Angst)"
          i = c.index('r') # index of Red
          if i < 3: continue # Red must be in the bottom row
          if l[i] == 'A': continue # Red is not Angst
          if l[i - 3] != 'C': continue # Charm must be above Red
      
      
          # "the Blue square is between Belief and the Orange square"
          i = c.index('b') # index of Blue
          if i not in (1, 4): continue # Blue must be in the central column
          # and Blue is between Belief and Orange
          if not((l[i - 1] == 'B' and c[i + 1] == 'o') or
                 (l[i + 1] == 'B' and c[i - 1] == 'o')): continue
      
          # "the Green square has no edge in common with Envy"
          i = c.index('g') # index of Green
          j = l.index('E') # index of Envy
          if i == j or j in adj[i]: continue
      
          # colours of the squares, in order of the labels
          s = tuple(c[l.index(i)] for i in labels)
      
          r[s].append((l, c))
      
      for (k, v) in r.items():
        if len(v) < 2: continue
        print(k, v)
      
  2. arthurvause 18 October 2012 at 10:02 am

    Here is a version adapted from my Python code for the classic Zebra/Water puzzle. http://arthurvause.blogspot.co.uk/2012/10/who-owns-zebra.html

    The adaptation isn’t entirely satisfactory as there are several “reverse lookups” required.

    # arrangement of squares is:  1 2 3
    #                             4 5 6 
    
    from itertools import permutations as perm
    
    Labels = ['Angst','Belief','Charm','Doubt','Envy','Fury']
    Colours = ['Red','Blue','Orange','Green','Yellow','Purple']
    
    def lab_pos( ):
      for p in perm(Labels): yield {a:b for (a,b) in zip(p,range(1,7))}
    
    def col_lab( ):
      for p in perm(Labels): yield {a:b for (a,b) in zip(Colours,p)}
    
    def key(d, v): # find a key in dictionary d with value v
      return [name for name, val in d.items() if val == v][0]
    
    label_positions = [ x for x in lab_pos()
               if x['Charm'] < 4
               and key(x,1) < key(x,2) < key(x,3)
               and not (key(x,4) < key(x,5)  and key(x,5) < key(x,6)) ]
    
    for cl in col_lab():
      solutions = [ lp for lp in label_positions
        if lp[cl['Blue']] in [2,5]
        and abs(lp[cl['Blue']]-lp[cl['Orange']])==1
        and lp['Charm']+3 == lp[cl['Red']]
        and lp['Angst'] != lp[cl['Red']]
        and abs(lp[cl['Blue']]-lp['Belief'])==1
        and lp['Belief'] != lp[cl['Orange']]
        and not ( sorted( (lp['Envy'], lp[cl['Green']])) in
                 [[1,2],[2,3],[1,4],[2,5],[3,6],[4,5],[5,6]])
        and lp['Envy'] != lp[cl['Green']]
        and not ( key(cl,key(lp,4)) < key(cl,key(lp,5))
                  and key(cl,key(lp,5)) < key(cl,key(lp,6)) ) ]
    
      if len(solutions) > 1:
        for lab in Labels:
          print lab, key(cl,lab)
    

Leave a Comment

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