Enigmatic Code

Programming Enigma Puzzles

Enigma 311: Three score years and ten

From New Scientist #1459, 6th June 1985 [link]

The ages of George’s four daughters add up to 70. Amanda says that the exact figures are 8, 16, 21, and 25. But Brenda says that Celia is 15. Delia, on the other hand, says that Celia is 18.

This is all very confusing, until you know about a strange family habit. It is to state one’s own age correctly but to overstate the age of anyone older and to understate the age of anyone younger.

Even after making all possible deductions so far, you cannot work out the age of each daughter. For that you need a bit more information, for instance the number of years separating Belinda and Celia.

Please supply the name and age of the four.

There are now 894 Enigma puzzles on the site, and I think this is around half of all the Enigma puzzles published in New Scientist, from Enigma 1 in February 1979 to Enigma 1780 in December 2013.

To help me keep on top of posting the remaining Enigma puzzles I’m going to change the posting schedule to two puzzles a week, one on Friday and one on Monday. Which means, if I can keep sourcing the puzzles, I will have enough to last another 8.6 years!

[enigma311]

Advertisements

One response to “Enigma 311: Three score years and ten

  1. Jim Randell 18 September 2015 at 12:39 pm

    This Python 2 program runs in 87ms. (I used the filter_unique() function from the enigma.py library, rather than spin the possibilities into a collections.defaultdict()).

    from enigma import irange, diff, filter_unique, printf
    
    # decompose total <t> into <n> numbers
    def decompose(t, n, s=[]):
      if n == 1:
        yield s + [t]
      else:
        for x in irange(1, t - n + 1):
          for r in decompose(t - x, n - 1, s + [x]): yield r
    
    # would someone of age <a> say that sisters whose actual ages are <rs> are <ss>?
    def check(a, rs, ss):
      if not rs:
        return True
      else:
        # consider the next real age
        r = rs[0]
        # find a corresponding stated age
        for (i, s) in enumerate(ss):
          if (s < r < a or s > r > a) and check(a, rs[1:], ss[:i] + ss[i + 1:]):
            return True
        # it is not possible
        return False
    
    # A says the ages are (8, 16, 21, 25), so one of these is her age
    ages = (8, 16, 21, 25)
    
    # accumulate possible ages
    r = list()
    for A in ages:
      # and possible remaining ages
      for (B, C, D) in decompose(70 - A, 3):
    
        # check A's statement
        if not check(A, [B, C, D], diff(ages, [A])): continue
    
        # B says that C is 15
        if not check(B, [C], [15]): continue
    
        # D says that C is 18
        if not check(D, [C], [18]): continue
    
        printf("[A={A} B={B} C={C} D={D}]")
        r.append((A, B, C, D))
    
    # there should be multiple possibilities
    assert len(r) > 1
    
    # but the result can be uniquely determined from the difference in age between B and C
    fn = lambda (A, B, C, D): abs(B - C)
    (r, _) = filter_unique(r, fn)
    
    # output the results
    for (A, B, C, D) in r:
      printf("A={A} B={B} C={C} D={D}")
    

    Solution: Amanda is 16. Brenda is 24. Celia is 17. Delia is 13.

    The program presented does not run under Python 3 because it uses Tuple Parameter Unpacking which was removed from Python 3 (see PEP 3113). I think this was a bit of a shame, because although you can easily work around the removal it does make the resulting code look messy. (On the plus side if you do modify the program to run under Python 3 you can use the yield from construct in the recursive call in decompose() and stop it from working in Python 2).

    Before we are given the difference between B and C there are 5 possibilities:

    A=16, B=22, C=17, D=15 (B−C=5)
    A=16, B=23, C=17, D=14 (B−C=6)
    A=16, B=24, C=17, D=13 (B−C=7)
    A=21, B=22, C=17, D=10 (B−C=5)
    A=21, B=23, C=17, D=9 (B−C=6)

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: