読者です 読者をやめる 読者になる 読者になる

C言語の構造体を Ruby で表現してみる

C言語のいわゆる「K&R」本を読んでいたら、構造体というのはオブジェクト指向によく似ていると思った。ので、この本の第六章のスクリプト(p.155-159)を、Ruby で表現してみる。

少なくともここでは、C言語の構造体が完全に RubyOOP に移植できている。

#点を表すクラス
class Point
  def initialize(x = 0, y = 0)
    @x = x
    @y = y
  end
  attr_accessor :x, :y
  
  def addpoint(p)   #2点p1, p2の座標を足して、Pointを返す
    @x += p.x
    @y += p.y
    self
  end
  alias + addpoint
end


#2点をインスタンス変数にもつクラス。向かい合った2点によって表される長方形とも考えられる
class Rect
  def initialize
    @pt1 = Point.new
    @pt2 = Point.new
  end
  attr_accessor :pt1, :pt2
  
  def cannonrect   #レシーバーの値を「標準形式」(下を参照)に直して返す
    temp = Rect.new    
    temp.pt1.x = getmin(@pt1.x, @pt2.x)
    temp.pt1.y = getmin(@pt1.y, @pt2.y)
    temp.pt2.x = getmax(@pt1.x, @pt2.x)
    temp.pt2.y = getmax(@pt1.y, @pt2.y)
    return temp
  end
end


#以下、トップレベルでのメソッドの定義
def ptinrect(q, r)
  return (q.x >= r.pt1.x && q.x < r.pt2.x &&   #pt1の各座標はpt2の各座標より小さくなければならない
          q.y >= r.pt1.y && q.y < r.pt2.y)     #(標準形式)。pがrの中ならtrue、そうでなければfalse
end

def getmin(x, y)
  return (x < y) ? x : y
end

def getmax(x, y)
  return (x > y) ? x : y
end


例を挙げてみる。点pt と原点との距離を求める。

pt = Point(300, 400).new
p Math.sqrt(pt.x ** 2 + pt.y ** 2)   #=> 500.0

2点の中点(あるいは、長方形の真ん中の点)を求める。

screen = Rect.new
screen.pt1 = Point.new(100, 0)
screen.pt2 = Point.new(200, 100)
middle = Point.new((screen.pt1.x + screen.pt2.x) / 2, (screen.pt1.y + screen.pt2.y) / 2)
p middle     #=> #<Point:*** @x=150, @y=50>

2つの位置ベクトルの和を求める。

v1 = Point.new(20, 30)
v2 = Point.new(50, 90)
p v1.addpoint(v2)    #=> #<Point:*** @70, @y=120>
p v1 + v2            #=> #<Point:*** @70, @y=120>   + は addpoint のエイリアス

点q が長方形r の内部にあるか。

r = Rect.new
r.pt1 = Point.new(20, 30)
r.pt2 = Point.new(100, 200)

q = Point.new(50, 70)
p ptinrect(q, r)    #=> true
q = Point.new(50, 20)
p ptinrect(q, r)    #=> false

長方形r を定義する 2点を、「標準形式」に直す。

r = Rect.new
r.pt1 = Point.new(100, 200)
r.pt2 = Point.new(10, 20)
p r.cannonrect   #=> #<Rect:*** @pt1=#<Point:*** @x=10, @y=20>, @pt2=#<Point:*** @x=100, @y=200>>


※追記
Ruby にはまさしく Structクラスというのもありますね。これでもいけるか。(6/14追記)