Skip to content

connermcd's intermediate code

connermcd edited this page Mar 13, 2013 · 1 revision
class Player
  MAX_HEALTH = 20
  LOW_ON_HEALTH = 10

  def play_turn(warrior)
    @warrior = warrior
    @faraway = warrior.listen
    @nearby = {
      forward:  warrior.feel(:forward),
      left:     warrior.feel(:left),
      right:    warrior.feel(:right),
      backward: warrior.feel(:backward)
    }

    case
    when ticking_captives.any?     then do_ticking(ticking_captives)
    when nearby_captives.any?      then do_captives(nearby_captives)
    when nearby_enemies.any?       then do_enemies(nearby_enemies)
    when nearby_bound_enemies.any? then do_bound_enemies(nearby_bound_enemies)
    else do_safety
    end
  end

  def do_ticking(ticking_captives)
    direction = @warrior.direction_of ticking_captives.first
    if nearby_ticking.any?
      @warrior.rescue! nearby_ticking.keys.first
    elsif @nearby[direction].enemy?
      enemy_blocking_route_to_ticking(direction)
    # elsif low_on_health? && @warrior.look(direction).select(&:enemy?).any?
    elsif low_on_health? && enemies_ahead(direction).count > 0
      @warrior.rest!
    else
      walk(direction)
    end
  end

  def enemies_ahead(direction)
    x = get_warrior_location[0] + dir_to_loc(direction)[0]
    y = get_warrior_location[1] + dir_to_loc(direction)[1]
    @faraway.select(&:enemy?).select do |s|
      @nearby.keys.each do |dir|
        s.location == [x + dir_to_loc(dir)[0]] + [y + dir_to_loc(dir)[1]]
      end
    end
  end

  def get_warrior_location
    [@nearby[:backward].location[0]+1, @nearby[:left].location[1]+1]
  end

  def dir_to_loc(direction)
    case
    when :forward  then [1,0]
    when :left     then [0,-1]
    when :right    then [0,1]
    when :backward then [-1,0]
    end
  end

  def do_captives(captives)
    @warrior.rescue! captives.keys.first
  end

  def do_enemies(enemies)
    if enemies.count > 1
      @warrior.bind! enemies.keys.first
    elsif low_on_health? && nearby_empty.any?
      walk(nearby_empty.keys.sample)
    elsif nearby_bound_enemies.count > 1
      @warrior.detonate! enemies.keys.first
    else
      @warrior.attack! enemies.keys.first
    end
  end

  def do_bound_enemies(bound_enemies)
    @warrior.attack! bound_enemies.keys.first
  end

  def do_safety
    if full_health? || @warrior.listen.empty?
      walk_towards_action
    else
      @warrior.rest!
    end
  end

  def walk_towards_action
    if @faraway.select(&:captive?).any?
      walk(@warrior.direction_of @faraway.select(&:captive?).first)
    elsif @faraway.select(&:enemy?).any?
      walk(@warrior.direction_of @faraway.select(&:enemy?).first)
    else
      walk(@warrior.direction_of_stairs)
    end
  end

  def walk(direction)
    if @faraway.any? && @nearby[direction].stairs?
      @warrior.walk! nearby_empty.keys.sample
    else
      @warrior.walk! direction
    end
  end

  def enemy_blocking_route_to_ticking(direction)
    empty_spaces = nearby_empty.keys - [:backward]
    if empty_spaces.any?
      @warrior.walk! nearby_empty.keys.first
    elsif nearby_enemies.count > 1
      excess_enemies = nearby_enemies.keys - [direction]
      @warrior.bind! excess_enemies.first
    elsif @warrior.look(direction)[0..1].select(&:enemy?).count > 1
      @warrior.detonate! direction
    else
      @warrior.attack! direction
    end
  end

  def ticking_captives
    @faraway.select(&:ticking?)
  end

  def nearby_ticking
    @nearby.select { |d, space| space.ticking? }
  end

  def nearby_captives
    @nearby.select { |d, space| space.to_s == "Captive" }
  end

  def nearby_bound_enemies
    @nearby.select { |d, space| space.captive? && space.to_s != "Captive" }
  end

  def nearby_enemies
    @nearby.select { |d, space| space.enemy? }
  end

  def nearby_empty
    @nearby.select { |d, space| space.empty? && !space.stairs? }
  end

  def full_health?
    @warrior.health == MAX_HEALTH
  end

  def low_on_health?
    @warrior.health <= LOW_ON_HEALTH
  end
end