# Re: Magic Squares (#124)

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

# Reference : 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

``````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

``````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

``````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

Updated.

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

# Reference : 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

``````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

``````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

``````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

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 )

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

regards,
David T.

On May 21, 9:26 am, “doug meyer” [email protected] 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.

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.

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

#!/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 = (randrows+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}
}

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

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

On 5/21/07, James Edward G. II [email protected] wrote:

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