roy > naoya > 基礎プログラミングI·情報検索 > (5)制御構造[2]
(5) 05/17の授業内容:制御構造[2]
[1] 条件判断への導入
前回は、制御構造のうち「繰り返し」について学んだ。今回はもう一つの制御構造である「条件判断」について確認した上で、「繰り返し」表現の記法であるwhile-endと組み合わせた用法について確認する。
条件判断は次のような場面で活用できる。
- 計算問題を出す。正解していれば「正解です!」と表示し、間違っていれば「不正解です!」と表示する。
- 5問クイズを出す。4問以上正解で「ワンダフル!」、それ以外は「まあまあ」と表示する。
これらの例を図式的に(フローチャートで)表現すると以下のようになる。◇の箇所で条件を満たしているかどうか判定が行われ、満たしている場合と満たしていない場合では異なる動作を行っている(前回と同じ図)。
プログラムでこれを表現する場合、左右に分けて書くことができないので、上下に分割して書く。
正解している場合 正解です!と表示 そうでない場合 不正解です!と表示
プログラムは上から進んでくるが、この部分では条件に応じて「正解です!」が表示されたり「不正解です!」が表示されたりする。順番に1行ずつ実行されて両方のメッセージが表示されることはない。
[2] 条件判断(1):if-end
条件判断の代表格となるのがif-endである。if文と呼ぶこともあるが同じものである。
条件が1つの場合
if文の基本構造を先ほどの日本語で書いた条件分岐の例と対比させながら確認してみよう
正解している場合 正解です!と表示 そうでない場合 不正解です!と表示
if 条件A #=>条件Aを満たせば 処理A #=>処理Aを実施する else #=>条件Aを満たさない場合は 処理B #=>処理Bを実施する end
「正解している場合」に対応するのが「if 条件A」となる。ifの横に具体的に条件を書く。「そうでない場合」は「else」と表現する。最後にはendがついている。endをつけ忘れるとプログラムが動かない。この構造を把握するために、以下のプログラムをif.rbという名称で保存し、実行してみよう。
#!/usr/koeki/bin/ruby
print"問題です。\n"
print"28の約数の和は28になる。\n"
print"Yesの場合は1を、Noの場合は2を入力\n"
answer = gets.chomp!.to_i
if answer == 1
print"正解です!\n"
else
print"不正解です!\n"
end
ifの横には「answer == 1」という条件が書かれている。==は右辺と左辺が等しいという論理演算子である。つまり条件は「answer(に代入されている値)が1である」ということになる。このプログラムの実行結果を以下に示す。正解した場合と不正解の場合いずれも示すので、各自で実行した際に同じ結果となるか確認してみよう。
pan{c10xxxx}% ruby if.rb[Return] 問題です。 28の約数の和は28になる。 Yesの場合は1を、Noの場合は2を入力 1[Return] 正解です!
pan{c10xxxx}% ruby if.rb[Return] 問題です。 28の約数の和は28になる。 Yesの場合は1を、Noの場合は2を入力 2[Return] 不正解です!
条件が2つ以上の場合
次はもう少し複雑なケースを考えてみよう。以下は80点以上ならA、60点以上ならB、60点未満ならCと表示するという状況をフローチャートで表現したものである。1つ目の◇で80点以上という条件を満たしているか判定が行われ、満たさない場合は2回目の◇で60点以上という条件を満たしているかどうか調べている。
このように2つの条件がある場合、if文ではどのように書くのだろうか。このフローチャートをプログラムで表現したものが以下(hantei.rb)である。
#!/usr/koeki/bin/ruby
print"得点を入力してください\n"
score = gets.chomp!.to_i
if score >= 80 #=>1つ目の条件を記載
print"A評価です\n" #=>1つ目の条件を満たす場合に実施
elsif score >= 60 #=>1つ目の条件を満たさない場合2つ目の条件を満たすか判定
print"B評価です\n" #=>2つ目の条件を満たす場合に実施
else #=>いずれも満たさない場合は
print"C評価です\n" #=>これを実施する
end
2つ目の条件を記載するためにelsifが登場している。ifの横に記載された1つ目の条件を満たすか否かがまず判定され、満たした場合にはその下に書かれた処理が実行される。満たさない場合にはelsifの行で2つ目の条件を満たすかどうか判定が行われ、満たす場合はその下の処理、満たさない場合はelse以下の処理が行われる。最後には必ずendがつく。
なお、ifの行やelsifの行で登場している「>=」は≧と同じ意味である。キーボードには≧のキーはないので、≧のかわりに「>=」としている。
条件が3つ以上になった場合はelsifを何度も使用して記述する。これについて詳細は[3]if-endの応用[補足]を参照のこと。
if文のまとめ
- 次の基本構造を持つ。
if 条件A 処理A elsif 条件B 処理B else 処理C end
- 最後にはendを必ずつける。
- 条件が3つ以上の場合はelsifを繰り返し使用する。
[3] 条件判断(1'):if-endの応用[補足]
[4] 条件判断(2):その他の条件判断[補足]
[5] 出席課題
hantei.rbを書き換え、S〜Dの5段階評価ができるようにしてみよう(hantei2.rb)。得点と評価の関係は以下の通り。
- 90点以上:S
- 80点以上:A
- 70点以上:B
- 60点以上:C
- 60点未満:D
hantei.rbを別名で保存してから修正を行うと良い。Ctrl+x Ctrl+wで名前をつけて保存になる。programディレクトリにhantei2.rbという名称で保存をしてから修正を始めよう。
制限時間は10分。うまくいかない場合は、できたところまででよいのでメールで解答を送信すること。出席点は2点。提出要領は下記の通り。
- 提出先:課題提出用メールアドレス
- メールのSubject:ruby05
- 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降にプログラムおよび実行結果を貼りつける。その他説明を加えても良い。
[6] while-endの特殊な用法
while true
コンビニやスーパーのレジのプログラムを書くことを考えてみよう。複数の商品を購入することを考えると、以下の部分を繰り返して実行する、すなわちwhile-endを用いて書くことが予想される。
- バーコードを読取り金額を取得する(キーボードから金額を入力する)。
- その金額を合計金額に加算する。
- 合計ボタンを押したらお会計、押さなければ次の商品のバーコードを読み取る
では、while-endを使ってどのように書いたらよいだろうか。前回はwhileの横に繰り返し継続条件を書き、その条件を満たさなくなった時点で繰り返しから抜けるようにしていた。
しかし、レジのプログラムではこの方略は採用できない。合計ボタンを押したときに繰り返しを終了しなければならないからである。つまりユーザーからの入力によって繰り返しを終了する必要があり、あらかじめ繰り返しの回数を定めておくことができないのである。
このような場合にはwhile trueを用いる。trueとは条件を満たすという意味である。したがってwhile trueは、whileの横の繰り返し継続条件が「常に条件を満たす」ということになり、永久に繰り返しを継続せよという構文になる。このままでは本当に永久にプログラムが継続するため、while-end内に別途繰り返し終了条件を設ける。まずはwhile trueを用いたプログラム(register.rb)を確認してみよう。
#!/usr/koeki/bin/ruby
sum = 0
while true
print"金額を入力してください(お会計は0と入力):\n "
price = gets.chomp!.to_i
if price == 0 then
break
end
sum += price
end
printf("ありがとうございます。お会計 %d 円になります。\n", sum)
pan{c10xxxx}% ruby register.rb[Return] 金額を入力してください(お会計は0と入力): 200[Return] 金額を入力してください(お会計は0と入力): 100[Return] 金額を入力してください(お会計は0と入力): 350[Return] 金額を入力してください(お会計は0と入力): 0[Return] ありがとうございます。お会計650円になります。
while-end内では、printメソッドでメッセージを表示し、getsメソッドを使ってユーザーからの金額の入力を受け取りpriceに代入している。そして、priceの値をsumに加算代入することで、繰り返しを行うたびにsumの値は増加する。
新しく登場したのはプログラム中に黄色で示した、while trueとif-endである。
- while true:trueは条件を満たすという意味。while tureとすると常に条件を満たすことになり、永久に繰り返しが行われる。このままでは本当に終了しないので、while-end内に別途繰り返しを終了する条件を入れる。具体的にはif文を使用し、if文の中にbreakを入れる。
- break:繰り返しから抜ける命令。このプログラムではpriceに代入された値が0であれば(=ユーザが0を入力したら)、breakが実行される。breakが実行されるとwhile-endの繰り返しから抜け出し、endの下のprintfの行に進む(for-endやuntil-endでも使用することができる)。
while trueについてのまとめ
- ユーザの入力に基づいて繰り返しを終了する場合などにはwhileの横に繰り返しを継続する条件を書くかわりにwhile tureとする。
- while trueとすると永久に繰り返しが継続し、終了しない。
- while-end内にif文を設け、if文の中にbreakを入れる。breakは繰り返しから抜ける命令で、if文に記載された条件を満たす場合に繰り返しを終了することになる。
breakするための条件は多様
register.rbではユーザが0と入力することで繰り返しから抜けたが、breakするための条件は自由に設定することができる。
まずは、ユーザがキーボードからquitという文字列を入力したときにbreakするように書き換えてみよう(register2.rb)。
#!/usr/koeki/bin/ruby
sum = 0
while true
print"金額を入力(終了はquit):\n"
price = gets.chomp!
if price == "quit"
break
end
sum += price.to_i
end
printf("合計%d円です。\n", sum)
このプログラムでは、ユーザがキーボードから入力する値は2種類の型がある。
- 整数:商品の金額
- 文字列:breakするための「quit」
register.rbでは、price = gets.chomp!.to_iというようにgetsメソッドの後ろに、to_iメソッドをつけていた。to_iメソッドは値の型を整数に変換するメソッドである。ユーザが商品の金額を入力した場合は、整数変換した上でpriceに値が代入されるので問題はないが、quitを入力した場合はどうなるだろうか。
quitなどの文字列は整数に変換すると0になる。このため、キーボードからquitを入力してもpriceに代入される際には0になってしまう。したがって、price = gets.chomp!.to_iとするとpriceに代入された値がquitである場合にbreakするというif文に記載された条件を満たすことができない。
正しく終了するためにはto_iの位置を変更する必要がある。gets.chomp!.to_iをgets.chomp!に修正し、to_iをsum += price.to_iの位置につけ、sumに金額を加算する際に整数に変換すればうまく動くようになる。
なお、breakするための条件を書き間違え、繰り返しから抜けられなくなった場合は、Ctrl+cで強制終了することができる。
pan{c10xxxx}% ruby regi.rb[Return] 金額を入力(終了はquit): 198[Return] 金額を入力(終了はquit): 298[Return] 金額を入力(終了はquit): quit[Return] 合計496円です。
値の型変換メソッドをつける位置について
- 変数.to_iのように変数につけることができる。
- アルファベットや日本語を整数に変換すると0になる。
- プログラムが止まらなくなったらCtrl+cで強制終了できる。
[7] break、redo、next
breakと同じように、while-end、for-end、until-endで使用することができる繰り返し制御の記法を参考までに以下に示す。
- break:繰り返しの実行を中止し、繰り返しから抜ける
- redo:その回の繰り返しを無効化し、その回の繰り返しの先頭からやりなおす(whileの横の繰り返し継続条件は満たしているものとして扱われる)
- next:その回の繰り返しを無効化し、次の繰り返しに突入する(次の繰り返しを実施するかどうかはwhileの横の条件次第)
redoについては以下のように不適切な入力に対する再入力の促しとして使用できる。
while true
print"1、2、3のいずれかを入力:\n "
number = gets.chomp!.to_i
if number < 1 || number > 3
print"1、2、3のいずれかを入力してください\n"
redo
end
(略)
end
(略)
if number < 1 || number > 3では、「||」を使って2つの条件を併記している。「||」は「または」という意味であるため、この条件はnumberが1未満または3を超える場合ということになる。
この条件を満たす場合には、次のprintの行が実行され正しい値の入力が促される。そして、redoを行うことで、直前に入力した値を無効にして、while trueの真下の行に戻される。
[8] レポート課題
課題
前回作成したreport2a.rbについて以下の改良をできるところまで実施しなさい。必ず1番から順に実施すること(report3.rb)(8点満点)
- 最後に合計得点だけでなく、平均点が表示できるようにする(小数点以下は第1位まで)
- while trueを用いて書き直し、キーボードからexitと入力した際に繰り返しから抜ける(breakする)ようにする
- breakするための条件にレポートの得点を8回入力した場合も追加する(条件が2つになる)
- レポートの得点は最高8点とし、入力した得点がマイナスの場合や8点を超える場合は入力間違いとみなして、再入力をうながすようにする
- 極めてよくできたレポートの場合は8点を超える点をつける場合があるので、8点を超える得点を入力した場合には、正しい得点かどうか確認し、正しければ合計に加算し、誤っていれば再入力をうながす(マイナスの場合は無条件で再入力)
提出要領
- 提出先:課題提出先メールアドレス
- 提出期限:5/23(日)23:00
- メールのSubject:report03
- 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降は下記の構成とする
- 何番まで実施したか
- 作成したプログラム
- プログラムの実行結果
- プログラムの説明
- 感想
- 添付ファイル(report3.rb)
作成要領
- 採点基準:期限内提出点(2点)、メールの体裁(1点)、プログラム(2.5点)、プログラムの説明(2.5点)
- プログラムの説明は、それぞれの修正について、変更点と変更理由がわかるように説明する。
- プログラムについては、5個の修正につき1つ0.5点で評価する。
- 他人のレポートを丸写しした場合は、写した側、写させた側共に0点とする。
- わかりにくい説明や、Webページを単にコピー&ペーストしただけの説明は減点する。一度読み直してから提出すること。
- 驚異的に良くできているレポートについては満点の8点を超える得点をつけることがある。
- よくできていたレポートは、他の人の参考になるよう、本人が特定できないような形で掲載する。掲載してほしくない場合はメールでの課題提出時にその旨記載すること。