Forum: Ruby Re: Magic Squares (#124)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
0da6451f946989192d902d6422af93bc?d=identicon&s=25 David Tran (Guest)
on 2007-05-21 03:28
(Received via mailing list)
#---------------------------------------------------------------#
#                                                               #
#  Program   : Magic Square                                     #
#  Author    : David Tran                                       #
#  Date      : 2007-05-20                                       #
#  Blog      : http://davidtran.doublegifts.com/blog/?p=27      #
#  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 [](i,j)
    @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
    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
0da6451f946989192d902d6422af93bc?d=identicon&s=25 David Tran (Guest)
on 2007-05-21 04:18
(Received via mailing list)
Updated.

#---------------------------------------------------------------#
#                                                               #
#  Program   : Magic Square                                     #
#  Author    : David Tran                                       #
#  Date      : 2007-05-20                                       #
#  Blog      : http://davidtran.doublegifts.com/blog/?p=27      #
#  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 [](i,j)
    @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
    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 SinglyEvenMagicSquare
    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 [i%2*2 + j%2] + 4 * (value - 1)
    end
  end
  #------------------------------------------------------------------#
end

if __FILE__ == $0
  puts MagicSquare.new(ARGV[0].to_i)
end
0da6451f946989192d902d6422af93bc?d=identicon&s=25 David Tran (Guest)
on 2007-05-21 15:04
(Received via mailing list)
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 )

http://davidtran.doublegifts.com/blog/?p=27

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

regards,
David Tran
8100138c6c0cd6f3bc27b4fe55c550e5?d=identicon&s=25 doug meyer (Guest)
on 2007-05-21 16:27
(Received via mailing list)
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 = (rand*rows+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}
}
B1b1d33e0655e841d4fd8467359c58d0?d=identicon&s=25 Yossef Mendelssohn (Guest)
on 2007-05-21 20:58
(Received via mailing list)
On May 21, 9:26 am, "doug meyer" <doug.me...@sigeps.org> 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.

If you're talking about the problem I think you're talking about,
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.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-21 21:02
(Received via mailing list)
On May 21, 2007, at 1:58 PM, Yossef Mendelssohn 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 Gray II
8100138c6c0cd6f3bc27b4fe55c550e5?d=identicon&s=25 doug meyer (Guest)
on 2007-05-21 22:20
(Received via mailing list)
I assume you meant to include this:
square = Array.new(rows){Array.new(rows)}
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-21 22:28
(Received via mailing list)
On 5/21/07, James Edward Gray II <james@grayproductions.net> wrote:
> > If you're talking about the problem I think you're talking about,
> >
> > 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? <G>


--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-21 22:54
(Received via mailing list)
On May 21, 2007, at 3:18 PM, doug meyer wrote:

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

Oops, yes, I snipped it.  Thanks for the correction.

James Edward Gray II
This topic is locked and can not be replied to.