Forums
New posts
Search forums
Members
Current visitors
Log in
Register
What's new
Search
Search
Search titles only
By:
New posts
Search forums
Menu
Log in
Register
Install the app
Install
Forums
Archive
Archive
Ruby
[QUIZ] Magic Squares (#124)
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
[QUOTE="Robert Dober, post: 4560485"] Hmm does not seem that the attachments are too readable on the Ruby Quiz site. So please forgive me for posting them here again, inline. I do not include the HTML plugin as it is not closely connected to the topic of the Quiz. Cheers Robert # cat 124-magic-square.rb # vim: sts=2 sw=2 ft=ruby expandtab nu tw=0: Usage = <<-EOS usage: ruby #{$0} [-t|--test] [-h|--html] <Square Order List> Prints Magic Squares for all indicated orders. Indicating -t also tests the results. EOS loop do case ARGV.first when "-t", "--test" require 'test-squares' ARGV.shift when "-h", "--html" require 'html-output' ARGV.shift when "-?", "--help", nil puts Usage exit when "--" ARGV.shift && break else break end end # # This is a default output module, another output # module called HTMLOutput is provided as an example # how to pull in an appropriate Output module # as plugin. # module Output def to_s decoration = false l = (@order*@order).to_s.size return @data.map{ |line| line.map{ |cell| "%#{l}d" % cell }.join(" ") }.join("\n") unless decoration sep_line = "+" << ( "-" * l.succ.succ << "+" ) * @order sep_line.dup << "\n" << @data.map{ | line | "| " << line.map{ |cell| "%#{l}d" % cell }.join(" | ") << " |" }. zip( [sep_line] * @order ).flatten.join("\n") end end # # The usage of cursors is slowing down the program a little # bit but I feel it is still fast enough. # class Cursor attr_reader :cpos, :lpos def initialize order, lpos, cpos @order = order @lpos = lpos @cpos = cpos end def move ldelta, cdelta l = @lpos + ldelta c = @cpos + cdelta l %= @order c %= @order self.class.new @order, l, c end def next! @cpos += 1 return if @cpos < @order @cpos = 0 @lpos += 1 @lpos %= @order end end # # This is where the work is done, like # testing and outputting and what was it? # Ah yes storing the data. # class SquareData include Output include HTMLOutput rescue nil include TestSquare rescue nil def initialize order @order = order @data = Array.new( @order ){ Array.new( @order ) { nil } } end def peek(i, j); @data[i][j] end def poke(i, j, v); @data[i][j] = v end def [](c); @data[c.lpos][c.cpos] end def []=(c, v); @data[c.lpos][c.cpos] = v end def each_subdiagonal (@order/4).times do | line | (@order/4).times do | col | 4.times do | l | 4.times do | c | yield [ 4*line + l, 4*col + c ] if l==c || l+c == 3 end end # 4.times do end # (@order/4).times do end # (@order/4).times do end def siamese_order model = self.class.new @order last = @order*@order @pos = Cursor.new @order, 0, @order/2 yield @pos.lpos, @pos.cpos, peek( @pos.lpos, @pos.cpos ) model[ @pos ] = true 2.upto last do npos = @pos.move -1, +1 npos = @pos.move +1, 0 if model[ npos ] model[ @pos = npos ] = true yield @pos.lpos, @pos.cpos, peek( @pos.lpos, @pos.cpos ) end # @last.times do end end # class SquareData # # The base class for Magic Squares it basically # is the result of factorizing the three classes # representing the three differnt cases, odd, even and # double even. # It's singleton class is used as a class Factory for # the three implementing classes. # class Square def to_s decoration = false @data.to_s decoration end private def initialize order @order = order.to_i @last = @order*@order @data = SquareData.new @order compute @data.test rescue nil end end # # The simplest case, the Siamese Order algorithm # is applied. # class OddSquare < Square private def compute @pos = Cursor.new @order, 0, @order/2 @data[ @pos ] = 1 2.upto @last do | n | npos = @pos.move -1, +1 npos = @pos.move +1, 0 if @data[ npos ] @data[ @pos = npos ] = n end # @last.times do end end # class OddSquare # # The Double Cross Algorithm is applied # to double even Squares. # class DoubleCross < Square def compute pos = Cursor.new @order, 0, 0 1.upto( @last ) do | n | @data[ pos ] = n pos.next! end # 1.upto( @last ) do @data.each_subdiagonal do | lidx, cidx | @data.poke lidx, cidx, @last.succ - @data.peek( lidx, cidx ) end end end # # And eventually we use the LUX algorithm of Conway for even # squares. # class FiatLux < Square L = [ [0, 1], [1, 0], [1, 1], [0, 0] ] U = [ [0, 0], [1, 0], [1, 1], [0, 1] ] X = [ [0, 0], [1, 1], [1, 0], [0, 1] ] def compute half = @order / 2 lux_data = SquareData.new half n = half/2 pos = Cursor.new half, 0, 0 n.succ.times do half.times do lux_data[ pos ] = L pos.next! end # half.times do end # n.succ.times do half.times do lux_data[ pos ] = U pos.next! end # half.times do lux_data.poke n, n, U lux_data.poke n+1, n, L 2.upto(n) do half.times do lux_data[ pos ] = X pos.next! end end # 2.upto(half) do count = 1 lux_data.siamese_order do | siam_row, siam_col, elem | elem.each do | r, c | @data.poke 2*siam_row + r, 2*siam_col + c, count count += 1 end # elem.each do end # lux_data.siamese_order do end end # class FiatLux class << Square # # trying to call the ctors with consistent values only # protected :new def Factory arg arg = arg.to_i case arg % 4 when 1, 3 OddSquare.new arg when 0 DoubleCross.new arg else FiatLux.new arg end end end ARGV.each do |arg| puts Square::Factory( arg ).to_s( true ) puts end __END__ ######################################### ######################################### #207/15 > cat test-squares.rb # vim: sts=2 sw=2 ft=ruby expandtab nu tw=0: module TestSquare def assert cdt, msg return $stderr.puts( "#{msg} . . . . . ok" ) if cdt raise Exception, msg << "\n" << to_s end def test dia1 = dia2 = 0 @order.times do | idx | dia1 += peek( idx, idx ) dia2 += peek( idx, -idx.succ ) end # @lines.each_with_index do assert dia1==dia2, "Both diagonals" @order.times do | idx1 | col_n = row_n = 0 @order.times do | idx2 | col_n += peek idx2, idx1 row_n += peek idx1, idx2 end assert dia1 == col_n, "Col #{idx1}" assert dia1 == row_n, "Row #{idx1}" end # @lines.each_with_index do end # def test def is_ok? dia1 = dia2 = 0 @order.times do | idx | dia1 += peek( idx, idx ) dia2 += peek( idx, -idx.succ ) end # @lines.each_with_index do return false unless dia1==dia2 @order.times do | idx1 | col_n = row_n = 0 @order.times do | idx2 | col_n += peek idx2, idx1 row_n += peek idx1, idx2 end return false unless dia1 == col_n return false unless dia1 == row_n end # @lines.each_with_index do true end end __END__[/i][/i] [/QUOTE]
Verification
Post reply
Forums
Archive
Archive
Ruby
[QUIZ] Magic Squares (#124)
Top