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.

Enigma 1270

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

    Enigma 1270 - Solutions A

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

    Enigma 1270 - Solutions B

  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
    

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: