#---------------------------------------------------------------#
Program : Magic Square
Author : David T.
Date : 2007-05-20
Blog : http://davidtran.doublegifts.com/blog/?p=27
Reference : Magic Square -- from Wolfram MathWorld
#---------------------------------------------------------------#
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 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