# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1270: Christmas star

From New Scientist #2426, 20th December 2003 [link]

If you place a number in each of the twelve circles on this star you can then calculate the “line-total” of each of the six lines by adding up the four numbers along the line. Similarly you can calculate the “triangle-total” of each of the six small triangles by adding up the three numbers around the triangle.

Your task is to place the numbers 1 to 12 in the circles so that each of the line-totals is the same, and there is a triangle-total larger than the line-total, and a triangle-total less than half the line-total.

What number is diametrically opposite 1? And what number is diametrically opposite 2?

[enigma1270]

Advertisements

### 2 responses to “Enigma 1270: Christmas star”

1. Jim Randell 17 December 2014 at 9:19 am

This Python program runs in 1.8s.

It could be made more efficient (but more complicated), by considering lines with fewer numbers of blanks at each recursive step (and in particular filling out lines with only one missing number), in a similar style to my solution to Enigma 241. But for a problem of this size it is perhaps not worth it.

```from enigma import irange, printf

#     A
#  B C D E
#   F   G
#  H I J K
#     L
#
# the "magic" lines are ACFH ADGK HIJK BCDE BFIL EGJL
# each must sum to s
#
# so: 6s = 2(A+B+C+D+E+F+G+H+I+J+K+L)
#     3s = A+B+C+D+E+F+G+H+I+J+K+L
#
# as A to L are 1 to 12 we have:
#
# 3s = T(12) = 78
#
# so: s = 26
#
# we can reduce duplicate solutions by requiring A < B, E, H, K, L
# and B < E

# lines
lines = (
(0, 2, 5, 7),
(0, 3, 6, 10),
(7, 8, 9, 10),
(1, 2, 3, 4),
(1, 5, 8, 11),
(4, 6, 9, 11)
)

# triangles
triangles = (
(0, 2, 3),
(3, 4, 6),
(6, 9, 10),
(8, 9, 11),
(5, 7, 8),
(1, 2, 5)
)

# update the number placements, rejecting duplicate solutions
# ps - current placements
# i - index to update
# n - value to update at index i
# s - line sum
def update(ps, i, n, s):
ps = list(ps)
ps[i] = n
# check for duplicate solutions
if not(ps[0] is None or all(ps[j] is None or ps[0] < ps[j] for j in (1, 4, 7, 10, 11))): return
if not(ps[1] is None or ps[4] is None or ps[1] < ps[4]): return
# check the lines
for g in lines:
ns = tuple(ps[j] for j in g)
if None in ns: continue
if sum(ns) != s: return
return ps

# place the numbers
# s - magic sum
# ns - numbers to place
# ps - placements
def solve(s, ns, ps):
# are we done?
if not ns:
# determine the triangle total
ts = tuple(sum(ps[i] for i in g) for g in triangles)
# there should be a triangle total larger than the magic sum
if not any(x > s for x in ts): return
# and a triangle total less than half the magic sum
if not any(x < (s + 1) // 2 for x in ts): return
# numbers opposite 1 and 2
opp1 = ps[11 - ps.index(1)]
opp2 = ps[11 - ps.index(2)]
printf("opp(1)={opp1}, opp(2)={opp2}, ps={ps}, ts={ts}")
else:
# find an empty slot
i = ps.index(None)
# choose a number to place
for n in ns:
ps2 = update(ps, i, n, s)
if ps2:
solve(s, ns.difference([n]), ps2)

solve(26, set(irange(1, 12)), [None] * 12)
```

Solution: 3 is diametrically opposite 1, and 5 is diametrically opposite 2.

There are essentially 4 different solutions.

One pair of solutions has triangle sums of 12, 18 and 27 (each pair of diametrically opposed triangles have the same sum):

The other pair of solutions has triangle sums of 12, 21 and 27:

2. arthurvause 18 December 2014 at 9:27 pm

As Jim points out, it is not really worth putting too much effort into tuning a solution, but I couldn’t resist having a go.

If the inner ring c,d,f,g,i,j are defined, the values of the outer ring a,b,e,h,k,l can be deduced (see code beolw for the formulae). Using a similar idea to Jim’s to fix c as the smallest member of the inner ring and avoiding reflections by only considering one permutation of d,f :

```from itertools import permutations, combinations

for c in range(1,8): # w.l.o.g. c is the smallest number in the inner ring
for d,f in combinations( range(c+1,13),2): # avoiding reflections
for remaining_inner in combinations( set(range(c+1,13))-set((d,f)),3):
if (sum(remaining_inner)+c+d+f)%2==0: # sum has to be even (see formulae for outer ring items)
outercandidates = set(range(1,13))- set((c,d,f))-set(remaining_inner)
for g,i,j in permutations( remaining_inner ):
a =( 26 -d-g-f-c+i+j)/2
if  a in outercandidates:
k = (26 -d-g+f+c-i-j)/2
if  k in outercandidates - set((a,)):
h = (26 +d+g-f-c-i-j)/2
if ( h in outercandidates - set((a,k))):

e = (26 -c-d-g-j+f+i)/2
l = (26 +c+d-g-j-f-i)/2
b = (26 -c-d+g+j-f-i)/2
if set((a,b,c,d,e,f,g,h,i,j,k,l))== set(range(1,13)):
triangle_sums = [a+c+d,b+c+f,d+e+g,f+h+i,g+j+k,i+j+l]
if max(triangle_sums)>26 and min(triangle_sums)<13:
print a,b,c,d,e,f,g,h,i,j,k,l
```

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