Hatena::Grouprubyist

Ruby初心者prinyの学習帳 RSSフィード

2008-12-03練習:プログラミング入門 - 9. クラス

OrangeTree クラスを作ってみなさい。このクラスには、木の高さを返すheightメソッドと、メソッドを呼ぶことで、1年分時間を進める oneYearPasses メソッドがあります。毎年、この木は成長し大きくなります(オレンジの木が 1 年に伸びる分だけ)。そして、ある年限が来たら(これもメソッド呼び出しによります) その木は死んでしまいます。最初の 2,3 年は実をつけませんが、その後は実がなる様にします。で、成長した木は若い木よりたくさん実をつけます。このあたりはあなたが納得するよう調節してみましょう。そして、もちろん countTheOranges (木になっているオレンジの数を返す)メソッドと、 pichAnOrange (オレンジをひとつ摘むメソッド。このメソッドで @orangeCount が、1だけ小さくなり、いかにおいしいオレンジだったかを告げる文字列かあるいは、もう木にオレンジがなっていないことを告げる文字列かを返します。)を実行できるようにしなければいけません。それと、ある年に取り残したオレンジは次の年には落ちてしまうようにしましょう。

http://www1.tf.chiba-u.jp/~shin/tutorial/index.rb?Chapter=09

いろんな実を収穫できる「ふしぎな木」をつくる。

# 「ふしぎな木」には 5 種類の実がなる
FRUIT_VARIATION = ["モモ", "リンゴ", "ナシ", "みかん", "さくらんぼ"]
# 「ふしぎな木」の寿命は 10 年
MAX_AGE = 10

class WonderfulTree  
  def initialize
    @tree_age = 0       # 樹齢。初期値は 0 (年)
    @tree_height = 0    # 木の高さ。初期値は 0 (cm)
    @fruit_list = []    # 木になっている実のリスト。初期値は空
  end
  
  attr_reader :fruit_list
  
  # 「ふしぎな木」の高さを伝える
  def speak_tree_height
    puts "「ふしぎな木」の高さは #{@tree_height} cm です。"
  end
  
  # 「ふしぎな木」になっている実の数を伝える
  def speak_fruit_num
    puts "「ふしぎな木」になっている実の数は #{@fruit_list.size} 個です。"
  end
  
  # 実を 1 つだけ収穫する。
  def harvest_one_fruit(index)
    harvested_fruit = @fruit_list.delete_at(index)
    # 収穫できたら、収穫した実の種類を伝える。
    if harvested_fruit == nil
      $stderr.puts "その番号の実は存在しません。"
    else
      puts "#{harvested_fruit}」を 1 個収穫しました。"
    end
  end
  
  # 「ふしぎな木」に実がなっているとき、実の種類を伝える
  def speak_fruit_list
    if @fruit_list.size >= 1
      @fruit_list.each_with_index do |fruit, index|
        puts "#{index}:#{fruit}"
      end
      puts "を収穫できます。"
    end
  end
  
  # 経過させる年数を引数にもらって、時間を進める
  def pass_time(year)
    # 寿命がきていなかったら、高さ、樹齢を増やし、実を実らせる。
    # 寿命がくると「ふしぎな木」は枯れてしまう
    if @tree_age + year  < MAX_AGE
      year.times do |i|
        @tree_height += 20
        @tree_age += 1
        bear_seed
      end
      puts "「ふしぎな木」は、樹齢 #{@tree_age} 年になりました。"
    else  
      puts "「ふしぎな木」は寿命がきて、枯れてしまいました。"
      exit  #プログラム終了
    end
  end
  
  private
  
  # 実をつける
  def bear_seed
    #木は 3 年たつと実をつける
    if @tree_age >= 3
      #ある年に取り残した実は次の年には落ちる(去年の実の数を今年の実の数で上書きする)
      @fruit_list = []

      #成長するほどたくさんの実をつける
      fruit_num = (@tree_age-2)*2
      fruit_num.times do |i|
        @fruit_list.push(FRUIT_VARIATION[rand(FRUIT_VARIATION.size)])
      end
    end
  end
