Skip to content

Instantly share code, notes, and snippets.

@tpett
Last active December 22, 2015 10:10
Show Gist options
  • Save tpett/6456997 to your computer and use it in GitHub Desktop.
Save tpett/6456997 to your computer and use it in GitHub Desktop.
Player objects for the RubyWarrior game. Includes both the beginner and intermediate versions.
class Player
attr_reader :warrior, :spaces
MAX_HP = 20
RETREAT_HP = 10
def play_turn(warrior)
set_state(warrior)
if @retreating
if next_space.wall?
@retreating = false
play_turn(warrior)
else
warrior.walk!(@direction)
end
elsif next_space.wall?
if @direction == :forward
warrior.pivot!
else
change_direction!
play_turn(warrior)
end
elsif health_decreasing? && !enemy_close?
warrior.walk!(@direction)
elsif should_retreat?
change_direction!
@retreating = true
play_turn(warrior)
elsif next_space.captive?
warrior.rescue!(@direction)
elsif should_attack?
warrior.attack!(@direction)
elsif should_shoot?
warrior.shoot!(@direction)
elsif should_rest?
warrior.rest!
elsif should_walk?
warrior.walk!(@direction)
end
@previous_hp = warrior.health
end
private
def set_state(warrior)
@warrior = warrior
@direction ||= default_direction
@previous_hp ||= MAX_HP
@spaces = warrior.look
end
def change_direction!
if @direction == :forward
@direction = :backward
else
@direction = :forward
end
end
def default_direction
if warrior.look(:backward).any?(&:captive?) && warrior.none?(&:enemy?)
:backward
else
:forward
end
end
def health_decreasing?
warrior.health < @previous_hp
end
def health_low?
warrior.health <= RETREAT_HP
end
def enemy_close?
warrior.feel(:forward).enemy? ||
warrior.feel(:backward).enemy?
end
def next_space
spaces.first
end
def should_attack?
next_space.enemy?
end
def should_shoot?
if enemy_distance = spaces.index(&:enemy?)
spaces[0..enemy_distance].none?(&:captive?)
end
end
def should_walk?
next_space.empty? ||
next_space.stairs?
end
def should_rest?
!enemy_close? &&
!health_decreasing? &&
warrior.health < MAX_HP
end
def should_retreat?
!next_space.enemy? &&
health_decreasing? &&
health_low?
end
end
class Player
attr_reader :warrior, :enemies, :movements
DIRECTIONS = %i(left right forward backward)
MAX_HP = 20
LOW_HP = 10
def play_turn(warrior)
set_state(warrior)
if out_numbered?
warrior.bind!(enemies_in_vicinity.first)
elsif enemies_in_vicinity.any? && should_detonate?
warrior.detonate!(enemies_in_vicinity.first)
elsif enemies_in_vicinity.any? && should_attack?
warrior.attack!(enemies_in_vicinity.first)
elsif true_captives_in_vicinity.any?
warrior.rescue!(true_captives_in_vicinity.first)
elsif need_rest? && should_rest?
warrior.rest!
elsif captives_in_vicinity.any? && !ticking_captives?
warrior.rescue!(captives_in_vicinity.first)
else
@movements << walk_direction
warrior.walk!(walk_direction)
end
end
private
def set_state(warrior)
@warrior = warrior
@enemies ||= enemy_spaces
@movements ||= []
end
def enemy_locations
@enemies.collect(&:location)
end
def out_numbered?
vicinity.values.select(&:enemy?).count > 1
end
def vicinity
Hash[DIRECTIONS.map { |dir| [dir, warrior.feel(dir)] }]
end
def enemies_in_vicinity
vicinity.keys.select { |dir| vicinity[dir].enemy? }
end
def captives_in_vicinity
vicinity.keys.select { |dir| vicinity[dir].captive? }
end
def true_captives_in_vicinity
captives_in_vicinity.reject { |dir| enemy_locations.include?(vicinity[dir].location) }
end
def empty_in_vicinity
vicinity.keys.select { |dir| vicinity[dir].empty? && !vicinity[dir].stairs? }
end
def multiple_enemies_ahead?
warrior.look.select(&:enemy?).size > 1
end
def need_rest?
warrior.health < MAX_HP &&
(enemy_spaces.any? || captive_spaces.any? { |space| enemy_locations.include?(space.location) })
end
def should_detonate?
multiple_enemies_ahead? &&
ticking_captive_spaces.none? { |space| warrior.distance_of(space) <= 2 }
end
def should_attack?
!ticking_captives? || (ticking_captives? && in_walk_loop?)
end
def should_rest?
!ticking_captives? ||
(
ticking_captives? &&
warrior.health < LOW_HP &&
warrior.look.select(&:enemy?).any?
)
end
def ticking_captives?
ticking_captive_spaces.any?
end
def ready_to_exit?
occupied_spaces.empty?
end
def walk_direction
if ready_to_exit?
warrior.direction_of_stairs
else
if vicinity[first_unit_direction].empty? && !vicinity[first_unit_direction].stairs?
first_unit_direction
else
empty_in_vicinity.first
end
end
end
def in_walk_loop?
@movements.last == :forward && walk_direction == :backward ||
@movements.last == :backward && walk_direction == :forward ||
@movements.last == :left && walk_direction == :right ||
@movements.last == :right && walk_direction == :left
end
def first_unit_direction
warrior.direction_of(occupied_spaces.first)
end
def occupied_spaces
(ticking_captive_spaces + enemy_spaces + captive_spaces).uniq
end
def captive_spaces
warrior.listen.select(&:captive?)
end
def ticking_spaces
warrior.listen.select(&:ticking?)
end
def ticking_captive_spaces
warrior.listen.select { |space| space.captive? && space.ticking? }
end
def enemy_spaces
warrior.listen.select(&:enemy?)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment