Last active
December 22, 2015 10:10
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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