[[プログラミング言語/Ruby/コードリーディング/しりとりゲーム]]

*AutoPlayerクラス [#ddabee6e]

**リスト4-1 AutoPlayerインタフェース [#f75a126a]
 class AutoPlayer < Player
   include Rands
   def answer(before)
 private
   def think_answer(before)

スーパークラスを同じくPlayerとするManualPlayerクラスよりもシンプルだ。
公開されているメソッドはanswerしかない。



**リスト4-2 AutoPlayer#answer [#q35b4e4a]
  def answer(before)
    if before
      while wd = think_answer(before)
        if @gm.twice? wd
          @dictionary.delete_if{|x| x == wd}
        else
          break
        end
      end
      wd
    else
      array_rand(@dictionary)
    end
  end

インデントのネストがわりと深めだ。

"初回の回答"="beforeがnil"はManualPlayerの項で語ったとおりで、
最初のインデントネストのif-elseはその分岐だ。
要件どおり、初回の回答者を任された場合、自身の辞書からarray_randで
ひとつ見繕って返す。

そうでない場合、think_answerで回答を導き出すようだ。

answerの返り値は、wdまたはarray_randの返り値である。



**リスト4-3 think_answer [#fa94ede2]
  def think_answer(before)
    @dictionary.detect{|x| /\A#{before[-1, 1]}\w*/ === x}
  end

Array#detectメソッド(ComparableモジュールのMix-in)は、
配列の要素に渡されたブロックを試していって、結果が真になる
最初の要素を返す。どれも真にならなければnilだ。

think_answerはほぼこれのラップだ。しりとりできている単語かnilを返す。



**リスト4-4 AutoPlayer#answerの一部 [#ldef2c4d]
      while wd = think_answer(before)
        if @gm.twice? wd
          @dictionary.delete_if{|x| x == wd}
        else
          break
        end
      end
      wd

このwhileループはthink_answerがnilを返すまで続く。
think_answerがnilを返すときというのは、辞書にしりとりできる
単語がない場合だ。つまり回答不能である。
wdにもthink_answerの返り値としてnilが代入されているはずなので、
answerはnilを返す。

そして、whileの中では自らのGameMasterに考え出した回答が既出かどうか
問い合わせる。twice?が偽、つまり既出ではない有効な回答ならば
ループを終える。wdがその回答として返される。

既出の回答である場合は、それはもう使えない単語なので辞書から消してしまう。
Array#delete_ifは、要素ごとにブロックを試し、結果が真ならばその要素を削ってしまう
破壊的メソッドである。

相手が優秀な回答者ならば、AutoPlayerの辞書から次々単語が消されていき、
やがてthink_answer(の中のArray#detect)が失敗してnilを返すだろう。

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS