2016年8月20日土曜日

Ruby Warrior をやってみる(Level6)

はい。また Ruby Warrior です。
前回に引き続き Level6 です。

だんだん難しくなってきました。
例によって、説明文を意訳します。

The wall behind you feels a bit further away in this room. And you
hear more cries for help. You can walk backward by passing ‘:backward’
as an argument to walk!. Same goes for feel, rescue! and attack!.
Archers have a limited attack distance.

背後に壁があるのを感じる。
そして、助けを求める声も聞こえる。
:backward を walk! に引数にすることで後退することができる。
これを使って感じ取り、捕虜を助け、そして敵を攻撃せよ。
ここにいるアーチャーは範囲攻撃を持っている。

って感じですかね。
どうやら feel 系(warrior.feel(:backward).xxx)のメソッドの引数や、warrior のメソッド(e.g. warrior.walk!(:backward) など)に :backward シンボルを渡すことで、戦士の背後のチェックや行動ができるようになるみたいです。
ちなみに、:backward の反対は :forward を使うこともできます。
ココらへんは、デフォルト引数(xxx(direction=:forward)みたいな感じ)でも使ってるんでしょうか。

さて、ここいら辺の情報を持ってしても適当に実装するとクリアできませんでした。
相変わらずロジックがショボイからでしょうか。
悲観的なことは置いていて、クリアしたコードは以下のとおり。

class Player
  def initialize
    @health = 20
    @direction = :backward
  end
  
  def play_turn(warrior)
    @warrior = warrior

    return warrior.rescue!(@direction) if feel_captive?
    @direction = change_direction if feel_wall?

    if decrease_health?
      check_enemy? ? warrior.attack! : warrior_walk!
      @direction = change_direction if pinch_health?
    else
      if max_health?
        check_enemy? ? warrior.attack! : warrior_walk!
      else
        warrior.rest!
      end
    end
    @health = warrior.health
  end
  
  def decrease_health?
    @health > @warrior.health
  end
  
  def pinch_health?
    @warrior.health <= 8
  end
  
  def max_health?
    @warrior.health == 20
  end
  
  def feel_captive?
    @warrior.feel(@direction).captive?
  end
  
  def feel_wall?
    @warrior.feel(@direction).wall?
  end
  
  def check_enemy?
    @warrior.feel.enemy? || @warrior.feel(:backward).enemy?
  end
  
  def warrior_walk!
    @warrior.walk!(@direction)
  end
  
  def change_direction
    @direction === :forward ? :backward : :forward
  end
end

デフォルトである「# cool code goes here」のコメントはクールなコードな気分がなんとなくしなくなったので外しました。

説明文にあったとおり、このレベルから方向を指定できるようになったので、方向を保持するインスタンス変数を使うようにしました。これ使って救助や攻撃、移動の方向を指定するようにします。

あと、if 文が多用に使われて見難いので判定系はメソッドに分けてみました。メソッド化に当たり、play_turn() の warrior を各メソッドの引数で渡そうかとも思いましたが、ゲーム内だけなので、これもインスタンス変数を用いるようにしました。

終盤のアーチャー 2 体部分がいやらしいのですが、攻撃を一定量もらうと攻撃の当たらない位置まで一旦退いて回復後出直す方法をとっています。

うーん。今回は、敵の配置等を見て、このレベル専用に実装したんですが、これ汎用的な実装できるんでしょうか?
終わったら他の人のコードも見てみましょうか。。。

Written with StackEdit.

0 件のコメント:

コメントを投稿