Ruby関西勉強会#23参加

してきました。
初級者レッスンの課題は全部で3問あり、うち2題がボクの定めるポリシーを満たしたので、一応さらしておきます。(^^;

  • 課題1. 九九の表を出力する。
  • 課題2. 100マス計算の結果を出力する(問題の出力は割愛しています。)

ロジックの方はシンプルですが、出力結果を成型する部分に時間がかかりました。
なお、課題3は棚上げしておきます。

class Array
  def shuffle
    sort_by{rand}
  end
end

module Ite02
  def self.main
    puts "KuKu"
    KukuMatrix.main
    puts "\n---\nHyakuMasu"
    HyakuMatrix.main
  end
  
  class UnknownOperatorException < Exception
  end

  class CalcMatrix
    attr_accessor :index_array, :size
    attr_reader :op, :table
    
    DEFAULT_SIZE = 20
    DEFAULT_OP = nil
    
    def initialize(t_size=nil, t_op=nil)
      set_values(t_size, t_op)
    end
    
    def set_values(t_size, t_op)
      self.size = t_size || self.class::DEFAULT_SIZE
      self.op = t_op || self.class::DEFAULT_OP
      self.index_array = new_array
    end
    
    def op=(t_op)
      case t_op
      when /\A[\+\-\*\/]\Z/
        @op = t_op
      when nil
        @op = %w(+ - / *).shuffle.first
      else
        raise UnknownOperatorException,  "Unknown Operator: #{op}"
      end
    end
    
    def table_data
      index_array.map { |i|
        index_array.map { |j|
          begin
            calc(i,j)
          rescue => e
            'X'
          end
        }
      }
    end

    def calc(a, b)
      eval("a#{op}b", binding)
    end
  
    def make_line(row)
      w = max_width + 1
      row.inject('') { |ret, e|
        is_numeric = e.kind_of?(Numeric)
        ret << (is_numeric ? ("%#{w}d" % e) : "%#{w}s" % 'X')
      }
    end

    def clear_index_array
      @index_array = nil
    end

    def new_array
      (0...size).to_a.shuffle
    end
    
    def make_table
      @max_width = nil
      @table = table_data
    end
    
    def max_width
      @max_width ||= @table.inject(0) { |ret, row|
        ret = row.inject(ret) { |ret2, col|
          len = col.to_s.length
          ret2 = (ret2 >= len ? ret2 : len)
        }
      }
    end
  
    def print_table
      w = max_width.to_i + 1
      printf( "%#{w}s|" << ("%#{w}d"*size) << "\n", op, *index_array)
      print( ("-"*w) << "+" << ("-"*w*size) << "\n" )
      table.each_with_index do |row, idx|
        printf("%#{w}d|" << make_line(row) << "\n", index_array[idx])
      end
    end
  
    def self.main
      main_internal
    end
    
    def self.main_internal(t_size=nil, t_op=nil)
      cm = self.new(t_size, t_op)
      cm.make_table
      cm.print_table      
    end
  end
  
  class HyakuMatrix < CalcMatrix
    DEFAULT_SIZE = 10
    DEFAULT_OP = nil
  end
  
  class KukuMatrix < CalcMatrix
    DEFAULT_SIZE = 9
    DEFAULT_OP = '*'
    
    def new_array
      (1..size).to_a
    end
  end
end

if $0 == __FILE__
  Ite02.main
end

出力結果はこんな感じです。
サブクラスにて、一部のメソッドや定数をオーバーライドすることで、動作が変わるようにしています。

KuKu
  *|  1  2  3  4  5  6  7  8  9
                                                            • -
1| 1 2 3 4 5 6 7 8 9 2| 2 4 6 8 10 12 14 16 18 3| 3 6 9 12 15 18 21 24 27 4| 4 8 12 16 20 24 28 32 36 5| 5 10 15 20 25 30 35 40 45 6| 6 12 18 24 30 36 42 48 54 7| 7 14 21 28 35 42 49 56 63 8| 8 16 24 32 40 48 56 64 72 9| 9 18 27 36 45 54 63 72 81
    • -
HyakuMasu /| 7 2 5 6 8 1 4 0 3 9
                                            • -
7| 1 3 1 1 0 7 1 X 2 0 2| 0 1 0 0 0 2 0 X 0 0 5| 0 2 1 0 0 5 1 X 1 0 6| 0 3 1 1 0 6 1 X 2 0 8| 1 4 1 1 1 8 2 X 2 0 1| 0 0 0 0 0 1 0 X 0 0 4| 0 2 0 0 0 4 1 X 1 0 0| 0 0 0 0 0 0 0 X 0 0 3| 0 1 0 0 0 3 0 X 1 0 9| 1 4 1 1 1 9 2 X 3 1