11
\$\begingroup\$

Though challenges involving magic squares abound on this site, none I can find so far ask the golfer to print / output all normal magic squares of a certain size. To be clear, a normal magic square of order \$n\$ is:

  1. An \$n\times n\$ array of numbers.
  2. Each positive integer up to and including \$n^2\$ appears in exactly one position in the array, and
  3. Each row, column, and both main- and anti-diagonals of the array sum to the same "magic number".

Your challenge is to write the shortest program that prints all normal magic squares of order 3. There are 8 such squares. For the purposes of this challenge, the characters surrounding the output array, such as braces or brackets that accompany arrays in many languages, are allowed. For a non-optimized example in python, see here. Happy golfing!

\$\endgroup\$
8
  • 5
    \$\begingroup\$ Welcome to Code Golf! This looks like a reasonably well-specified challenge, but for future reference, we strongly recommend using the Sandbox to get feedback on challenge ideas before posting them to the main site. \$\endgroup\$
    – pxeger
    Sep 1 '21 at 13:44
  • 2
    \$\begingroup\$ Also, your output requirement "print them, and the brackets are allowed" is unusual; I'd recommend using the site default rules about I/O, to allow (for example) submissions to return the array from a function rather than submit a full program. \$\endgroup\$
    – pxeger
    Sep 1 '21 at 13:46
  • \$\begingroup\$ Closely related (generate a magic square of a given size, rather than generate all) \$\endgroup\$ Sep 1 '21 at 14:01
  • 1
    \$\begingroup\$ I'm a bit confused by the wording. Is there any input to the code at all? The wording and title of most of the body seem to imply that we take \$n\$ and produce all the order \$n\$ magic squares, but the final bit just says order 3. \$\endgroup\$
    – Wheat Wizard
    Sep 1 '21 at 14:10
  • 1
    \$\begingroup\$ Can we output the 8 matrices without separators, like this? (The output is unambiguous because each matrix is known to have 3 rows). If not, what separators are allowed? \$\endgroup\$
    – Luis Mendo
    Sep 1 '21 at 18:18

16 Answers 16

9
\$\begingroup\$

Python 3, 61 bytes

Outputs every magic square, each as three comma-separated rows in the form: XXX,XXX,XXX.

for c in'\zÁßİĺ':print(f'{ord(c)*1780218+275171220:,}')

Try it online!

Explanation

There are only eight magic squares, each of which are rotations/reflections of each other. In their flattened decimal representation, they are:

276951438, 294753618, 438951276, 492357816, 618753294, 672159834, 816357492, 834159672

What's remarkable about these numbers is that they are all congruent to 1017648 (mod 1780218), meaning they can be expressed in the form x*1780218+1017648. In the code, we actually use x*1780218+275171220 as the formula instead, since it takes up less bytes to represent in our string. The number is then comma-formatted with f'{x:,}' to show the separation of the rows.

Python 3, 61 bytes

The same method but does not contain unicode characters, is (annoyingly) the same length.

n=50863752
for c in b'~	PFP	':n-=~c*1780218;print(f'{n:,}')

Try it online!

\$\endgroup\$
3
\$\begingroup\$

JavaScript (Node.js), 201 bytes

_=>(h=S=>S[1]?S.flatMap(e=>h(S.filter(a=>a!=e)).map(a=>[e,...a])):[S])([1,2,3,4,5,6,7,8,9]).filter(e=>[[0,3],[0,1],[3,1],[6,1],[1,3],[2,3],[0,4],[2,2]].every(l=>e[l[0]]+e[l[0]+=l[1]]+e[l[0]+l[1]]==15))

Try it online!

Explanation

The integers 1 thru 9 should appear once each in the magic square, so the sum of all elements is \$\frac{9(9+1)}{2}=45\$ using a relatively simple formula.

Therefore, since each row forms one-third of the magic square, the sum of each row should equal 15 (and, by definition, the sums of columns and three-length diagonals must also equal 15).

The first thing my code does is that it creates all permutations of [1,2,3,4,5,6,7,8,9] (362880 of them to be exact) and checks for the ones which follow specifications. This is done using a special procedure I used in the Parker square challenge.

Rows, columns and diagonals are encoded in a format [b, i]:

  • b is the starting index
  • i is the number of indexes to add

The obtained subarray for such an array [b, i] would be (if the original array was l) l[b], l[b+i], l[b+i+i]. This is done using a slightly golfier method.

We check if, for each array, the corresponding sub-array (obtained via simple indexing methods) has a sum of 15.

As it turns out there are only eight magic squares of order 3. Right after writing my solution (and golfing it), I returned to this question and clicked the math.se link to find that someone had come up with a very simple formula. This notwithstanding, I am posting my answer because I think it offers a more creative approach than simple hard-coding. I am open to suggestions for reducing length.

\$\endgroup\$
4
  • \$\begingroup\$ Welcome to Code Golf! Great answer. \$\endgroup\$ Sep 1 '21 at 15:44
  • \$\begingroup\$ @BrowncatPrograms I'm not really new to Code Golf as a matter of fact ;) I used to be RecursiveCo but I wanted to restart for some reason so I signed up again. \$\endgroup\$ Sep 1 '21 at 15:46
  • \$\begingroup\$ I posted a clarification that the challenge is indeed only for the n=3 case. I think with this constraint, very lean code can be written, and that's what I'm looking for! I expect a few dozen bytes should do it in some language. \$\endgroup\$
    – rajb245
    Sep 1 '21 at 15:51
  • \$\begingroup\$ @rajb245 Thanks for the information! Let me update my answer. \$\endgroup\$ Sep 1 '21 at 15:52
3
\$\begingroup\$

Python 3, 89 83 bytes

The 8 magic squares of order 3 are all just rotations / reflections of each other, so this stores one of them and calculates the remaining ones.

exec("x='672','159','834'"+(';*map(print,*x),print();x=[*zip(*x)][::-1]'*4)[:-6]*2)

Try it online!

A few bytes can be saved by using an uglier output format: Try it online!


Here are two programs with numpy that don't use hardcoding. The first one is quite slow, 157 bytes:

import itertools as I,numpy as N
for p in I.permutations(N.r_[1:10]):d=N.r_[p].reshape(3,3);{*d.sum(0),*d.sum(1),d.trace(),d[:,::-1].trace()}-{15}or print(d)

Try it online!

And the second one is decently fast, 175 bytes:

from numpy import*
from itertools import*
d=r_[[*permutations(r_[1:10])]].reshape(-1,3,3)
print(d[all(c_[sum(d,1),sum(d,2),trace(d,0,1,2),trace(flip(d,2),0,1,2)]==15,axis=1)])

Try it online!

\$\endgroup\$
3
\$\begingroup\$

R, 79 78 76 bytes

m=matrix(c(2,7,6,9,5,1,4,3,8),3)
while({show(m);show(t(m));m-4})m=t(m[3:1,])

Try it online!

Hardcodes one square and loops though its rotations, displaying also a transposition with every iteration.

Abuses the fact that while takes only the first element in a vector/matrix to check the looping condition.

\$\endgroup\$
3
\$\begingroup\$

MATL, 15 12 bytes

4:"3tYL@X!tP

Try it online! Outputs all matrices without separation. Note that the output is unambiguous.

Alternatively, this version uses a line as separator, for 15 bytes.

How it works

4:      % Range [1 2 3 4]
"       % For each k in that range
  3tYL  %   Magic square of size 3 (gives one of the 8 possible squares)
  @     %   Push k
  X!    %   Rotate matrix 90 degrees k times
  t     %   Duplicate
  P     %   Flip vertically
        % End (implicit)
        % Display stack, bottom to top (implicit)
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Ahh, a magic built-in, quite literally :) \$\endgroup\$ Sep 1 '21 at 17:20
  • \$\begingroup\$ Ah builtins! I guess I didn't specify anything about using that. \$\endgroup\$
    – rajb245
    Sep 2 '21 at 18:34
