Magic Squares

December 12, 2014

Magic squares are an arrangement of consecutive counting numbers starting from 1 into rows and columns in which every row, column and the two main diagonals all sum to the same number. Magic squares are an important element of recreational mathematics, and have been known since antiquity; this magic square of order 3, with magic sum 15, was published in China in 650BC:

4 9 2
3 5 7
8 1 6

That magic square was constructed by the “start bottom, move down and right, else up” rule: Starting from either of the center cells on the bottom row, enter a 1, then move to the next square diagonally down and right (wrapping around the sides of the square if necessary), then enter the next number in sequence, 2, and so on. However, if the next square is occupied, move instead to the next square up from the current square, then continue the sequence. Various rules like “start left, move down and right, else up” and “start top, move up and right, else down” also work, but rules like “start top, move down and left, else up” don’t; I’ll let you have the pleasure of figuring out which rules work and which don’t. This method works only for odd orders; there are other methods for even orders, which we may examine at some other time.

In the example square, the starting cell is the center cell on the bottom edge, where you see 1. Moving down and right and wrapping to the top of the next column, enter 2. Then moving down and right and wrapping to the left of the next row, enter 3. The next cell down and right already contains 1, so instead move up from the current cell and enter 4. Then moving down and right, enter 5. Then moving down and right, enter 6. The next cell down and right, wrapping both the row and column, already contains 4, so instead move up from the current cell and enter 7. Then moving down and right and wrapping to the left of the next row, enter 8. Finally, moving down and right and wrapping to the top of the next column, enter 9.

Your task is to write a program that takes an odd order n, one of the four starting cells and a rule and generates the indicated magic square. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

2 Responses to “Magic Squares”

  1. Mike said

    Python version. Accepts rule like “start top, move up and left, else down”. Leave out the non-direction words: “top up left down”, or abbreviate it to a string of the initial letters: ‘tuld’.

    import math, re
    
    def print_magic(sq):
        w = math.ceil(math.log10(len(sq)*len(sq)))
        fmt = "{{:{}}}".format(w).format
        for row in sq:
            print(*(fmt(col) for col in row))
    
            
    def magic(size=3, rule="start top, move up and right, else down"):
        if len(rule) > 5:
            pattern = r't(?=op)|b(?=ottom)|u(?=p)|d(?=own)|l(?=eft)|r(?=ight)'
            rule = re.findall(pattern, rule)
    
        r = 0 if rule[0] == 't' else size - 1 if rule[0] == 'b' else size // 2
        c = 0 if rule[0] == 'l' else size - 1 if rule[0] == 'r' else size // 2
        dr = -1 if 'u' in rule[1:3] else 1 if 'd' in rule[1:3] else 0
        dc = -1 if 'l' in rule[1:3] else 1 if 'r' in rule[1:3] else 0
        er = -1 if 'u' in rule[3:] else 1 if 'd' in rule[3:] else 0
        ec = -1 if 'l' in rule[3:] else 1 if 'r' in rule[3:] else 0
    
        square = [[None for c in range(size)] for r in range(size)]
        for n in range(1, size * size + 1):
            square[r][c] = n
            r = (r + dr) % size
            c = (c + dc) % size
            if square[r][c] is not None:
                r = (r - dr + er) % size
                c = (c - dc + ec) % size
        return square
    

Leave a Reply

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 )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: