Enigmatic Code

Programming Enigma Puzzles

Enigma 1387: Something to declare

From New Scientist #2547, 15th April 2006

I have taken a pack of 10 cards numbered 1 to 10 and dealt them face down, giving a pair of cards to each of the clever kids Andy, Bandy, Candy, Dandy and Endy. They each look at their two cards and will, in turn, have to declare: “power” if the sum of the two is a perfect square or cube; “prime” if the sum is a prime; “big” if the sum is more than 12; “consecutive” if the two numbers are consecutive. For example, if dealt the 4 and 5, at his turn the child would make two declarations: “power” and “consecutive”.

When I asked them in turn for their declarations I am told that Andy, Bandy, Candy and Dandy each have nothing to declare. At that stage Andy said that he knew one particular declaration that Endy was bound to make. Endy then announced how many declarations he was going to make. Then only Bandy and Candy could work out Endy’s pair.

What are Andy’s, Dandy’s and Endy’s pairs?

[enigma1387]

One response to “Enigma 1387: Something to declare

  1. Jim Randell 5 October 2013 at 9:26 am

    This one is a bit tricky to decide what to record at each stage of the program, but once you’ve got the data structures sorted out the program itself is relatively straightforward. This Python program uses the [[ filter2() ]] function, recently added to the enigma.py library, which is similar to Python’s built-in [[ filter() ]] function, except it returns both a list of values for which the function is true and a second list of values where the function returned false. It runs in 46ms.

    from itertools import combinations
    from collections import defaultdict
    from enigma import irange, is_square, is_cube, filter2, printf
    
    numbers = set(irange(1, 10))
    
    powers = set((4, 8, 9, 16))
    primes = set((3, 5, 7, 11, 13, 17, 19))
    
    def declare(x, y):
      s = list()
      t = x + y
      if t in powers: s.append('power')
      if t in primes: s.append('prime')
      if t > 12: s.append('big')
      if abs(x - y) == 1: s.append('consecutive')
      return tuple(s)
    
    # we need to find pairs of numbers that result in no declaration
    ns = list(s for s in combinations(numbers, 2) if not declare(*s))
    printf("[{n} no declaration pairs {ns}]", n=len(ns))
    
    # A's pair -> (common declarations for E, number of declarations for E -> [(B, C, D, E) ...])
    r = dict()
    
    # choose A's pair
    for A in ns:
      v = None
      # choose 3 pairs for B, C, D (in some order)
      for (B, C, D) in combinations(ns, 3):
        # together they should constitute 8 of the numbers
        # and what's left is E's pair
        E = tuple(numbers.difference(A, B, C, D))
        if len(E) != 2: continue
        dE = declare(*E)
        if v is None:
          v = (set(dE), defaultdict(list))
        else:
          v[0].intersection_update(dE)
        v[1][len(dE)].append(((B, C, D), E))
        printf("[A={A} B/C/D={B}/{C}/{D} E={E} ({dE})]", dE=' '.join(dE))
      if v is not None: r[A] = v
    
    # look for common declarations for E, based on A's pair
    for (A, vs) in r.items():
      if len(vs[0]) < 1: continue
      # now look at completions based on E's number of declarations
      for (n, ps) in vs[1].items():
        # map pairs for B/C/D to possible pairs for E
        s = defaultdict(set)
        for (BCD, E) in ps:
          printf("[A={A} (E:{dEA}) n={n} E={E} B/C/D={BCD}]", dEA=' '.join(vs[0]))
          for x in BCD:
            s[x].add(E)
        # find a possible B/C/D assignment such that 1 is ambiguous (D) and 2 are unique (B/C)
        for (BCD, E) in ps:
          # filter BCD into ambiguous values (D) and unique values (B/C)
          (D, BC) = filter2(lambda x: len(s[x]) > 1, BCD)
          printf("[B/C/D={BCD}, ambiguous: {D}, unique: {BC}]")
          if len(D) != 1: continue
          printf("A={A} (E:{dEA}), E={E}, E declares {n} ({dE}), D={D[0]}, B/C={BC[0]}/{BC[1]}", dEA=' '.join(vs[0]), dE=' '.join(declare(*E)))
    

    Solution: Andy’s pair is (1, 5); Dandy’s pair is (2, 10); Endy’s pair is (6, 7).

    Andy predicts that Endy will declare “big”, and Endy in fact makes three declarations “prime, big, consecutive”. Bandy and Candy have the pairs (3, 9) and (4, 8), but we don’t know which is holding which. Dandy can’t determine Endy’s pair, as he can’t distinguish the actual scenario from Endy having (8, 9) and Bandy and Candy having (3, 7) and (4, 6). Although once he knows Bandy and Candy can work out Endy’s pair, Dandy should also be able to work it out also.

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

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

%d bloggers like this: