Enigmatic Code

Programming Enigma Puzzles

Enigma 1690: Dolly the sheep

From New Scientist #2857, 24th March 2012 [link]

Dolly was the name given to the first cloned sheep at the UK’s Roslin Institute in 1996. The letters in the diagram represent, in some order, the numbers 1 to 16 forming a magic square where each row, column and main diagonal have the same sum. The letters of the word “clone”, and letters not within the square, have their values according to a=1, b=2 etc. but other letters within the square may or may not.

What is the sum d+o+l+l+y?

[enigma1690]

Advertisements

4 responses to “Enigma 1690: Dolly the sheep

  1. Jim Randell 21 March 2012 at 7:17 pm

    I adapted my Magic Square Solver (last seen in Enigma 1682). I should probably wrap it up as a generic library.

    The following Python program runs in 100ms.

    import copy
    from enigma import irange, printf
    
    # the numbers in the magic square
    numbers = set(irange(1, 16))
    
    # the magic constant
    s = sum(numbers) // 4
    
    # the magic square itself
    square = [0] * 16
    
    # the filled out squares
    for c in list("clone"):
      n = ord(c) - 97
      square[n] = n+1
    
    # remove the numbers that are already filled out
    numbers.difference_update(square)
    
    # magic lines
    lines = (
      # rows
      ( 0,  1,  2,  3),
      ( 4,  5,  6,  7),
      ( 8,  9, 10, 11),
      (12, 13, 14, 15),
      # columns
      ( 0,  4,  8, 12),
      ( 1,  5,  9, 13),
      ( 2,  6, 10, 14),
      ( 3,  7, 11, 15),
      # diagonals
      ( 0,  5, 10, 15),
      ( 3,  6,  9, 12),
    )
    
    class Impossible(Exception): pass
    class Solved(Exception): pass
    
    class Puzzle:
    
      def __init__(self, square, numbers):
        self.square = square
        self.numbers = numbers
    
      def clone(self):
        return copy.deepcopy(self)
    
      def become(self, other):
        for x in vars(other).keys():
          setattr(self, x, getattr(other, x))
    
      # complete missing squares
      def complete(self):
        if not self.numbers: raise Solved
        for line in lines:
          ns = tuple(self.square[i] for i in line)
          if ns.count(0) != 1: continue
          n = s - sum(ns)
          if not n in self.numbers: raise Impossible
          i = ns.index(0)
          self.square[line[i]] = n
          self.numbers.discard(n)
          return True
        return False
    
      # make a guess at a square
      def hypothetical(self):
        if not self.numbers: raise Solved
        i = self.square.index(0)
        for n in self.numbers:
          new = self.clone()
          new.square[i] = n
          new.numbers.discard(n)
          if new.solve():
            self.become(new)
            return True
        raise Impossible
    
      # solve the square
      def solve(self):
        try:
          while True:
            while self.complete(): pass
            self.hypothetical()
        except (Impossible, Solved):
          pass
        return not(self.numbers)
    
    
    p = Puzzle(square, numbers)
    if p.solve():
      for w in ("abcd", "efgh", "ijkl", "mnop"):
        for i in list(w):
          print("{i}={l:2d}".format(i=i, l=p.square[ord(i) - 97]), end=' ')
        printf('')
      dolly = list(p.square[ord(i) - 97] for i in list("doll"))
      dolly.append(ord('y') - 96)
      printf("dolly = {dolly}, sum = {sum}", sum=sum(dolly))
    

    Solution: d+o+l+l+y = 77.

    • Jim Randell 24 March 2012 at 9:24 am

      I’ve folded the Magic Square solver into my enigma.py module, so if you have the latest version of the module the program becomes:

      from enigma import MagicSquare, printf
      
      # make a 4x4 magic square
      p = MagicSquare(4)
      
      # set the initial values
      for c in list("clone"):
        i = ord(c) - 97
        p.set(i, i + 1)
      
      # solve the square
      if p.solve():
        # output the square
        for w in ("abcd", "efgh", "ijkl", "mnop"):
          for i in list(w):
            print("[{i}={l:2d}]".format(i=i, l=p.get(ord(i) - 97)), end=' ')
          print('')
        # output the solution
        dolly = list(p.get(ord(i) - 97) for i in list("doll"))
        dolly.append(ord('y') - 96)
        printf("dolly = {dolly}, sum = {sum}", sum=sum(dolly))
      
  2. Naim Uygun 21 March 2012 at 10:33 pm

    I will check your script. Thanks for your share.

    Here is the magic square :
    16-2-3-13
    5-11-10-8
    9-7-6-12
    4-14-15-1

    The answer is 77
    (without running any program or script)

  3. Hugh Casement 27 May 2016 at 10:49 am

    Once again an associative magic square where opposite pairs sum to 17, half the magic constant.  It’s formed by writing the integers 1 to 16 in order and swapping opposite pairs on the two main diagonals.  Dürer then transposed the middle two columns to give the year of his birth, 1514.  I’m sure there are more interesting magic squares!

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: