# 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:

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.

[enigma340]

### 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:

• 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))
```

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