[QUIZ][SOLUTION]Re: Magic Squares (#124)



On May 18, 6:57 pm, Ruby Quiz <j...@xxxxxxxxxxxxxxxxxxx> wrote:
The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

A magic square of size N is a square with the numbers from 1 to N ** 2 arranged
so that each row, column, and the two long diagonals have the same sum. For
example, a magic square for N = 5 could be:

+------------------------+
| 15 | 8 | 1 | 24 | 17 |
+------------------------+
| 16 | 14 | 7 | 5 | 23 |
+------------------------+
| 22 | 20 | 13 | 6 | 4 |
+------------------------+
| 3 | 21 | 19 | 12 | 10 |
+------------------------+
| 9 | 2 | 25 | 18 | 11 |
+------------------------+

In this case the magic sum is 65. All rows, columns, and both diagonals add up
to that.

This week's Ruby Quiz is to write a program that builds magic squares. To keep
the problem easy, I will say that your program only needs to work for odd values
of N. Try to keep your runtimes pretty reasonable even for the bigger values of
N:

$ time ruby magic_square.rb 9
+--------------------------------------------+
| 45 | 34 | 23 | 12 | 1 | 80 | 69 | 58 | 47 |
+--------------------------------------------+
| 46 | 44 | 33 | 22 | 11 | 9 | 79 | 68 | 57 |
+--------------------------------------------+
| 56 | 54 | 43 | 32 | 21 | 10 | 8 | 78 | 67 |
+--------------------------------------------+
| 66 | 55 | 53 | 42 | 31 | 20 | 18 | 7 | 77 |
+--------------------------------------------+
| 76 | 65 | 63 | 52 | 41 | 30 | 19 | 17 | 6 |
+--------------------------------------------+
| 5 | 75 | 64 | 62 | 51 | 40 | 29 | 27 | 16 |
+--------------------------------------------+
| 15 | 4 | 74 | 72 | 61 | 50 | 39 | 28 | 26 |
+--------------------------------------------+
| 25 | 14 | 3 | 73 | 71 | 60 | 49 | 38 | 36 |
+--------------------------------------------+
| 35 | 24 | 13 | 2 | 81 | 70 | 59 | 48 | 37 |
+--------------------------------------------+

real 0m0.012s
user 0m0.006s
sys 0m0.006s

For extra credit, support even values of N. You don't need to worry about N = 2
though as it is impossible.

Here it is:
# magic_square.rb
# Magic Square with Odd Number
class OddMagicSquare
attr_reader :square

def initialize(n)
@square = Array.new(n)
@square.each_index {|i| @square[i] = Array.new(n)}
middle = n/2
@square[0][middle] = 1
@pos = [0,middle]
@len = n
end

def printing_magic_square
v_border = '+' + '-' * (6 * @len - 1) + '+'
@square.each do |row|
puts v_border
row.each do |r|
if r then
print format('|' + "%4d" + ' ', r)
else
print '| nil '
end
end
print "|\n"
end
puts v_border
end

def iterate_square
value = 2
last_value = @len ** 2
while true do
move
fill value
break if value == last_value
value = value + 1
end
end

private

def fill(value)
@square[@pos[0]][@pos[1]] = value
end

def move
move_down if not move_diagonal_up
end

def move_diagonal_up
# get future position
future_pos = Array.new(2)
@pos[0] == 0 ? future_pos[0] = @len - 1 : future_pos[0] = @pos[0]
- 1
@pos[1] == @len - 1 ? future_pos[1] = 0 : future_pos[1] = @pos[1]
+ 1
# check if it is empty or not
if @square[future_pos[0]][future_pos[1]] then
return false
else
@pos = future_pos
end
return true
end

def move_down
@pos[0] == @len - 1 ? @pos[0] = 0 : @pos[0] = @pos[0] + 1
end

end

The test case:
#tc_magic_square.rb
require 'test/unit'

require 'magic_square'

class TestOddMagicSquare < Test::Unit::TestCase

def setup
@n = 5
@odd_magic_square = OddMagicSquare.new(@n)
@odd_magic_square.iterate_square
@square = @odd_magic_square.square
@sum = (@n ** 2 / 2 + 1) * @n
end

def test_sum_row_and_col
@n.times do |t|
assert_equal @sum, get_sum_column(t)
assert_equal @sum, get_sum_row(t)
end
assert_equal @sum, get_sum_diagonal('left')
assert_equal @sum, get_sum_diagonal('right')
end

private

def get_sum_column(i)
sum = 0
@n.times do |t|
sum += @square[t][i]
end
sum
end

def get_sum_row(i)
sum = 0
@n.times do |t|
sum += @square[i][t]
end
sum
end

def get_sum_diagonal(alignment)
if alignment == 'left' then
sum = i = 0
@n.times do |t|
sum += @square[i][i]
i = i + 1
end
return sum
elsif alignment == 'right' then
sum = 0
i = @n - 1
@n.times do |t|
sum += @square[i][i]
i = i - 1
end
return sum
else
raise 'Alignment must be left or right.'
end
end

end

Here how it is run:
# use_magic_square.rb
require 'magic_square'

# getting input
n = ARGV[0].to_i

# input must be odd and bigger than 2
raise 'Argument must be odd and bigger than 2' if n % 2 == 0 or n < 3

odd_magic_square = OddMagicSquare.new(n)
odd_magic_square.iterate_square
odd_magic_square.printing_magic_square

$ ruby use_magic_square.rb 5
+-----------------------------+
| 17 | 24 | 1 | 8 | 15 |
+-----------------------------+
| 23 | 5 | 7 | 14 | 16 |
+-----------------------------+
| 4 | 6 | 13 | 20 | 22 |
+-----------------------------+
| 10 | 12 | 19 | 21 | 3 |
+-----------------------------+
| 11 | 18 | 25 | 2 | 9 |
+-----------------------------+

.



Relevant Pages

  • Re: [SOLUTION] Code to S-Exp (#95)
    ... Please do not post any solutions or spoiler discussion for this quiz until ... Support Ruby Quiz by submitting ideas as often as you can: ... An s-expression is a nested list structure where the first element of each list ... def method_missing ...
    (comp.lang.ruby)
  • Re: [SOLUTION] Code to S-Exp (#95)
    ... Please do not post any solutions or spoiler discussion for this quiz until ... Support Ruby Quiz by submitting ideas as often as you can: ... An s-expression is a nested list structure where the first element of each list ... def method_missing ...
    (comp.lang.ruby)
  • Re: [QUIZ] Not So Random (#173)
    ... quiz until 48 hours have passed from the time on this message. ... Support Ruby Quiz 2 by submitting ideas as often as you can! ... irb> Array.new ... def srand ...
    (comp.lang.ruby)
  • Re: why is overloading invalid in ruby.
    ... def sum ... Ruby doesn't support method overloading. ... definition of the sum method, with each definition overwriting the previous ... args << 2 if args.empty? ...
    (comp.lang.ruby)
  • Re: [QUIZ SOLUTION] Happy Numbers (#93) -- nondecreasing digits
    ... Please do not post any solutions or spoiler discussion for this quiz until ... Support Ruby Quiz by submitting ideas as often as you can: ... def internal_happy? ... generate digits whose numbers are in nondecreasing order. ...
    (comp.lang.ruby)