Home More Samples
```///////////////////////////////////////////////////////////////////////////////
//
// http://mathsforeurope.digibel.be/magic.htm
//
// Ultra Super Magic Squares 5x5
//
///////////////////////////////////////////////////////////////////////////////
//
// An Ultra Super Magic Square is a Magic square that is complete and
// symmetrical.
//
// (1) Complete property
// In the squares, not only the major but also the minor diagonals add up to
// the number 65. For example:
//
//   A * * * *
//   * B * * *
//   * * C * *
//   * * * D *    A + B + C + D + E = 65    (Major diagonal)
//   * * * * E
//
//   * A * * *
//   * * B * *
//   * * * C *
//   * * * * D    A + B + C + D + E = 65
//   E * * * *
//
//   * * A * *
//   * * * B *
//   * * * * C
//   D * * * *    A + B + C + D + E = 65
//   * E * * *
//
// ...
// ...   and so on.
//
// (2) Self complement
// The square is invariant for the complemental transform. If we change each
// number "n" of the square by "26-n" , we get the same square rotated.
// Also called self-similar or self-joined square.
//
// (3) Five-star constellation patterns;
// Sum of the five numbers of all small squares and the centers sum to the same
// number 65.
//
//   1  *  *  *  9    1  * 22  *  *    * 15  * 18  *    *  * 22  *  9
//   *  *  *  *  *    * 19  *  *  *    *  *  6  *  *    *  *  *  5  *
//   *  * 13  *  *   10  * 13  *  *    *  2  * 24  *    *  * 13  * 16
//   *  *  *  *  *    *  *  *  *  *    *  *  *  *  *    *  *  *  *  *
//  17  *  *  * 25    *  *  *  *  *    *  *  *  *  *    *  *  *  *  *
//   ....
//   ....
//                                                      *  *  *  *  *
//                                                      *  *  *  *  *
//                                                      *  * 13  * 16
//      ....      ....     ....     ....    ....        *  *  *  7  *
//                                                      *  *  4  * 25
// (4) Rhonbohedral patterns
// Furthermore, five numbers of all small rhonbohedrons add up to
// the same number 65.
//
//   * 15  *  *  *    *  * 22  *  *
//  23 19  6  *  *    * 19  6  5  *
//   *  2  *  *  *    *  * 13  *  *
//   *  *  *  *  *    *  *  *  *  *
//   *  *  *  *  *    *  *  *  *  *   ......
//
//   ......
//   ......
//
//   *  *  *  *  *    *  * 22  *  *
//   *  *  *  *  *    *  *  *  *  *
//   *  *  * 24  *   10  * 13  * 16
//   *  * 20  7  3    *  *  *  *  *
//   *  *  * 11  *    *  *  4  *  *
//
// The F1 code below will calculate all 16 Ultra Super Magic Squares 5x5.
// The code itself is quite straightforward and can be easily adapted to calculate
// Ultra Super Magic Squares of other dimensions.
//
// To execute the code, run the query
//
//         all UltraSuperMS5x5q()
//
// The program will generate and print all solutions in the following format:
//
// +---------------+
// |  1 15 22 18  9|
// | 23 19  6  5 12|
// | 10  2 13 24 16|
// | 14 21 20  7  3|
// | 17  8  4 11 25|
// +---------------+
//
// ___ Solution: 1 __________________________________
//
// ....
// ....
// ....
//
// +---------------+
// |  5 23 16 14  7|
// | 11  9  2 25 18|
// | 22 20 13  6  4|
// |  8  1 24 17 15|
// | 19 12 10  3 21|
// +---------------+
//
// ___ Solution: 16 __________________________________
//
// Number of solutions: 16   Number of backtracks: 3085
// Elapsed time: 00:00:01
//
//
///////////////////////////////////////////////////////////////////////////////

MS5 = [0..24]->>L[1..25]  // an array of 25 numbers 1..25

pred UltraSuperMS5x5q() iff
UltraSuperMS5x5(ms) &
PrintFormattedSolution(ms)

///////////////////////////////////////////////////////////////////////////////
// This is the main workhorse code. Explicitely specify all constraints
// (mentioned above) required for Ultra Super Magic Square 5x5.
//
pred UltraSuperMS5x5(ms::MS5) iff
ms = [ a1, a2, a3, a4, a5,
b1, b2, b3, b4, b5,
c1, c2, c3, c4, c5,
d1, d2, d3, d4, d5,
e1, e2, e3, e4, e5] &

// set constraints to avoid generating solutions with
// rotational/mirror symetries.

a1 < a5 & a1 < e5 & a1 < e1 & a5 < e1 &

// constraints for rows
a1 + a2 + a3 + a4 + a5 = 65 &
b1 + b2 + b3 + b4 + b5 = 65 &
c1 + c2 + c3 + c4 + c5 = 65 &
d1 + d2 + d3 + d4 + d5 = 65 &
e1 + e2 + e3 + e4 + e5 = 65 &

// constraints for columns
a1 + b1 + c1 + d1 + e1 = 65 &
a2 + b2 + c2 + d2 + e2 = 65 &
a3 + b3 + c3 + d3 + e3 = 65 &
a4 + b4 + c4 + d4 + e4 = 65 &
a5 + b5 + c5 + d5 + e5 = 65 &

// major + minor diagonals
a1 + b2 + c3 + d4 + e5 = 65 &
a2 + b3 + c4 + d5 + e1 = 65 &
a3 + b4 + c5 + d1 + e2 = 65 &
a4 + b5 + c1 + d2 + e3 = 65 &
a5 + b1 + c2 + d3 + e4 = 65 &

// reversed major + minor digonals
a5 + b4 + c3 + d2 + e1 = 65 &
a4 + b3 + c2 + d1 + e5 = 65 &
a3 + b2 + c1 + d5 + e4 = 65 &
a2 + b1 + c5 + d4 + e3 = 65 &
a1 + b5 + c4 + d3 + e2 = 65 &

// five star constellations patterns
a1 + a5 + c3 + e1 + e5 = 65 &

a1 + a3 + b2 + c1 + c3 = 65 &
a2 + a4 + b3 + c2 + c4 = 65 &
a3 + a5 + b4 + c3 + c5 = 65 &

b1 + b3 + c2 + d1 + d3 = 65 &
b2 + b4 + c3 + d2 + d4 = 65 &
b3 + b5 + c4 + d3 + d5 = 65 &

c1 + c3 + d2 + e1 + e3 = 65 &
c2 + c4 + d3 + e2 + e4 = 65 &
c3 + c5 + d4 + e3 + e5 = 65 &

// Rhonbohedral patterns
a2 + b1 + b2 + b3 + c2 = 65 &
a3 + b2 + b3 + b4 + c3 = 65 &
a4 + b3 + b4 + b5 + c4 = 65 &

b2 + c1 + c2 + c3 + d2 = 65 &
b3 + c2 + c3 + c4 + d3 = 65 &
b4 + c3 + c4 + c5 + d4 = 65 &

c2 + d1 + d2 + d3 + e2 = 65 &
c3 + d2 + d3 + d4 + e3 = 65 &
c4 + d3 + d4 + d5 + e4 = 65 &

a3 + c1 + c3 + c5 + e3 = 65 &

// Create a joint square "msj"
JointSquare(ms,msj,0) &

// If the joint square after some rotations is the same as
// the "magic" square, we have an self-joined (or symmetrical) square.
(Rotated180(msj,msr) | Rotated90(msj,msr) | Rotated270(msj,msr)) &

msr = ms

///////////////////////////////////////////////////////////////////////////////
// If we substitute each number x of a Magic square of order n by n**2 + 1 - x
// (the x from the formula signifies the number in the original square), then
// it can be proved that we get another Magic square. We call them joined
// squares.
local pred JointSquare(msa::MS5,msj::MS5,i:<I) iff
if i < Len(msj) then
msj(i) = 26 - msa(i) & JointSquare(msa,msj,i+1)
end

///////////////////////////////////////////////////////////////////////////////
// Rotate a square clockwise by 90 degrees:
//
//     0  1  2  3  4      20 15 10  5  0
//     5  6  7  8  9      21 16 11  6  1
//    10 11 12 13 14  ->  22 17 12  7  2
//    15 16 17 18 19      23 18 13  8  3
//    20 21 22 23 24      24 19 14  9  4
//
local pred Rotated90(ms::MS5,msr::MS5) iff
msr( 0) = ms(20) &
msr( 1) = ms(15) &
msr( 2) = ms(10) &
msr( 3) = ms( 5) &
msr( 4) = ms( 0) &
msr( 5) = ms(21) &
msr( 6) = ms(16) &
msr( 7) = ms(11) &
msr( 8) = ms( 6) &
msr( 9) = ms( 1) &
msr(10) = ms(22) &
msr(11) = ms(17) &
msr(12) = ms(12) &
msr(13) = ms( 7) &
msr(14) = ms( 2) &
msr(15) = ms(23) &
msr(16) = ms(18) &
msr(17) = ms(13) &
msr(18) = ms( 8) &
msr(19) = ms( 3) &
msr(20) = ms(24) &
msr(21) = ms(19) &
msr(22) = ms(14) &
msr(23) = ms( 9) &
msr(24) = ms( 4)

///////////////////////////////////////////////////////////////////////////////
// Rotate a square by 180 degrees. This is done by two successive rotations
// by 90 degrees.
//
local pred Rotated180(ms::MS5,msr::MS5) iff
Rotated90(ms,ms90) & Rotated90(ms90,msr)

///////////////////////////////////////////////////////////////////////////////
// Rotate a square by 270 degrees. This is done by successive rotations
// by 180 and by 90 degrees.
//
local pred Rotated270(ms::MS5,msr::MS5) iff
Rotated180(ms,ms180) & Rotated90(ms180,msr)

///////////////////////////////////////////////////////////////////////////////
// Print the one dimensional array of 25 elements in a form of a 5x5 matrix
//
local proc PrintFormattedSolution(ms:<MS5) iff
Print('\n+---------------+\n') &
PrintRows(ms,0) &
Print('+---------------+\n')

local proc PrintRows(ms:<MS5,row:<I) iff
if row < 5 then
Print('|') & PrintCols(ms,row,0) & Print('|\n') & PrintRows(ms,row+1)
end

local proc PrintCols(ms:<MS5, row:<I,col:<I) iff
if col < 5 then
PrintNum3(ms(row*5+col)) & PrintCols(ms,row,col+1)
end

///////////////////////////////////////////////////////////////////////////////
// Print each number 1..25 as three characters, by prepending blank spaces
// where neccessary.
//
local proc PrintNum3(i:<L) iff
if i < 10 then Print(' ') end & Print(' ') & Print(i)

```