On May 18, 6:57 pm, Ruby Quiz <j... / grayproductions.net> 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 |
+-----------------------------+