短いRubyコードの実行

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

乱数

ゲーム性のあるプログラムを作るためには、プログラムを起動する度に違 う値を返すメソッドが不可欠である。計算機では何らかの決まりに沿って 見かけ上ランダムな数を順次発生させられる。厳密にはこれを 擬似乱数という。

乱数の種を初期化するsrand メソッドで生成される乱数を変えることができる。 以下のプログラム断片は、じゃんけんのグーチョキ パーをランダムに出すものである。

janken = ["グー", "チョキ", "パー"]
srand()				# 乱数の種を初期化
hand = rand(3)			# 3未満の整数(0, 1, 2)を発生
printf("私の手は %s です.\n", janken[hand])

上のようにsrand()と引数なしで呼ぶとその時の時刻などを元に 推測困難な種となるが、たとえばsrand(10)のように 既知の値を与えるとその種による乱数列が出るので、毎回同じ乱数を出させて デバッグするときなどに有用である。

文字列操作

文字列の一部を取り出したり、切り取ったりすることができる。 ゲーム性や実用性の高いものを作るときには、文字列の一部を表示したり 一部を別の単語に置き換えたりすることが必要になる。これまで 触れなかった少し複雑な文字列操作メソッドを紹介する。 以下の説明ではS を文字列とする。

その他の文字列操作メソッドについては、 Rubyマニュアル - Stringクラスのマニュアルページを参照すること。

時間

Rubyプログラムが動いているときの現在時刻はTimeを 利用して取得する。

たとえば10秒以内になにかの処理をやらせる場合は以下のようにする。

start = Time.now.to_i
while true
  ………何かの処理………
  if Time.now.to_i - start > 10
    puts "時間切れです"
    break
  end
end

プログラムの実行を一時停止したいときには sleepメソッドを使う。

繰り返し

要素全てに対する繰り返し

配列に複数の値が入っているときの繰り返し処理の書き方にはいくつかある。 以下の処理はどれも同じ働きをする。

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

デモ出力プログラムの完成

以上のことを組み合わせると以下のようなプログラムになる。

roll.rb

#!/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)で、端末出力時必ず行の先頭に復帰させるための制御文字 である。また、実際に出力する行のところで、

という工夫がある。これらの理由を知るには、実際にその部分を取った プログラムを実行してみるとよい。sleep の引数を変えてみると 表示する速度が変わるので、最適な速さを探してみるとよいだろう。 また表示元テキストroll.txtの末尾に余計な空白を入れておいた のは、全て表示し終わったあとの余韻を残すためである。


本日の目次