Rubyのメソッドの働きをちょっと確認したい場合は以下の方法を覚えておく とよいだろう。
-e
オプションruby
コマンドに-e
オプションを付けると、
次のコマンドライン引数をRubyの文と解釈して直接解釈実行してくれる。
Rubyの文全体が1個の引数になるように、シングルクォート
('')で括る。
ruby -e 'printf("Hello!\n")'
Hello
irb
コマンドRubyの文を1行ずつ対話実行する。コマンドラインから
irb
と実行してみよう。
irb
irb(main):001:0>
ここに、Rubyの文を入れ、[Return]を押すと即座に結果が得られる。
irb(main):001:0> x = 5 5 irb(main):002:0> y = x**3 125
ゲーム性のあるプログラムを作るためには、プログラムを起動する度に違 う値を返すメソッドが不可欠である。計算機では何らかの決まりに沿って 見かけ上ランダムな数を順次発生させられる。厳密にはこれを 擬似乱数という。
rand
乱数を発生する。
rand(自然数)
とすると、0から自然数未満の整数の乱数を発生する。
rand(0)
とすると0から1未満の実数値で乱数を発生する。
乱数の種を初期化するsrand
メソッドで生成される乱数を変えることができる。
以下のプログラム断片は、じゃんけんのグーチョキ
パーをランダムに出すものである。
janken = ["グー", "チョキ", "パー"] srand() # 乱数の種を初期化 hand = rand(3) # 3未満の整数(0, 1, 2)を発生 printf("私の手は %s です.\n", janken[hand])
上のようにsrand()
と引数なしで呼ぶとその時の時刻などを元に
推測困難な種となるが、たとえばsrand(10)
のように
既知の値を与えるとその種による乱数列が出るので、毎回同じ乱数を出させて
デバッグするときなどに有用である。
文字列の一部を取り出したり、切り取ったりすることができる。 ゲーム性や実用性の高いものを作るときには、文字列の一部を表示したり 一部を別の単語に置き換えたりすることが必要になる。これまで 触れなかった少し複雑な文字列操作メソッドを紹介する。 以下の説明ではS を文字列とする。
S*自然数
自然数 の数だけ元の文字列S を 繰り返した文字列を返す。区切り線などを表示するときに便利。
puts "-"*79
とすると、79個の -
(と改行)を出力する。
S[開始位置..終了位置]
文字列Sの開始位置から終了位置
までの文字列を返す。最初の文字の位置を0とする。位置に負の数を指定
すると文字列の終端から数え始める。たとえば、-1は最後の文字で、
-2は最後から二番目の文字である。
例:
"abcdefg"[0..2] => "abc" "abcdefg"[4..-1] => "efg" "abcdefg"[-3..-1] => "efg"
文字列の長さを調べるには、文字列に備わる length
メソッド、または size
メソッドを使う。
"abcde".size => 5 "abcde".length => 5
文字を1字ずつ取り出すにはたとえば以下のようにする。
x = "abcdef" i = 0; while i < x.length printf("%c\n", x[i]) i+=1 end
sub, sub!, gsub, gsub!
sub
メソッドは、sub(正規表現, 置換後文字列)
の形式で利用して第1引数の「正規表現」にマッチする部分を
「置換後文字列」に置き換える。
置き換えは最初にマッチしたものに対してだけ行なわれる。
例:
"abcdef".sub(/bc/, "FOO") => "aFOOdef" "This is a pen".sub(/is/, "IS") => "ThIS is a pen"
sub!
は、sub
と同様だが、
元の文字列自身を直接書き換える(破壊的操作)。つまりsub
は元の文字列とは別に新しい文字列を作って返すが、sub!
は新しい文字列を作らないので、元の文字列は保存されない。
例:
x = "This is a pen" y = x.sub(/is/, "IS") x => "This is a pen" y => "ThIS is a pen" x = "This is a pen" y = x.sub!(/is/, "IS") x => "ThIS is a pen" y => "ThIS is a pen"
gsub
は、正規表現にマッチしたものを
全て置き換える。
例:
x = "This is a pen" y = x.gsub(/is/, "IS") x => "This is a pen" y => "ThIS IS a pen" x = "This is a pen" y = x.gsub!(/is/, "IS") x => "ThIS IS a pen" y => "ThIS IS a pen"
その他の文字列操作メソッドについては、 Rubyマニュアル - Stringクラスのマニュアルページを参照すること。
Rubyプログラムが動いているときの現在時刻はTime
を
利用して取得する。
Time.now
現在の時刻を返す。秒数でカウントしたい場合は
to_i
メソッドを介して利用するとよい。
たとえば10秒以内になにかの処理をやらせる場合は以下のようにする。
start = Time.now.to_i while true ………何かの処理……… if Time.now.to_i - start > 10 puts "時間切れです" break end end
プログラムの実行を一時停止したいときには
sleep
メソッドを使う。
sleep(秒数)
指定した秒数 だけ一時停止する。1秒未満の指定も可能。
配列に複数の値が入っているときの繰り返し処理の書き方にはいくつかある。 以下の処理はどれも同じ働きをする。
sum = 0 x = [10, 20, 15, 44, 8, 3] for i in x do sum += i end
sum = 0 x = [10, 20, 15, 44, 8, 3] x.each do |i| sum += i end
sum = 0 i = 0 x = [10, 20, 15, 44, 8, 3] while i < x.length sum += x[i] i += 1 end
指定した回数繰り返すには以下のどれかを用いるとよい。以下の例は どれも10回繰り返す。
i = 0 while i < 10 繰り返し i += 1 end
for i in 1..10 do 繰り返し end
1.upto(10) do |i| 繰り返し end
(1..10).each do |i| 繰り返し end
ファイルの内容を1行ずつ読み込みながら処理を続ける場合の書き方は
いくつかある。以下の例は、どれも "datafile"
というファイル
の中味を1行ずつ読み、それを line
という変数に
代入しつつ処理を繰り返すものである。
open("datafile", "r") do |f| while line=f.gets 繰り返し end end
f = open("datafile", "r") while line=f.gets 繰り返し end f.close
IO.foreach("datafile") do |line| 繰り返し end
ここまでの知識を応用して、あるファイルの内容をゆっくりと
出力するプログラムを作ってみよう。
roll.txt
というファイルに以下のような
内容が書いてあるとする。
西暦20XX年、宇宙創造の神は
破滅に向かう地球を救うべく、
とある場所にあるコンピュータに
一つのメッセージを託しました。
人類に残された道はそのメッセージを
手に入れること。
そのためには………
N u m b e r M a g i q !!
最後の行には10個の空白を入れておく(理由は後述)。
プログラムを起動すると、このテキストファイルの1行目が、 画面の右側から動いて移動してくる。
← 西暦20XX年 (左に向かって移動していく)
行の先頭に達すると次の行が出てくる。
西暦20XX年、宇宙創造の神は ← 破滅に向か (これも左に向かって移動していく)
同様に最後の行まで動きが分かるようにゆっくりと出力していく。このよう なプログラムを作ろう。
文字列の位置が分かりやすいように以下のような文字列を考えよう。
x="0123456789"
これを先頭の文字から1文字ずつ出てくるようにするには、
"0" | x[0..0] |
"01" | x[0..1] |
"012" | x[0..2] |
"0123" | x[0..3] |
: | : |
: | : |
"0123456789" | x[0..9] |
のように1字ずつ増やしながら切り出す。0から始めて
x.length-1
まで部分文字列を取り出せばよい。
x="0123456789"
0.upto(x.length-1) do |i|
puts x[0..i]
end
=>
0
01
012
0123
01234
012345
0123456
01234567
012345678
0123456789
再び x="0123456789"
の例で考えると、全部で10文字なので
先頭1字だけが右端に出てくるときは、それより前に9字分の空白があればよい。
これを一般化すると、文字列の長さがlength
だったときに、
先頭i
字だけを出力するなら、length-1-i
字分の空
白を入れればよい、となる。
これを考慮してループを作ると以下のようになる。
x="0123456789"
length=x.length
0.upto(length-1) do |i|
puts " "*(length-1-i) + x[0..i]
end
=>
0
01
012
0123
01234
012345
0123456
01234567
012345678
0123456789
以上のことを組み合わせると以下のようなプログラムになる。
#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
IO.foreach("roll.txt") do |msg|
msg.chomp!
length=msg.length
0.upto(length-1) do |i|
STDERR.print "\r" + " "*(length-1-i) + msg[0..i] + " "
sleep(0.05)
end
print "\n"
end
プログラム中に現れる "\r"
は、ASCIIコード13番の
CR(Carriage Return)で、端末出力時必ず行の先頭に復帰させるための制御文字
である。また、実際に出力する行のところで、
print
ではなくSTDERR.print
としている。
末尾に空白文字列 " "
を余分に出力している。
という工夫がある。これらの理由を知るには、実際にその部分を取った
プログラムを実行してみるとよい。sleep
の引数を変えてみると
表示する速度が変わるので、最適な速さを探してみるとよいだろう。
また表示元テキストroll.txt
の末尾に余計な空白を入れておいた
のは、全て表示し終わったあとの余韻を残すためである。