#!/usr/bin/ruby
# Makes a multidimension array (matrix) with the width and height of n
def define_matrix(n)
@square = Array.new(n) { Array.new(n) }
fill_matrix_with_zeroes(n)
@size = n
@max = @size * @size
end
# Fills the matrix with zeroes
def fill_matrix_with_zeroes(n)
n.times do | i |
n.times do | j |
@square[i][j] = 0
end
end
end
# Writes to the matrix
def input(i, j, input)
if @square[j-1][i-1] == 0
@square[j-1][i-1] = input
end
end
# Tests if the place in the matrix is free
def is_zero(x, y)
if @square[y-1][x-1] == 0 && y > 0 && x > 0
return true
else
return false
end
end
# Finds the next place to write
def next_pos
x = @pos[0]
y = @pos[1]
if is_zero(x+1, y-1)
@pos = [x+1, y-1]
elsif x == @size && is_zero(1, y-1)
@pos = [1, y-1]
elsif y == 1 && is_zero(x+1, @size)
@pos = [x+1, @size]
elsif is_zero(x, y+1)
@pos = [x, y+1]
else
unless @num == @max
puts "Rule error!!!"
puts "X: #{x}"
puts "Y: #{y}"
output
exit
end
end
end
# Finds the start position
def start_pos
@pos = [(@size.to_f/2+0.5).to_i, 1]
end
# Prints the table nicely
def output
out = ""
@square.each do | line |
line.each do | number |
out << number.to_s.rjust(@max.to_s.length + 1)
end
out << "\n"
end
puts out
end
#================ Running the program ===============
if $0 == __FILE__
if ARGV.length > 0 && (ARGV[0].to_i % 2 > 0)
define_matrix(ARGV[0].to_i)
start_pos
for k in 1..@max
input(@pos[0], @pos[1], k)
unless k == @max
next_pos
end
end
output
else
puts "Call with an odd number!"
end
end
Refactorings
No refactoring yet !
bob
June 3, 2010, June 03, 2010 20:38, permalink
by the way, it is called magic square: http://en.wikipedia.org/wiki/Magic_square
arvanasse
June 4, 2010, June 04, 2010 13:11, permalink
#!/usr/bin/ruby
class MagicSquare
def initialize(size)
initialize_matrix size
build_matrix
end
def output
max_width = @max.to_s.length + 1
out = @square.collect do | line |
line.collect{| number | number.to_s.rjust(max_width) }.join
end.join("\n")
puts out
end
private
def initialize_matrix(n)
# By specifying zero as the default object there
# is no need to fill with zeroes
@square = Array.new(n) { Array.new(n, 0) }
@size = n
@max = @size * @size
end
def build_matrix
set_starting_position
1.upto(@max) do |k|
set(@pos[0], @pos[1], k)
next_pos unless k == @max
end
end
def is_zero(x, y)
y > 0 && x > 0 && get(x-1, y-1) == 0
end
def get(x, y)
@square[y][x]
end
def set(i, j, input)
@square[j-1][i-1] = input if is_zero(i, j)
end
def set_starting_position
@pos = [(@size.to_f/2+0.5).to_i, 1]
end
def next_pos
x, y = @pos
@pos = case
when is_zero( x+1, y-1 ) then @pos = [x+1, y-1]
when x == @size && is_zero(1, y-1) then @pos = [1, y-1]
when y == 1 && is_zero(x+1, @size) then @pos = [x+1, @size]
when is_zero(x, y+1) then @pos = [x, y+1]
else report_rule_error unless @num == @max
end
end
def report_rule_error
puts "Rule error!!!"
puts "X: #{x}"
puts "Y: #{y}"
output
exit
end
end
#================ Running the program ===============
if $0 == __FILE__
unless ARGV.length > 0 && (ARGV[0].to_i % 2 > 0)
raise ArgumentError, "Please call with an odd number!"
end
square = MagicSquare.new ARGV[0].to_i
square.output
end
Hi
I made this piece of code to do some rule training.
I produces a square with an odd side number, in which you can add the numbers horizontally, vertically and diagonally, and the result will be the same.
Smallest output that makes sense is:
8 1 6
3 5 7
4 9 2
The rules are:
Always try to go one up and one to the right.
If you're at the top, try to go one to the right, and all way down.
If you're at the right side, go one up, and all left.
And if non of the above works, go one down.
/Claus :)