2
\$\begingroup\$

Haskell, 102 91 bytes

r=reverse
m=map
[id,r,m r,r.m r]<*>m(m$m((+0).read.pure).show)[[276,951,438],[294,753,618]]

Try it online!

Doesn't actually bother calculating anything, just compresses a hard-coded output.

There are some tactics used for compression

  1. We encode each row as a base 10 number and use m((+0).read.pure).show to turn it into a list of intergers.
  2. We only encode 2 of the squares and use flips to get the remaining squares.

I tried also other methods

  • Only encoding the first two rows / columns and calculating the remainder
  • Encoding each starting square only as a single number and splitting it into pieces

Plus some specific optimizations that only make sense with the above (e.g. multiply by 33 or 66).

\$\endgroup\$
2
\$\begingroup\$

05AB1E, 25 bytes

9Lœε3ô}ʒ4.DÅ\ªsÅ/ªsÅ|ªO˜Ë

Try it online!

Brute force, takes ~42 seconds to run on TIO.

Attempted explanation

9Lœε3ô}                      # All possible 3×3 squares (1..9 permutations, chunk in 3 pieces)
       ʒ4.D                  # Filter by (Create 4 copies of the current square first to get the parts)
           Å\ªsÅ/ªsÅ|ª       # Take the rows, cols and diagonals in a list (Through builtins and appending into one another)
                      O˜Ë    # Flattened sums are equal? Determines magic square (filter) 

Or, 23 bytes if flat lists of magic squares are acceptable:

9Lœʒ3ô4.DÅ\ªsÅ/ªsÅ|ªO˜Ë

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 20 bytes: 9Lœ3δôʒ`yÅ\yÅ/yø`)OË: ε3ô} can be 3δô; Å| can be ø (no idea why Å| is even a builtin tbh.. maybe it vectorizes or something; but I personally haven't used it yet); ʒ4.DÅ\ªsÅ/ªsøªO˜Ë can be ʒDÅ\ªyÅ/ªyøªO˜Ë (y is the value of filters/maps/foreach loops, so no need for the duplicates + swaps), after which it can be golfed 1 byte further to ʒ`yÅ\yÅ/yø`)OË (or alternatively ʒDø«yÅ\ªyÅ/ªOË). \$\endgroup\$ Sep 3 '21 at 8:20
  • \$\begingroup\$ Oh actually, just ʒDøyÅ\yÅ/)O˜Ë is enough for the final part, so it's 19 bytes. \$\endgroup\$ Sep 3 '21 at 8:28
2
\$\begingroup\$

Jelly, 22 18 bytes

9Œ!i⁼ṛɗƇ5s€3§;SEƲƇ

Try it online!

The Footer simply formats the output into a nice column of grids, remove it to see the list of matrices

-4 bytes thanks to Jonathan Allan

How it works

9Œ!i⁼ṛɗƇ5s€3§;SEƲƇ - Main link. Takes no arguments
9                  - Set the left argument to 9
 Œ!                - All permutations of [1,2,3,4,5,6,7,8,9]
      ɗ 5          - Group the previous 3 links into a dyad f(p, 5):
   i               -   Index of 5 in p
     ṛ             -   Yield 5
    ⁼              -   Does the index of 5 equal 5?
       Ƈ           - Keep those permutations for which f(p, 5) is true
         s€3       - Split each into a 3x3 matrix
                ƲƇ - Keep those matrices for which the following is true:
            §      -   Sums of the rows
              S    -   Sums of the columns
             ;     -   Concatenate
               E   -   Are all equal?
\$\endgroup\$
3
  • \$\begingroup\$ Out of the squares with all the row and column sums equal those which also have their diagonal sums also equal are those with \$5\$ in the centre. As such you can filter these from the permutations and save four bytes like this. Still doesn't beat hardcoding one and constructing all symmetries though (currently for that I have 16). \$\endgroup\$ Sep 1 '21 at 17:15
  • \$\begingroup\$ @JonathanAllan That's a nice observation, thanks! \$\endgroup\$ Sep 1 '21 at 17:20
  • \$\begingroup\$ this approach was what i was expecting when i asked the question; i had not considered basing the algorithm on rotations/reflections of a single hardcoded literal. great answer! \$\endgroup\$
    – rajb245
    Sep 18 '21 at 20:00
2
\$\begingroup\$

Python 2, 59 bytes

l="276","951","438"
exec"r=zip(*l);l=r[::-1];print r,l,;"*4

Try it online!

Prints the eight arrays space-separated.

\$\endgroup\$
3
  • \$\begingroup\$ Why the last comma? Without it seems to work fine for -1: Try it online!. (Is it outgolfing xnor, or was it just a spelling mistake?) \$\endgroup\$
    – pajonk
    Sep 2 '21 at 15:41
  • 1
    \$\begingroup\$ @pajonk It would make two different separators between outputs (spaces and newlines), and it's not clear to me that's allowed. \$\endgroup\$
    – xnor
    Sep 2 '21 at 17:59
  • \$\begingroup\$ Ah, ok. I get it now. Thanks for clarification! \$\endgroup\$
    – pajonk
    Sep 2 '21 at 18:12
1
\$\begingroup\$

Jelly, 16 bytes

“ÑṆ6Ẉ’Ds3ZU$Ƭ;U$

A niladic Link that yields a list of eight lists of lists of digits, the eight magic squares.

Try it online!

How?

Builds one then constructs the other seven using rotations and reflections.

“ÑṆ6Ẉ’Ds3ZU$Ƭ;U$ - Link: no arguments
“ÑṆ6Ẉ’           - base 250 literal = 276951438
      D          - decimal digits -> [2,7,6,9,5,1,4,3,8]
       s3        - split into threes -> [[2,7,6],[9,5,1],[4,3,8]]
            Ƭ    - collect up until a fixed point is found under:
           $     -   last two links as a monad - f=rotate(current):
         Z       -     transpose - i.e. swap rows with columns
          U      -     upend - i.e. reverse each row
               $ - last two links as a monad - f=add_reflections(four_rotations):
              U  -   upend - i.e. revese each row of each rotation
             ;   -   (four_rotations) concatenate (upended)

Alternatives

⁽Xð×3Œ?s3ZU$Ƭ;U$
“=ẹʋ‘×3D‘ZU$Ƭ;U$
\$\endgroup\$
1
\$\begingroup\$

Japt, 29 21 bytes

Well, this is pretty damned slightly less hideous! Outputs a 3D-array.

4o!z49#ë7816ì ò3
cUmy

Test it (footer formats output into squares)

\$\endgroup\$
1
\$\begingroup\$

brainfuck, 317 bytes

++++++>++>-[----->+>+>+>+>+>+>+>+>+>+>+>+<<<<<<<<<<<<]++++++++++>->++++>+++>----->++++++>++>-->----->+>>+++++>-----<<<<<<<<<<<<
<[->>.>.>.>.<.<.<.<.>>>>>.>.>.>.<.<.<.<<<<<.>>>>>>>>>.>.>.>.<.<.<.<<<<<<<<<..>>>>>>>>>.>.>.>.<.<.<.<<<<<<<<<.>>>>>.>.>.>.<.<.<.<<<<<.>.>.>.>.<.<.<.<..<<[->>>+>->>>->>+>>>+>-<<<<<<<<<<<<<]>]

Score includes one unnecessary newline for "clarity."

Line 1 sets the code up.

Line 2 prints a vertically mirrored pair (separated by .) on three rows, then the horizontal mirrors of the first pair (Slightly odd but more user readable than some other answers!)

Then, internally, the six values off the 4 5 6 diagonal are adjusted (by +/-6 each) to flip the square diagonally, and line 2 is run again to print the other four squares.

Try it online!

Commented code

++++++>++>-                                                                 FIll cells 0 1 and 2 with 6 2 and 255 respectively for looping
[----->+>+>+>+>+>+>+>+>+>+>+>+<<<<<<<<<<<<]                                 Iterate 255/5=51 times to fill cells 3 to 14 with ASCII "2"
++++++++++>                                                                 Cell 2 = 10 for linefeed
->++++>+++>----->++++++>++>-->----->+>>+++++>-----<<<<<<<<<<<<              Adjust cells 3 to 14 to 276/951/438/ (cannot include period in comments so used slash instead)
<[->                                                                        Iterate twice (counter in cell 1)
  >.>.>.>.<.<.<.<.>>>>>.>.>.>.<.<.<.<<<<<.>>>>>>>>>.>.>.>.<.<.<.<<<<<<<<<..   Output characters for 1st pair of squares (each row needs more arrows to get away from cell 2 linefeed) 
  >>>>>>>>>.>.>.>.<.<.<.<<<<<<<<<.>>>>>.>.>.>.<.<.<.<<<<<.>.>.>.>.<.<.<.<..   Output characters for 2nd pair of squares (basically the reverse of the first)
  <<[->>>+>->>>->>+>>>+>-<<<<<<<<<<<<<]>                                      Flip diagonal by ajusting the 6 values off the 4 5 6 diagonal plus or minus 6
]                                                                           And loop to output 3rd and 4th pairs of squares
\$\endgroup\$
0
\$\begingroup\$

Charcoal, 21 bytes

”)‴vv»!C”F⁴«F²«D‖»⟲»⎚

Try it online! Link is to verbose version of code. Explanation:

”)‴vv»!C”

Write a compressed magic square of digits to the canvas.

F⁴«F²«D‖»⟲»

Output all the rotations and reflections of the canvas.

Clear the canvas so that there's no implicit output.

The squares can be padded for easier viewing at a cost of 3 bytes:

←&!↶⸿⦃3εⅉ‽”F⁴«F²«D‖»⟲»⎚

Try it online! Link is to verbose version of code.

If two columns of four squares is acceptable output, then for 17 bytes:

”←&!↶⸿⦃3εⅉ‽”⟲C‖C¬

Try it online! Link is to verbose version of code. Explanation:

”←&!↶⸿⦃3εⅉ‽”

Output a padded magic square. (An unpadded square would save 3 bytes, but it would make the output format unreadable.)

⟲C

Make a 90° rotated copy.

‖C¬

Make four reflected copies of each copy. (One of these is reflected both horizontally and vertically, which is equivalent to a 180° rotation. Also the horizontal and vertical reflections are simply 180° rotations of each other. This therefore produces all of the rotations and their reflections.)

\$\endgroup\$
0
\$\begingroup\$

Perl 5, 70 bytes

map{say for/.../g,''}map$_*1780218+275171220,unpack"W*",'\zÁßİĺ'

Try it online!

Borrowed method from @dingledooper's python3 answer.

\$\endgroup\$
0
\$\begingroup\$

Ruby, 67 bytes

r=259149258
"

Q\x1EG\x1EQ
".bytes{|x|p (r+=x*1780218).digits 1000}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

APL (Dyalog Unicode), 47 bytes

⎕←(3 3⍴⍕)¨1↓+\50863752,1780218×1+⎕UCS'~	PFP	'

Try it online!

nice, my sixth APL answer

fast hardcoding (fork of dingledooper method)

'...' magic string

⎕UCS cast to unicode codepoints

1+ increment

...× multiply by magic

..., prepend by magic

+\ cumulative sum

1↓ decapitate

(... for each

stringify

3 3⍴ mold to 3×3 matrix

⎕← to stdout

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.