rubyでコードを書くって行為とは・・・
rubyの書き方、思考方法は本で読んで、取り敢えず動かしてみるだけでは見えてこないものが多いです。他者のコードを読むにも読解力が低い状態だと、習慣的な表現にさえ詰まる。また、こちらがその習慣を知らないと習慣慣れした人たちから逆に自分の書いたコードで驚かれることだってある。前に書いた命名の仕方だったりがそれにあたりますが、今回はそれとはまた別種の学んだものを纏めておこうと思います。
クラスメソッドのself
このクラスメソッドに書かれてるselfってなんなのか・・・書かないとそのメソッドを呼ぶこともできない。なんでやねんって話なんですよね。一番最初に思う疑問は。オブジェクト指向にそもそも慣れてないと、ここで躓くのです。
答えはクラスメソッドを示すためのものです。レシーバーがクラス名になるメソッドです。
下記は書籍で見たクラスメソッドの書き方です。呼び出す際に、クラス名であるGreeterをレシーバーにして、greetメソッドを呼んでいます。
class Greeter
class << self
def greet
puts "おはこんばんちわ"
end
end
end
Greeter.greet
下記はselfをレシーバーみたいに使った書き方ですね。クラス自身のgreetメソッドということだと思っています。初っ端はこれだけを見たのでなんのこっちゃわかりませんでした。
class Greeter
def self.greet
puts "おはこんばんちわ"
end
end
Greeter.greet
クラス自身のgreetメソッド、と捉える理由として、下記の書き方ができるからです。selfではなく、直接クラス名をレシーバーみたいに書いても、greetメソッドを呼び出すことができます。
class Greeter
def Greeter.greet
puts "おはこんばんちわ"
end
end
Greeter.greet
ではなぜ、クラスメソッドにおいて、selfを使うのか?
- selfを書いておいて、インスタンスメソッドと差異化
- 二度書き防止
の2点にあると思われます。後日、インスタンスメソッドとの違いも記述する予定です。
クラス関係の余談
とあるコードではrailsのActive Supportにおけるclass_attributeにおいても、slefが使用されているのを見たことがあります。これもselfの部分をFirebaseクラスに書き換えてやっても動いたことから、このclass_attributeも呼んで字の如く、Class#に分類されるもののようですね。
class Firebase
require 'google/cloud'
class_attribute :contact
self.contact = Google::Cloud.new(ENV['GOOGLE_PROJECT']).firestore
end
ロジックの初手は肝要
ビリヤード台で左上から右下45度でボールを発射して壁で理想的な反射をする場合、ボールはどの座標を通って何ステップでコーナーの穴に落ちるか
ゲームプログラミングのコードを課題として頂いた時(ゲームプログラミングであることは後になって気づいたことですが)に、今まで有限ループでのロジック組みに取り組んでいたために、(例えば、1ヶ月のユーザー登録者数を計算するので、DB上から取り出したユーザーの分だけループさせたいのような)この手の無限ループロジックの発想が出てこなかった。そも思考ロジックの土台すらままなっておらず、この課題は答え合わせになるまで解く事ができなかったものです。
x_max = ARGV[0]
y_max = ARGV[1]
if !x_max || !y_max
puts "引数を指定してください"
exit 1
end
x_max = x_max.to_i
y_max = y_max.to_i
#状態
x = 1
y = 1
step = 1
x_way = 1
y_way = 1
puts " #{step} (#{x},#{y})"
x += 1
y += 1
loop do
step += 1
puts " #{step} (#{x},#{y})"
if y == 1 && x == x_max || x == 1 && y == y_max || x == 1 && y == 1 || x == x_max && y == y_max
puts "GOAL!!"
break
elsif x == x_max
x_way = -1
elsif y == y_max
y_way = -1
elsif x == 1
x_way = 1
elsif y == 1
y_way = 1
end
x += x_way
y += y_way
end
以下、学んだものを纏めます。
状態(state)管理
プログラムは扱うデータの状態変化である。
今回のビリヤード問題において具体的化させると、
- 引数で与えられた数によって作られる盤面
- ボールの初期値
- ボールの進行方向
何の状態を変化させ、何が固定化されていると目的のコードを作れるかを考える。
境界条件
何がきっかけで、状態の変化に繋がるのか、もしくは終了になるのかを見極めて条件式、状態に対し動きを与える処理を書く。
今回のビリヤード問題において具体的化させると、
- 四方の壁にあるx軸とy軸の方向にある最小値と最大値
ということになります。これを抑えることでどのタイミングでボールの移動状態が変化するかを判断できます。条件式を考える上で、重要になる。ロジックの走りは、境界条件を意識する。
正しい無限ループ
プログラミングにおける無限ループは、
ループを実行しながら終了条件が見えてくるものに関して無限ループを使用する。言い換えると、プログラムを書いてる時に終了条件が明らかに分からないものを利用して無限ループを使用する。
ゲームのプログラムなんてのはまさにそれキャラのダッシュモーションはユーザーの入力に依存するので、入力される限り無限ループさせる必要がある、という事ですね。
無限ループにおける利用はDB関係でも必要になる。大量のデータをループで処理する場合、殆ど無限ループと変わらない数のループを要するので、一定条件を満たしたら、終了するような設計にする必要がある。
感想
ロジックを組むにおいて、そもそも有限ループか、一定条件まで続くループなのか、でコードを書く事ができていなかった故に、今回の課題はろくに辿り着けることができなかったが、重要な思考としての無限ループは理解できてよかった。