Magic squares of doubly even order: Difference between revisions

From Rosetta Code
Content added Content deleted
(comment deleted!)
(→‎{{header|Ruby}}: Added Ruby)
Line 405: Line 405:
</pre>
</pre>


=={{header|zkl}}==
=={{header|Ruby}}==
{{trans|Java}}
<lang zkl>class MagicSquareDoublyEven{
fcn init(n){ var result=magicSquareDoublyEven(n) }
fcn toString{
sink,n:=Sink(String),result.len(); // num collumns
fmt:="%2s ";
foreach row in (result)
{ sink.write(row.apply('wrap(n){ fmt.fmt(n) }).concat(),"\n") }
sink.write("\nMagic constant: %d".fmt((n*n + 1)*n/2));
sink.close();
}
fcn magicSquareDoublyEven(n){
if (n<4 or n%4!=0 or n>16)
throw(Exception.ValueError("base must be a positive multiple of 4"));
bits,size,mult:=0b1001011001101001, n*n, n/4;
result:=n.pump(List(),n.pump(List(),0).copy); // array[n,n] of zero


<lang ruby>def double_even_magic_square(n)
foreach i in (size){
raise ArgumentError, "Need multiple of four" if n%4 > 0
bitsPos:=(i%n)/mult + (i/(n*mult)*4);
block_size, max = n/4, n*n
value:=(bits.bitAnd((2).pow(bitsPos))) and i+1 or size-i;
pre_pat = [true, false, false, true,
result[i/n][i%n]=value;
false, true, true, false]
}
pre_pat += pre_pat.reverse
result;
pattern = pre_pat.flat_map{|b| [b] * block_size} * block_size
}
flat_ar = pattern.each_with_index.map{|yes, num| yes ? num+1 : max-num}
}
flat_ar.each_slice(n).to_a
MagicSquareDoublyEven(8).println();</lang>
end

def to_string(square)
n = square.size
fmt = "%#{(n*n).to_s.size + 1}d" * n
square.inject(""){|str,row| str << fmt % row << "\n"}
end

puts to_string(double_even_magic_square(8))</lang>
{{out}}
{{out}}
<pre>
<pre>
1 2 62 61 60 59 7 8
1 2 62 61 60 59 7 8
9 10 54 53 52 51 15 16
56 55 11 12 13 14 50 49
48 47 19 20 21 22 42 41
48 47 19 20 21 22 42 41
40 39 27 28 29 30 34 33
25 26 38 37 36 35 31 32
32 31 35 36 37 38 26 25
33 34 30 29 28 27 39 40
24 23 43 44 45 46 18 17
24 23 43 44 45 46 18 17
49 50 14 13 12 11 55 56
16 15 51 52 53 54 10 9
57 58 6 5 4 3 63 64
57 58 6 5 4 3 63 64

Magic constant: 260
</pre>
</pre>

Revision as of 18:27, 11 April 2016

Magic squares of doubly even order is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

A magic square of doubly even order has a size that is a multiple of four (e.g. 4, 8, 12).
This means that the subsquares also have an even size, which plays a role in the construction.

1 2 62 61 60 59 7 8
9 10 54 53 52 51 15 16
48 47 19 20 21 22 42 41
40 39 27 28 29 30 34 33
32 31 35 36 37 38 26 25
24 23 43 44 45 46 18 17
49 50 14 13 12 11 55 56
57 58 6 5 4 3 63 64


The task: create a magic square of 8 x 8.

Cf.
See also


C++

<lang cpp>

  1. include <iostream>
  2. include <sstream>
  3. include <iomanip>

using namespace std;

class magicSqr { public:

   magicSqr() { sqr = 0; }
   ~magicSqr() { if( sqr ) delete [] sqr; }

   void create( int d ) {
       if( sqr ) delete [] sqr;
       while( d % 4 > 0 ) { d++; };
       sz = d;
       sqr = new int[sz * sz];
       memset( sqr, 0, sz * sz * sizeof( int ) );
       fillSqr();
   }
   void display() {
       cout << "Doubly Even Magic Square: " << sz << " x " << sz << "\n";
       cout << "It's Magic Sum is: " << magicNumber() << "\n\n";
       ostringstream cvr; cvr << sz * sz;
       int l = cvr.str().size();

       for( int y = 0; y < sz; y++ ) {
           int yy = y * sz;
           for( int x = 0; x < sz; x++ ) {
               cout << setw( l + 2 ) << sqr[yy + x];
           }
           cout << "\n";
       }
       cout << "\n\n";
   }

private:

   void fillSqr() {
       int tempAll[][4] = {{ 1, 0, 0, 1 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 1, 0, 0, 1 } };
       int rep = sz / 4, s = 1, curRow = 0, curCol = 0;
       int temp[4];
       
       for( int v = 0; v < rep; v++ ) {
           for( int rt = 0; rt < 4; rt++ ) {
               memcpy( temp, tempAll[rt], 4 * sizeof( int ) );
               for( int h = 0; h < rep; h++ ) {
                   for( int t = 0; t < 4; t++ ) {
                       if( temp[t] ) sqr[curCol + sz * curRow] = s;
                       s++;
                       curCol++;
                   }
               }
               curCol = 0;
               curRow++;
           }
       }
       s = 1;
       curRow = sz - 1;
       curCol = curRow;
       
       for( int v = 0; v < rep; v++ ) {
           for( int rt = 0; rt < 4; rt++ ) {
               memcpy( temp, tempAll[rt], 4 * sizeof( int ) );
               for( int h = 0; h < rep; h++ ) {
                   for( int t = 0; t < 4; t++ ) {
                       if( !temp[t] ) sqr[curCol + sz * curRow] = s;
                       s++;
                       curCol--;
                   }
               }
               curCol = sz - 1;
               curRow--;
           }
       }
   }
   int magicNumber() { return sz * ( ( sz * sz ) + 1 ) / 2; }

   void inc( int& a ) { if( ++a == sz ) a = 0; }

   void dec( int& a ) { if( --a < 0 ) a = sz - 1; }

   bool checkPos( int x, int y ) { return( isInside( x ) && isInside( y ) && !sqr[sz * y + x] ); }

   bool isInside( int s ) { return ( s < sz && s > -1 ); }

   int* sqr;
   int sz;

};

int main( int argc, char* argv[] ) {

   magicSqr s; s.create( 8 );
   s.display();
   return 0;

} </lang>

Output:
Doubly Even Magic Square: 8 x 8
It's Magic Sum is: 260

   1  63  62   4   5  59  58   8
  56  10  11  53  52  14  15  49
  48  18  19  45  44  22  23  41
  25  39  38  28  29  35  34  32
  33  31  30  36  37  27  26  40
  24  42  43  21  20  46  47  17
  16  50  51  13  12  54  55   9
  57   7   6  60  61   3   2  64

FreeBASIC

<lang freebasic>' version 18-03-2016 ' compile with: fbc -s console ' doubly even magic square 4, 8, 12, 16...

Sub Err_msg(msg As String)

   Print msg
   Beep : Sleep 5000, 1 : Exit Sub

End Sub

Sub de_magicsq(n As UInteger, filename As String = "")

   ' filename <> "" then save square in a file
   ' filename can contain directory name
   ' if filename exist it will be overwriten, no error checking
   If n < 4 Then
       Err_msg( "Error: n is to small")
       Exit Sub
   End If
   If (n Mod 4) <> 0 Then
       Err_msg "Error: not possible to make doubly" + _
       " even magic square size " + Str(n)
       Exit Sub
   End If
   Dim As UInteger sq(1 To n, 1 To n)
   Dim As UInteger magic_sum = n * (n ^ 2 +1) \ 2
   Dim As UInteger q = n \ 4
   Dim As UInteger x, y, nr = 1
   Dim As String frmt = String(Len(Str(n * n)) +1, "#")
   ' set up the square
   For y = 1 To n
       For x = q +1 To n - q
           sq(x,y) = 1
       Next
   Next
   For x = 1 To n
       For y = q +1 To n - q
           sq(x, y) Xor= 1
       Next
   Next
   ' fill the square
   q = n * n +1
   For y = 1 To n
       For x = 1 To n
           If sq(x,y) = 0 Then
               sq(x,y) = q - nr
           Else
               sq(x,y) = nr
           End If
           nr += 1
       Next
   Next
   ' check columms and rows
   For y = 1 To n
       nr = 0 : q = 0
       For x = 1 To n
           nr += sq(x,y)
           q += sq(y,x)
       Next
       If nr <> magic_sum Or q <> magic_sum Then
           Err_msg "Error: value <> magic_sum"
           Exit Sub
       End If
   Next
   ' check diagonals
   nr = 0 : q = 0
   For x = 1 To n
       nr += sq(x, x)
       q += sq(n - x +1, n - x +1)
   Next
   If nr <> magic_sum Or q <> magic_sum Then
       Err_msg "Error: value <> magic_sum"
       Exit Sub
   End If
   ' printing square's on screen bigger when
   ' n > 19 results in a wrapping of the line
   Print "Single even magic square size: "; n; "*"; n
   Print "The magic sum = "; magic_sum
   Print
   For y = 1 To n
       For x = 1 To n
           Print Using frmt; sq(x, y);
       Next
       Print
   Next
   ' output magic square to a file with the name provided
   If filename <> "" Then
       nr = FreeFile
       Open filename For Output As #nr
       Print #nr, "Single even magic square size: "; n; "*"; n
       Print #nr, "The magic sum = "; magic_sum
       Print #nr,
       For y = 1 To n
           For x = 1 To n
               Print #nr, Using frmt; sq(x,y);
           Next
           Print #nr,
       Next
       Close #nr
   End If

End Sub

' ------=< MAIN >=------

de_magicsq(8, "magic8de.txt") : Print

' empty keyboard buffer While Inkey <> "" : Var _key_ = Inkey : Wend Print : Print "hit any key to end program" Sleep End</lang>

Output:
Single even magic square size: 8*8
The magic sum = 260

 64 63  3  4  5  6 58 57
 56 55 11 12 13 14 50 49
 17 18 46 45 44 43 23 24
 25 26 38 37 36 35 31 32
 33 34 30 29 28 27 39 40
 41 42 22 21 20 19 47 48
 16 15 51 52 53 54 10  9
  8  7 59 60 61 62  2  1

Java

<lang java>public class MagicSquareDoublyEven {

   public static void main(String[] args) {
       int n = 8;
       for (int[] row : magicSquareDoublyEven(n)) {
           for (int x : row)
               System.out.printf("%2s ", x);
           System.out.println();
       }
       System.out.printf("\nMagic constant: %d ", (n * n + 1) * n / 2);
   }
   static int[][] magicSquareDoublyEven(final int n) {
       if (n < 4 || n % 4 != 0)
           throw new IllegalArgumentException("base must be a positive "
                   + "multiple of 4");
       // pattern of count-up vs count-down zones
       int bits = 0b1001_0110_0110_1001;
       int size = n * n;
       int mult = n / 4;  // how many multiples of 4
       int[][] result = new int[n][n];
       for (int r = 0, i = 0; r < n; r++) {
           for (int c = 0; c < n; c++, i++) {
               int bitPos = c / mult + (r / mult) * 4;
               result[r][c] = (bits & (1 << bitPos)) != 0 ? i + 1 : size - i;
           }
       }
       return result;
   }

}</lang>

 1  2 62 61 60 59  7  8 
 9 10 54 53 52 51 15 16 
48 47 19 20 21 22 42 41 
40 39 27 28 29 30 34 33 
32 31 35 36 37 38 26 25 
24 23 43 44 45 46 18 17 
49 50 14 13 12 11 55 56 
57 58  6  5  4  3 63 64 

Magic constant: 260

Perl 6

See Magic squares/Perl 6 for a general magic square generator.

Output:

With a parameter of 8:

 1  2 62 61 60 59  7  8
 9 10 54 53 52 51 15 16
48 47 19 20 21 22 42 41
40 39 27 28 29 30 34 33
32 31 35 36 37 38 26 25
24 23 43 44 45 46 18 17
49 50 14 13 12 11 55 56
57 58  6  5  4  3 63 64

The magic number is 260

With a parameter of 12:

  1   2   3 141 140 139 138 137 136  10  11  12
 13  14  15 129 128 127 126 125 124  22  23  24
 25  26  27 117 116 115 114 113 112  34  35  36
108 107 106  40  41  42  43  44  45  99  98  97
 96  95  94  52  53  54  55  56  57  87  86  85
 84  83  82  64  65  66  67  68  69  75  74  73
 72  71  70  76  77  78  79  80  81  63  62  61
 60  59  58  88  89  90  91  92  93  51  50  49
 48  47  46 100 101 102 103 104 105  39  38  37
109 110 111  33  32  31  30  29  28 118 119 120
121 122 123  21  20  19  18  17  16 130 131 132
133 134 135   9   8   7   6   5   4 142 143 144

The magic number is 870

REXX

Marked numbers indicate that those (sequentially generated) numbers don't get swapped   (and thusly, stay in place in the magic square). <lang rexx>/*REXX program constructs a magic square of doubly even sides (a size divisible by 4).*/ n=8; s=n%4; L=n%2-s+1; w=length(n**2) /*size; small sq; low middle; # width*/ @.=0; H=n%2+s /*array default; high middle. */ call gen /*generate a grid in numerical order. */ call diag /*mark numbers on both diagonals. */ call corn /* " " in small corner boxen. */ call midd /* " " in the middle " */ call swap /*swap positive numbers with highest #.*/ call show /*display the doubly even magic square.*/ call sum /* " " magic number for square. */ exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ o: parse arg ?; return n-?+1 /*calculate the "other" (right) column.*/ @: parse arg x,y; return abs(@.x.y) diag: do r=1 for n; @.r.r=-@(r,r); o=o(r); @.r.o=-@(r,o); end; return midd: do r=L to H; do c=L to H; @.r.c=-@(r,c); end; end; return gen: #=0; do r=1 for n; do c=1 for n; #=#+1; @.r.c=#; end; end; return show: #=0; do r=1 for n; $=; do c=1 for n; $=$ right(@(r,c),w); end; say $; end; return sum: #=0; do r=1 for n; #=#+@(r,1); end; say; say 'The magic number is: ' #; return max#: do a=n to 1 by -1; do b=n to 1 by -1; if @.a.b>0 then return; end; end /*──────────────────────────────────────────────────────────────────────────────────────*/ swap: do r=1 for n

               do c=1  for n;  if @.r.c<0  then iterate;  call max#  /*find max number.*/
               parse value  -@.a.b  (-@.r.c)    with    @.r.c  @.a.b /*swap two values.*/
               end  /*c*/
             end    /*r*/
     return

/*──────────────────────────────────────────────────────────────────────────────────────*/ corn: do r=1 for n; if r>s & r<=n-s then iterate /*"corner boxen", size≡S*/

               do c=1  for n;  if c>s & c<=n-s  then iterate;  @.r.c=-@(r,c);  end  /*c*/
             end   /*r*/
     return</lang>

output   when using the default input:

  1  2 62 61 60 59  7  8
  9 10 54 53 52 51 15 16
 48 47 19 20 21 22 42 41
 40 39 27 28 29 30 34 33
 32 31 35 36 37 38 26 25
 24 23 43 44 45 46 18 17
 49 50 14 13 12 11 55 56
 57 58  6  5  4  3 63 64

The magic number is:  260

Ruby

<lang ruby>def double_even_magic_square(n)

 raise ArgumentError, "Need multiple of four" if n%4 > 0
 block_size, max = n/4, n*n
 pre_pat = [true, false, false, true,
            false, true, true, false]
 pre_pat += pre_pat.reverse
 pattern = pre_pat.flat_map{|b| [b] * block_size} * block_size
 flat_ar = pattern.each_with_index.map{|yes, num| yes ? num+1 : max-num}
 flat_ar.each_slice(n).to_a

end

def to_string(square)

 n = square.size
 fmt = "%#{(n*n).to_s.size + 1}d" * n
 square.inject(""){|str,row| str << fmt % row << "\n"}

end

puts to_string(double_even_magic_square(8))</lang>

Output:
  1  2 62 61 60 59  7  8
 56 55 11 12 13 14 50 49
 48 47 19 20 21 22 42 41
 25 26 38 37 36 35 31 32
 33 34 30 29 28 27 39 40
 24 23 43 44 45 46 18 17
 16 15 51 52 53 54 10  9
 57 58  6  5  4  3 63 64