A magic square is an NxN square matrix whose numbers consist of consecutive numbers arranged so that the sum of each row and column, and both diagonals are equal to the same sum (which is called the magic number or magic constant).

A magic square of singly even order has a size that is a multiple of 4, plus 2 (e.g. 6, 10, 14). This means that the subsquares have an odd size, which plays a role in the construction.




Task
Create a magic square of 6 x 6.




 Related tasks
 Magic squares of odd order
 Magic squares of doubly even order

 See also
 Singly Even Magic Squares (1728.org)



with javascript_semantics
function swap(sequence s, integer x1, y1, x2, y2)
    {s[x1,y1],s[x2,y2]} = {s[x2,y2],s[x1,y1]}
    return s
end function
 
function se_magicsq(integer n)
 
    if n<6 or mod(n-2,4)!=0 then
        crash("illegal size (%d)",{n})
    end if
 
    sequence sq = repeat(repeat(0,n),n)
    integer magic_sum = n*(n*n+1)/2,
            sq_d_2 = n/2,
            q2 = power(sq_d_2,2),
            l = (n-2)/4,
            x1 = floor(sq_d_2/2)+1, x2,
            y1 = 1, y2,
            r = 1
 
    -- fill pattern a c
    --              d b
    -- main loop for creating magic square in section a
    -- the value for b,c and d is derived from a
    while true do
        if sq[x1,y1]=0 then
            x2 = x1+sq_d_2
            y2 = y1+sq_d_2
            sq[x1,y1] = r       -- a
            sq[x2,y2] = r+q2    -- b
            sq[x2,y1] = r+q2*2  -- c
            sq[x1,y2] = r+q2*3  -- d
            if mod(r,sq_d_2)=0 then
                y1 += 1
            else
                x1 += 1
                y1 -= 1
            end if
            r += 1
        end if
        if x1>sq_d_2 then
            x1 = 1
            while sq[x1,y1] <> 0 do
                x1 += 1
            end while
        end if
        if y1<1 then
            y1 = sq_d_2
            while sq[x1,y1] <> 0 do
                y1 -= 1
            end while
        end if
        if r>q2 then exit end if
    end while
 
    -- swap left side
    for y=1 to sq_d_2 do
        y2 = y+sq_d_2
        for x=1 to l do
            sq = swap(sq, x,y, x,y2)
        end for
    end for
 
    -- make indent
    y1 = floor(sq_d_2/2) +1
    y2 = y1+sq_d_2
    x1 = 1
    sq = swap(sq, x1,y1, x1,y2)
    x1 = l+1
    sq = swap(sq, x1,y1, x1,y2)
 
    -- swap right side
    for y=1 to sq_d_2 do
        y2 = y+sq_d_2
        for x=n-l+2 to n do
            sq = swap(sq, x,y, x,y2)
        end for
    end for
 
    -- check columms and rows
    for y=1 to n do
        r = 0
        l = 0
        for x=1 to n do
            r += sq[x,y]
            l += sq[y,x]
        end for
        if r<>magic_sum
        or l<>magic_sum then
            crash("error: value <> magic_sum")
        end if
    end for
 
    -- check diagonals
    r = 0
    l = 0
    for x=1 to n do
        r += sq[x,x]
        x2 = n-x+1
        l += sq[x2,x2]
    end for
    if r<>magic_sum
    or l<>magic_sum then
        crash("error: value <> magic_sum")
    end if
 
    return sq
end function
 
pp(se_magicsq(6),{pp_Nest,1,pp_IntFmt,"%3d",pp_StrFmt,3,pp_IntCh,false,pp_Pause,0})