end

guide = <<EOS
あなたは、以下の 5 種類のコマンドを使えます。

g1 : 1 年、時間を進めます。「ふしぎな木」が成長します。
g2 : 2 年、時間を進めます。「ふしぎな木」が成長します。
f : 収穫できる実が表示されます。収穫したい実の番号を入力すると、実を収穫できます。
h : 「ふしぎな木」の高さを調べます。
n : 「ふしぎな木」に実っている実の数を調べます。

「ふしぎな木」は成長すると実を実らせます。
寿命がくると枯れてしまいます。

さあ、コマンドを入力して、「ふしぎな木」を育てましょう。
EOS

puts guide

tree = WonderfulTree.new

while true
  puts "コマンドを入力してください。"
  command = gets.chomp
  case command.downcase
  when "g1"
    tree.pass_time(1)
  when "g2"
    tree.pass_time(2)
  when "f"
    if  tree.fruit_list.size >= 1
      tree.speak_fruit_list
      puts "収穫したい実の番号を入力してください。"
      fruit_num = gets.chomp
      if /\d/ =~ fruit_num
        tree.harvest_one_fruit(fruit_num.to_i)
      else
        $stderr.puts "入力が正しくありません。"
      end
    else
      puts "収穫できる実はありません。"
    end
  when "h"
    tree.speak_tree_height
  when "n"
    tree.speak_fruit_num
  else
    $stderr.puts "コマンドが正しくありません。"
  end
end

実行結果

あなたは、以下の 5 種類のコマンドを使えます。

g1 : 1 年、時間を進めます。「ふしぎな木」が成長します。
g2 : 2 年、時間を進めます。「ふしぎな木」が成長します。
f : 収穫できる実が侮ヲされます。収穫したい実の番号を入力すると、実を収穫できます
。
h : 「ふしぎな木」の高さを調べます。
n : 「ふしぎな木」に実っている実の数を調べます。

「ふしぎな木」は成長すると実を実らせます。
寿命がくると枯れてしまいます。

さあ、コマンドを入力して、「ふしぎな木」を育てましょう。
コマンドを入力してください。
g1
「ふしぎな木」は、樹齢 1 年になりました。
コマンドを入力してください。
g2
「ふしぎな木」は、樹齢 3 年になりました。
コマンドを入力してください。
f
0:ナシ
1:みかん
を収穫できます。
収穫したい実の番号を入力してください。
0
「ナシ」を 1 個収穫しました。
コマンドを入力してください。
f
0:みかん
を収穫できます。
収穫したい実の番号を入力してください。
3
その番号の実は存在しません。
コマンドを入力してください。
g2
「ふしぎな木」は、樹齢 5 年になりました。
コマンドを入力してください。
h
「ふしぎな木」の高さは 100 cm です。
コマンドを入力してください。
n
「ふしぎな木」になっている実の数は 6 個です。
コマンドを入力してください。
f
0:モモ
1:モモ
2:ナシ
3:リンゴ
4:モモ
5:リンゴ
を収穫できます。
収穫したい実の番号を入力してください。
2
「ナシ」を 1 個収穫しました。
コマンドを入力してください。
f
0:モモ
1:モモ
2:リンゴ
3:モモ
4:リンゴ
を収穫できます。
収穫したい実の番号を入力してください。
2
「リンゴ」を 1 個収穫しました。
コマンドを入力してください。
g2
「ふしぎな木」は、樹齢 7 年になりました。
コマンドを入力してください。
g2
「ふしぎな木」は、樹齢 9 年になりました。
コマンドを入力してください。
g2
「ふしぎな木」は寿命がきて、枯れてしまいました。

気になること

入力が正しくない系のエラー出力に $stderr を使ってみた。こういうエラーは $stderr を使うので正しい?

実を収穫するについて、クラスの中と外に分けて書いている。もっとよい方法がある?

コマンドのところで、「while true」と書いたけど、お作法的にあり?こういう場合は、どんな条件にするのが適切?