Enigmatic Code

Programming Enigma Puzzles

Enigma 340: Unmagic cross-figure

From New Scientist #1489, 2nd January 1986 [link]

Your task this week is to find the six three-figure numbers making up this cross-figure:

Enigma 340

Across:

1. When added to 4 across this give an odd total.
4. My middle digit equals the number of “1”s used altogether in the 3×3 answer.
5. A perfect cube.

Down:

2. A factor of the difference between 3 down and 1 down.
3. A perfect square.

Although you have not been given the clue for 1 down, I can tell you that the 3×3 answer is an unmagic square. In other words, the sums of the digits in each row of three, each column of three and each diagonal of three are all different.

Find the 3×3 answer.

[enigma340]

Advertisements

3 responses to “Enigma 340: Unmagic cross-figure

  1. Jim Randell 15 April 2016 at 7:37 am

    This Python program runs in 111ms.

    from enigma import irange, printf
    
    # possible digits
    digits = '0123456789'
    
    # 5A is a 3-digit perfect cube
    cubes = list(str(i ** 3) for i in irange(5, 9))
    
    # 3D is a 3-digit perfect square
    squares = list(str(i **  2) for i in irange(10, 31))
    
    # digit sum
    def dsum(s):
      return sum(int(d) for d in str(s))
    
    # 5A is a 3-digit perfect cube
    for a5 in cubes:
      a5s = dsum(a5)
    
      # 3D is a 3-digit perfect square
      for d3 in squares:
        # 5A and 3D share the final digit
        if not(a5[-1] == d3[-1]): continue
        # but not the same digit sum
        d3s = dsum(d3)
        if d3s == a5s: continue
        # 1A + 4A is odd, hence the sum of the first two digits of 3D is odd
        if not(dsum(d3[:2]) % 2 == 1): continue
    
        # choose the first two digits of 4A
        for a4x in irange(10, 99):
          a4 = str(a4x) + d3[1]
          a4s = dsum(a4)
          # the digit sum must be new
          if a4s in (a5s, d3s): continue
          # and also the digit sum of the NE diagonal
          nes = dsum(a5[0] + a4[1] + d3[0])
          if nes in (a4s, a5s, d3s): continue
    
          # and the first digit of 1D
          for d1x in irange(1, 9):
            d1 = str(d1x) + a4[0] + a5[0]
            d1s = dsum(d1)
            # the digit sum should be new
            if d1s in (a4s, a5s, d3s, nes): continue
            # and also the digit sum of the SE diagonal
            ses = dsum(d1[0] + a4[1] + d3[2])
            if ses in (a4s, a5s, d1s, d3s, nes): continue
    
            # difference between 1D and 3D
            d = abs(int(d1) - int(d3))
    
            # first digit of 2D
            for d2x in irange(1, 9):
              d2 = str(d2x) + a4[1] + a5[1]
              d2s = dsum(d2)
              # the digit sum must be new
              if d2s in (a4s, a5s, d1s, d3s, nes, ses): continue
    
              # check 2D is a factor of d
              if not(d % int(d2) == 0): continue
    
              # and check the central digit is the number of 1's
              if (d1 + d2 + d3).count('1') != int(d2[1]): continue
    
              a1 = d1[0] + d2[0] + d3[0]
              a1s = dsum(a1)
              if a1s in (a4s, a5s, d1s, d2s, d3s, nes, ses): continue
              
              printf("a1={a1} a4={a4} a5={a5} / d1={d1} d2={d2} d3={d3}")
    

    Solution: The completed cross-figure puzzle is shown below:

    Enigma 340 - Solution

    • Jim Randell 15 April 2016 at 7:39 am

      I also coded a declarative solution using the MiniZinc constraint solving language.

      It solves the problem in 79ms (using the mzn-g12fd solver):

      include "globals.mzn";
      
      % the numbers
      var 1..9:a;
      var 1..9:b;
      var 1..9:c;
      var 1..9:d;
      var 0..9:e;
      var 0..9:f;
      var 1..9:g;
      var 0..9:h;
      var 0..9:i;
      
      % 3-digit cubes
      set of int: cubes = { pow(x, 3) | x in 5..9 };
      
      % 3-digit squares
      set of int: squares = { pow(x, 2) | x in 10..31 };
      
      % turn digits a, b, c into the number abc
      function var int: number(var int: a, var int: b, var int: c) = 100 * a + 10 * b + c;
      
      % (1a) 1a + 4a is odd
      constraint (c + f) mod 2 == 1;
      
      % (4a) e counts the number of 1's
      constraint sum (x in [a, b, c, d, e, f, g, h, i]) (x == 1) == e;
      
      % (5a) is a perfect cube
      constraint number(g, h, i) in cubes;
      
      % (2d) divides |3d - 1d|
      constraint abs(number(a, d, g) - number(c, f, i)) mod number(b, e, h) == 0;
      
      % (3d) is a perfect square
      constraint number(c, f, i) in squares;
      
      % unmagic square
      constraint alldifferent([
        % rows
        a + b + c, d + e + f, g + h + i,
        % columns
        a + d + g, b + e + h, c + f + i,
        % diagonals
        a + e + i, c + e + g
      ]);
      
      solve satisfy;
      
      output [
        show([a, b, c]) ++ "\n" ++
        show([d, e, f]) ++ "\n" ++
        show([g, h, i])
      ];
      
  2. Brian Gladman 15 April 2016 at 9:57 pm
    cubes = tuple(x ** 3 for x in range(5, 10))
    squares = tuple(x ** 2 for x in range(10, 32))
    
    # try all three digit cubes in row three
    for r3 in cubes:
      g, h, i = (int(x) for x in str(r3))
      sum_r3 = g + h + i
      
      # and all three digit squares in column three
      for c3 in squares:
        c, f, _i = (int(x) for x in str(c3))
        sum_c3 = c + f + i
        # check that they have the same units digit, 
        # that the sum of rows 1 and 2 is odd and
        # that the row and column sums are distinct
        if _i != i or (c + f) % 2 == 0 or sum_c3 == sum_r3:
          continue
          
        # now complete the first two digits of the first row
        for ab in range(10, 100):
          a, b = divmod(ab, 10)
          sum_r1 = a + b + c
          
          # check for a three digit number in column two and that
          # we can still have distinct row, column and diagonal sums 
          if b == 0 or a + i == c + g or sum_r1 in (sum_r3, sum_c3):
            continue
          
          # now try values in the centre and check for distinct sums again
          for e in range(1, 10):
            t = [sum_r1, sum_r3, sum_c3, a + e + i, c + e + g, b + e + h]
            if len(set(t)) != 6:
              continue
            
            # now work out the number of ones still required with only the first
            # digit of row two still to be determined 
            ct1 = e - (a, b, c, e, f, g, h, i).count(1)
            if ct1 > 1:
              continue
            for d in range(1, 10):
              # check that the centre square is equal to the total number of ones
              if (d == 1) == ct1:
                # and that column 2 is a factor of the column 1/column 3 difference
                if abs(c3 - 100 * a - 10 * d - g) % (100 * b + 10 * e + h) == 0:
                  # and that the row, column and diagonal sums are all distinct
                  if len(set(t + [d + e + f, a + d + g])) == 8:
                    fs = '\n\t{} {} {}\n\t{} {} {}\n\t{} {} {}\n'
                    print(fs.format(a, b, c, d, e, f, g, h, i))
    

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: