# Re: Magic Squares (#124)

**URL:** <https://www.ruby-forum.com/t/re-magic-squares-124/104641>\
**Category:** Ruby\
**Created:** [May 21, 2007, 3:28am UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641 "2007-05-21T03:28:53Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 3:28am UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/1 "2007-05-21T03:28:53Z")

</div>

#---------------------------------------------------------------#

# 

# Program : Magic Square

# Author : David T.

# Date : 2007-05-20

# Blog : [http://davidtran.doublegifts.com/blog/?p=27](http://davidtran.doublegifts.com/blog/?p=27)

# Reference : [Magic Square -- from Wolfram MathWorld](http://mathworld.wolfram.com/MagicSquare.html)

# 

#---------------------------------------------------------------#  
class MagicSquare

def initialize(size = 3)  
raise “Error: size must greater than 2.” if size \< 3  
@magic\_square = if (size % 2 != 0)  
OddMagicSquare.new(size)  
elsif (size % 4 == 0)  
DoublyEvenMagicSquare.new(size)  
else  
SinglyMagicSquare.new(size)  
end  
end

def size  
@magic\_square.size  
end

def   
@magic\_square[i,j]  
end

def to\_s  
digits = (size \* size).to\_s.size  
divider = ‘+’ + ‘-’ \* ((digits + 2) \* size + (size - 1)) + “+\n”  
(0…size).inject(divider) do |s, i|  
(0…size).inject(s + “|”) do |s, j|  
s + " #{self[i,j].to\_s.rjust(digits)} |"  
end + “\n” + divider  
end  
end

def is\_magic\_square?  
sum = size \* (size \* size + 1) / 2  
(0…size).each do |i|  
return false if sum != (0…size).inject(0) { |s,j| s + self[i,j]  
}  
return false if sum != (0…size).inject(0) { |s,j| s + self[j,i]  
}  
end  
return false if sum != (0…size).inject(0) { |s,i| s + self[i,i] }  
return false if sum != (0…size).inject(0) { |s,i| s + self[i, size-1-i] }  
true  
end

private  
#------------------------------------------------------------------#  
class OddMagicSquare  
attr\_reader :size

```
def initialize(size)
  @size = size
  n = @size * @size
  @array = Array.new(n)
  i, j = 0, @size/2
  (1..n).each do |v|
    @array[get_index(i,j)] = v
    a, b = i-1, j+1
    i, j = self[a,b] ? [i+1, j] : [a, b]
  end
end

def [](i, j)
  @array[get_index(i,j)]
end

private
def get_index(i, j)
  (i % @size) * @size + (j % @size)
end

```

end  
#------------------------------------------------------------------#  
class DoublyEvenMagicSquare  
attr\_reader :size

```
def initialize(size)
  @size = size
end

def [](i, j)
  value = (i * @size) + j + 1
  i = (i % @size) % 4
  j = (j % @size) % 4
  ((i == j) || (i + j == 3)) ? (@size*@size+1-value) : value
end

```

end  
#------------------------------------------------------------------#  
class SinglyMagicSquare  
attr\_reader :size

```
def initialize(size)
  @size = size
  @odd_magic_square = MagicSquare.new(@size/2)
end

def [](i, j)
  i, j = i % @size, j % @size
  ii, jj = i / 2, j / 2
  center = @size / 2 / 2
  value = @odd_magic_square[ii, jj]
  _L = [4, 1, 2, 3]
  _U = [1, 4, 2, 3]
  _X = [1, 4, 3, 2]
  if jj == center
    if ii < center then _L
    elsif ii == center then _U
    elsif ii == center+1 then _L
    else _X
    end
  else
    if ii <= center then _L
    elsif ii == center+1 then _U
    else _X
    end
  end.map {|e| 4 * (value - 1) + e} [i%2*2 + j%2]
end

```

end  
#------------------------------------------------------------------#  
end

if **FILE** == $0  
puts MagicSquare.new(ARGV[0].to\_i)  
end

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 4:18am UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/2 "2007-05-21T04:18:56Z")

</div>

Updated.

#---------------------------------------------------------------#

# 

# Program : Magic Square

# Author : David T.

# Date : 2007-05-20

# Blog : [http://davidtran.doublegifts.com/blog/?p=27](http://davidtran.doublegifts.com/blog/?p=27)

# Reference : [Magic Square -- from Wolfram MathWorld](http://mathworld.wolfram.com/MagicSquare.html)

# 

#---------------------------------------------------------------#  
class MagicSquare

def initialize(size = 3)  
raise “Error: size must greater than 2.” if size \< 3  
@magic\_square = if (size % 2 != 0)  
OddMagicSquare.new(size)  
elsif (size % 4 == 0)  
DoublyEvenMagicSquare.new(size)  
else  
SinglyEvenMagicSquare.new(size)  
end  
end

def size  
@magic\_square.size  
end

def   
@magic\_square[i,j]  
end

def to\_s  
digits = (size \* size).to\_s.size  
divider = ‘+’ + ‘-’ \* ((digits + 2) \* size + (size - 1)) + “+\n”  
(0…size).inject(divider) do |s, i|  
(0…size).inject(s + “|”) do |s, j|  
“#{s} #{self[i,j].to\_s.rjust(digits)} |”  
end + “\n” + divider  
end  
end

def is\_magic\_square?  
sum = size \* (size \* size + 1) / 2  
(0…size).each do |i|  
return false if sum != (0…size).inject(0) { |s,j| s + self[i,j]  
}  
return false if sum != (0…size).inject(0) { |s,j| s + self[j,i]  
}  
end  
return false if sum != (0…size).inject(0) { |s,i| s + self[i,i] }  
return false if sum != (0…size).inject(0) { |s,i| s + self[i, size-1-i] }  
true  
end

private  
#------------------------------------------------------------------#  
class OddMagicSquare  
attr\_reader :size

```
def initialize(size)
  @size = size
  n = @size * @size
  @array = Array.new(n)
  i, j = 0, @size/2
  (1..n).each do |v|
    @array[get_index(i,j)] = v
    a, b = i-1, j+1
    i, j = self[a,b] ? [i+1, j] : [a, b]
  end
end

def [](i, j)
  @array[get_index(i,j)]
end

private
def get_index(i, j)
  (i % @size) * @size + (j % @size)
end

```

end  
#------------------------------------------------------------------#  
class DoublyEvenMagicSquare  
attr\_reader :size

```
def initialize(size)
  @size = size
end

def [](i, j)
  value = (i * @size) + j + 1
  i = (i % @size) % 4
  j = (j % @size) % 4
  ((i == j) || (i + j == 3)) ? (@size*@size+1-value) : value
end

```

end  
#------------------------------------------------------------------#  
class SinglyEvenMagicSquare  
attr\_reader :size

```
def initialize(size)
  @size = size
  @odd_magic_square = MagicSquare.new(@size/2)
end

def [](i, j)
  i, j = i % @size, j % @size
  ii, jj = i / 2, j / 2
  center = @size / 2 / 2
  value = @odd_magic_square[ii, jj]
  _L = [4, 1, 2, 3]
  _U = [1, 4, 2, 3]
  _X = [1, 4, 3, 2]
  if jj == center
    if ii < center then _L
    elsif ii == center then _U
    elsif ii == center+1 then _L
    else _X
    end
  else
    if ii <= center then _L
    elsif ii == center+1 then _U
    else _X
    end
  end [i%2*2 + j%2] + 4 * (value - 1)
end

```

end  
#------------------------------------------------------------------#  
end

if **FILE** == $0  
puts MagicSquare.new(ARGV[0].to\_i)  
end

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 3:04pm UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/3 "2007-05-21T15:04:55Z")

</div>

Hi,

Updated again on SinglyEvenMagicSquare class. ( shorter )  
Basically, it almost remains the same.

Don’t like to post too many emails when I find/try to improve my  
program on the details …  
If you read my previous 2 post solution, and like to see the “little”  
change, please go to my blog: ( it will have my last updated version )

[http://davidtran.doublegifts.com/blog/?p=27](http://davidtran.doublegifts.com/blog/?p=27)

otherwise, I am sorry to bother you on the mailing list.

regards,  
David T.

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 8:58pm UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/4 "2007-05-21T20:58:53Z")

</div>

On May 21, 9:26 am, “doug meyer” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hey,  
> Did anyone else run into the problem of trying to setup your square using:  
> Array.new(size, Array.new(size))  
> that was annoying! And I wasted too much time with formating the output.

If you’re talking about the problem I think you’re talking about,  
that’s the reason I dismissed that approach out of hand.

irb(main):001:0\> x = Array.new(5, Array.new(5,0))  
=\> [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0,  
0], [0, 0, 0, 0, 0]]  
irb(main):002:0\> x[2][2] = 5  
=\> 5  
irb(main):003:0\> x  
=\> [[0, 0, 5, 0, 0], [0, 0, 5, 0, 0], [0, 0, 5, 0, 0], [0, 0, 5, 0,  
0], [0, 0, 5, 0, 0]]

Those references will get you if you’re not careful.

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 4:27pm UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/5 "2007-05-21T16:27:17Z")

</div>

Hey,  
Did anyone else run into the problem of trying to setup your square  
using:  
Array.new(size, Array.new(size))  
that was annoying! And I wasted too much time with formating the output.

[http://pastie.caboo.se/63288](http://pastie.caboo.se/63288)

#!/usr/bin/env ruby

# Douglas Meyer

class Array  
def sum  
inject(0){|a,v|a+=v}  
end  
end

rows = ARGV[0].to\_i  
puts “Sorry, this program only works for odd row values!” if rows % 2 ==  
0

row\_sum = (1…rows\*\*2).to\_a.sum/rows  
puts “Row Sum: #{row\_sum}”  
decimals = (Math::log(row\_sum)/Math::log(10)).to\_i

square = Array.new(rows){Array.new(rows, 0)}

row = (rand_rows+1).to\_i  
col = (rand_rows+1).to\_i

#Computer square  
(1…rows\*\*2).each do |count|  
row = (row - 1) % rows  
col = (col - 1) % rows  
square[row][col] = count  
unless square[(row-1)%rows][(col-1)%rows] == 0  
col -= 2  
row -= 1  
end  
end

#Display and check sums  
string = “% #{decimals+2}d"_rows+" = % #{decimals+1}d"  
square.each{ |row|  
output = row  
output \<\< row.sum  
puts string % output  
}  
puts (" "_(decimals)+”= ")\*rows  
string = “% #{decimals+2}d”\*rows  
puts string % square.inject(Array.new(rows,0)){|sum,row|  
sum = sum.zip(row).map{|a|a.sum}  
}

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 10:20pm UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/6 "2007-05-21T22:20:05Z")

</div>

I assume you meant to include this:  
square = Array.new(rows){Array.new(rows)}

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 9:02pm UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/7 "2007-05-21T21:02:54Z")

</div>

On May 21, 2007, at 1:58 PM, Yossef M. wrote:

> irb(main):001:0\> x = Array.new(5, Array.new(5,0))  
> =\> [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0,  
> 0], [0, 0, 0, 0, 0]]  
> irb(main):002:0\> x[2][2] = 5  
> =\> 5  
> irb(main):003:0\> x  
> =\> [[0, 0, 5, 0, 0], [0, 0, 5, 0, 0], [0, 0, 5, 0, 0], [0, 0, 5, 0,  
> 0], [0, 0, 5, 0, 0]]
> 
> Those references will get you if you’re not careful.

But it’s very easy to fix:

=\> [[nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil,  
nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil]]

> > square[2][2] = 5  
> > =\> 5
> 
> > square  
> > =\> [[nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil,  
> > 5, nil, nil], [nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil]]

James Edward G. II

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 10:28pm UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/8 "2007-05-21T22:28:08Z")

</div>

On 5/21/07, James Edward G. II [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > If you’re talking about the problem I think you’re talking about,
> > 
> > Those references will get you if you’re not careful.
> 
> But it’s very easy to fix:

I think you left out something like:

square = Array.new(5) {Array.new(5)}

or one of the other solutions.

> =\> [[nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil,  
> nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil]]
> 
> > > square[2][2] = 5  
> > > =\> 5  
> > > square  
> > > =\> [[nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil,  
> > > 5, nil, nil], [nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil]]

Are we playing tag team today, James?

–  
Rick DeNatale

My blog on Ruby  
[http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![davidtl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@davidtl](https://www.ruby-forum.com/u/davidtl)\
**Post date:** [May 21, 2007, 10:54pm UTC](https://www.ruby-forum.com/t/re-magic-squares-124/104641/9 "2007-05-21T22:54:11Z")

</div>

On May 21, 2007, at 3:18 PM, doug meyer wrote:

> I assume you meant to include this:  
> square = Array.new(rows){Array.new(rows)}

Oops, yes, I snipped it. Thanks for the correction.

James Edward G. II
