Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactor methods into Map class

  • Loading branch information...
commit b15e523fd6c4e70a9547b326a2b27a6354662ee1 1 parent 389ef2d
@gabebw authored
Showing with 217 additions and 173 deletions.
  1. +172 −0 map.rb
  2. +45 −173 player.rb
View
172 map.rb
@@ -0,0 +1,172 @@
+class Map
+ ENEMY = {:S => {:health => 24, :damage => 3},
+ :a => {:health => 7, :damage => 3}}
+ DIRECTIONS = [:forward, :backward]
+
+ def initialize(player, warrior)
+ @player = player
+ @warrior = warrior
+ @current_enemy = nil
+ @safe_locations = []
+ @previous_location = nil
+ @current_current_enemy_location = nil
+ @enemy_location_to_info = {}
+
+ # A matrix of X columns by Y rows
+ @map = {}
+ end
+ attr_accessor :current_current_enemy_location, :previous_location
+
+ def update!(warrior)
+ @warrior = warrior
+ register_current_enemy!
+ current_x, current_y = current_location_of_warrior
+ @map[current_x] ||= {}
+ @map[current_x][current_y] = '@'.to_sym
+ @map[current_x][current_y+1] = pretty_space(@warrior.feel(:forward))
+ @map[current_x][current_y-1] = pretty_space(@warrior.feel(:backward))
+
+ if @player.just_started_taking_damage?
+ # Find a spot that's 2 away and is unknown
+ end
+ end
+
+ # What about walls?
+ def pretty_space(space)
+ space.empty? ? nil : space.unit.character.to_sym
+ end
+
+ # Get number of squares between warrior and given location
+ def get_distance_away(location)
+ target_x, target_y = location
+ current_x, current_y = currnet_location
+ distance = (((target_x - current_x).to_f ** 2) + ((target_y - current_y).to_f ** 2)) ** 0.5
+ distance = distance.ceil
+ distance - 1
+ end
+
+ def opposite_direction_of(dir)
+ case dir
+ when :forward then :backward
+ when :backward then :forward
+ end
+ end
+
+ # Returns a direction that will bring the warrior closer to the given location.
+ def towards(location)
+ target_x, target_y = location
+ current_x, current_y = current_location_of_warrior
+ current_x > target_x ? :backward : :forward
+ end
+
+ # Returns a direction that will bring the warrior farther away from the given location.
+ def away_from(location)
+ opposite_direction_of(towards(location))
+ end
+
+ # Mark the current location as safe
+ def mark_safe_location!(location)
+ @safe_locations << location unless @safe_locations.include?(location)
+ end
+
+ # Is a given location safe?
+ def is_safe_location?(location)
+ @safe_locations.include?(location)
+ end
+
+ def current_location_of_warrior
+ backward = @warrior.feel(:backward).location
+ x_coord = backward[0] + 1
+ y_coord = backward[1]
+ [x_coord, y_coord]
+ end
+
+ # Return a direction towards closest safe space
+ def towards_safe_space
+ puts "Moving toward safe space"
+ if @player.taking_damage_from_afar? and @player.should_rest?
+ # Move away from threat
+ direction = away_from(location_of_current_enemy)
+ else
+ direction = opposite_direction_of(@player.direction)
+ end
+ direction
+ end
+
+ def towards_current_enemy
+ towards(location_of_current_enemy)
+ end
+
+ # ENEMY TRACKING
+ def current_enemy
+ new_enemy = nil
+ if @player.taking_damage_from_afar?
+ new_enemy = :a
+ elsif @player.next_to_enemy?
+ dir = DIRECTIONS.detect { |d| @warrior.feel(d).enemy? }
+ new_enemy = @warrior.feel(dir).character
+ end
+ # Update only if we have a new enemy
+ if new_enemy
+ @current_enemy = new_enemy
+ end
+ @current_enemy = @current_enemy.to_sym unless @current_enemy.nil?
+ @current_enemy
+ end
+
+ # Returns a Hash of info about most recent enemy. Hash is empty if
+ # no enemies have been encountered yet.
+ def get_current_enemy_info
+ return {} if current_enemy.nil?
+ info = {}
+ info[:location] = location_of_current_enemy
+ info[:direction] = towards(info[:location])
+ info[:character] = current_enemy
+ info.merge!(ENEMY[info[:character]])
+
+ info
+ end
+
+ # Register the most recent enemy. We need to keep track of their health!
+ def register_current_enemy!
+ return if current_enemy.nil?
+ info = get_current_enemy_info
+ @enemy_location_to_info[info[:location]] ||= info
+ end
+
+ # Returns location of closest enemy. May be nil.
+ def location_of_current_enemy
+ if @player.next_to_enemy?
+ dir = DIRECTIONS.detect{|d| @warrior.feel(d).enemy? }
+ @current_enemy_location = @warrior.feel(dir).location
+ elsif current_enemy == :a and @player.just_started_taking_damage?
+ x,y = current_location_of_warrior
+ # Archer is shooting at us. They have a range of 2 squares.
+ # i.e. |@ a| is sufficient for them to hit the warrior.
+ @current_enemy_location = [x+3, y]
+ end
+ @current_enemy_location
+ end
+
+ # Removes most recent enemy from @enemy_location_to_info hash
+ def unregister_current_enemy!
+ info = get_current_enemy_info
+ @enemy_location_to_info.delete(info[:location])
+ @just_killed_an_enemy = true
+ end
+
+ # Decrement most recent enemy's health, unregistering them if they died.
+ def decrement_current_enemys_health_by(amount)
+ info = get_current_enemy_info
+ @enemy_location_to_info[info[:location]][:health] -= amount
+ if @enemy_location_to_info[info[:location]][:health] <= 0
+ # Enemy died
+ unregister_current_enemy!
+ end
+ end
+
+ # Get info about a specific enemy
+ def get_info_about_enemy_at(location)
+ @enemy_location_to_info[location]
+ end
+end
View
218 player.rb
@@ -1,39 +1,36 @@
+require './map'
class Player
- MAX_HEALTH = 20
- # How much damage the warrior does per turn
- DAMAGE_DEALT = 5
# When we have less than this % health, rest (unless we're not in a safe
# space)
+
+ ATTACK_POWER = 5
+ MAX_HEALTH = 20
MINIMUM_PERCENT_HEALTH = 50
- ENEMY = {:S => {:health => 24, :damage => 3},
- :a => {:health => 7, :damage => 3}}
- DIRECTIONS = [:forward, :backward]
def set_variables!(warrior)
@warrior = warrior
- @previous_health = current_health # set first
- @previous_space = current_location
+ @previous_health = current_health
# If true, then rest until at max health before continuing
@recuperating = false
- @safe_locations = []
- @most_recent_enemy = nil
- @enemy_location = nil
- # Map a specific enemy to its info
- @enemy_location_to_info = {}
+ @just_killed_an_enemy = false
+ @map = Map.new(self, warrior)
@already_set_variables = true
end
+ attr_accessor :direction
+
def play_turn(warrior)
# warrior.action returns [:latest_action, :direction_it_was_performed]
- set_variables! unless @already_set_variables
- register_most_recent_enemy
+ set_variables!(warrior) unless @already_set_variables
+ @warrior = warrior # yes, you have to set this each time
+ @map.update!(warrior)
perform_action!(warrior)
# Set variables for next turn
- @previous_health = current_health
- @previous_location = current_location
+ previous_health = current_health
+ @map.previous_location = current_location
end
# Performs a bang-action, e.g. walk!
@@ -68,28 +65,34 @@ def perform_action!(warrior)
@direction = :forward
warrior.walk!(direction)
elsif should_rest?
+ #@just_killed_an_enemy = false
if in_safe_space?
# Regain some health
- mark_safe_location!
+ @map.mark_safe_location!(current_location)
warrior.rest!
else
puts "Should rest, but not in safe space. Moving towards it."
- move_toward_safe_space!
@recuperating = true
+ reverse_direction!
+ @direction = @map.towards_safe_space
+ warrior.walk!(direction)
end
elsif space.captive?
warrior.rescue!(direction)
elsif space.enemy?
- most_recent_enemy = space.character
- attack_enemy!(direction)
+ #attack_enemy!
+ @map.register_current_enemy!
+ @map.decrement_current_enemys_health_by(ATTACK_POWER)
+ warrior.attack!(direction)
elsif space.empty?
# May have just moved away from an enemy, so check if we should
# re-engage.
- if location_of_most_recent_enemy.nil?
+ if @map.location_of_current_enemy.nil?
# No enemies, blithely continue
warrior.walk!(direction)
else
- move_toward_most_recent_enemy!
+ @direction = @map.towards_current_enemy
+ warrior.walk!(direction)
end
elsif space.wall?
# Hit a wall, switch direction and retry
@@ -104,37 +107,15 @@ def perform_action!(warrior)
# STATE CHANGERS
def reverse_direction!
- @direction = opposite_direction_of(direction)
- end
-
- # Moves warrior toward a safe space
- def move_toward_safe_space!
- puts "Moving toward safe space"
- if taking_damage_from_afar? and should_rest?
- # Move away from threat
- @direction = away_from(location_of_most_recent_enemy)
- else
- reverse_direction!
- end
- @direction = away_from(location_of_most_recent_enemy)
- @warrior.walk!(direction)
- end
-
- def move_toward_most_recent_enemy!
- @direction = towards(location_of_most_recent_enemy)
- @warrior.walk!(direction)
- end
-
- # Mark the current location as safe
- def mark_safe_location!
- @safe_locations << current_location unless @safe_locations.include?(current_location)
+ @direction = @map.opposite_direction_of(direction)
end
# A wrapper around warrior.attack!(direction) so we can track an enemy's
# health.
- def attack_enemy!(direction)
+ def attack_enemy!
location = @warrior.feel(direction).location
- decrement_most_recent_enemys_health_by(DAMAGE_DEALT)
+ @map.register_current_enemy!
+ @map.decrement_current_enemys_health_by(ATTACK_POWER)
@warrior.attack!(direction)
end
@@ -147,11 +128,6 @@ def in_safe_space?
not taking_damage? and not next_to_enemy?
end
- # Is a given location safe?
- def is_safe_location?(location)
- @safe_locations and @safe_locations.include?(location)
- end
-
# Should the warrior rest? Note that this doesn't take into account
# whether it's safe for the warrior to rest, it just recommends that he
# should.
@@ -164,8 +140,8 @@ def should_rest?
# Stop recuperating if at max health
@recuperating = @warrior.health < MAX_HEALTH
return @recuperating
- elsif most_recent_enemy
- not healthy_enough_to_beat_enemy_at?(get_most_recent_enemy_info[:location])
+ elsif @map.current_enemy
+ not healthy_enough_to_beat_enemy_at?(@map.get_current_enemy_info[:location])
else
low_on_health?
end
@@ -173,7 +149,7 @@ def should_rest?
# Is an enemy in an adjacent space?
def next_to_enemy?
- DIRECTIONS.any? { |dir| @warrior.feel(dir).enemy? }
+ Map::DIRECTIONS.any? { |dir| @warrior.feel(dir).enemy? }
end
def taking_damage?
@@ -186,7 +162,7 @@ def taking_damage_from_afar?
# Did we just start taking damage this turn?
def just_started_taking_damage?
- taking_damage? and is_safe_location?(@previous_location)
+ taking_damage? and @map.is_safe_location?(@previous_location)
end
def low_on_health?
@@ -205,135 +181,31 @@ def direction
@direction ||= :backward
end
- def current_location
- backward = @warrior.feel(:backward).location
- x_coord = backward[0] + 1
- y_coord = backward[1]
- [x_coord, y_coord]
- end
-
- def location_of_most_recent_enemy=(location)
- @enemy_location = location
- end
-
- def most_recent_enemy
- new_enemy = nil
- if taking_damage_from_afar?
- new_enemy = :a
- elsif next_to_enemy?
- dir = DIRECTIONS.detect { |d| @warrior.feel(d).enemy? }
- new_enemy = @warrior.feel(dir).character
- end
- # Update only if we have a new enemy
- if new_enemy
- @most_recent_enemy = new_enemy
- end
- @most_recent_enemy = @most_recent_enemy.to_sym unless @most_recent_enemy.nil?
- @most_recent_enemy
- end
-
# UTILITY
- def opposite_direction_of(dir)
- case dir
- when :forward then :backward
- when :backward then :forward
- end
- end
-
# Pass in an enemy location to determine how many turns it
# will take to kill it once you're next to it.
def turns_required_to_beat_enemy_at(enemy_location)
- info = get_info_about_enemy_at(enemy_location)
- turns = (info[:health].to_f / DAMAGE_DEALT).ceil
+ info = @map.get_info_about_enemy_at(enemy_location)
+ turns = (info[:health].to_f / ATTACK_POWER).ceil
turns
end
+ def current_location
+ backward = @warrior.feel(:backward).location
+ x_coord = backward[0] + 1
+ y_coord = backward[1]
+ [x_coord, y_coord]
+ end
+
# Do we have enough health to engage in battle?
def healthy_enough_to_beat_enemy_at?(enemy_location)
turns = turns_required_to_beat_enemy_at(enemy_location)
- enemy_info = get_info_about_enemy_at(enemy_location)
+ enemy_info = @map.get_info_about_enemy_at(enemy_location)
# Archers attack from a distance of 2 squares, but if we're right next
# to them then we need fewer turns
- turns += [2, get_distance_away(enemy_info[:location])].min if enemy_info[:character] == :a
+ turns += [2, @map.get_distance_away(enemy_info[:location])].min if enemy_info[:character] == :a
puts "turns reqd: #{turns}"
predicted_damage_taken = turns * enemy_info[:damage]
predicted_damage_taken < current_health
end
-
- # Returns location of closest enemy. May be nil.
- def location_of_most_recent_enemy
- if next_to_enemy?
- dir = DIRECTIONS.detect{|d| @warrior.feel(d).enemy? }
- @enemy_location = @warrior.feel(dir).location
- elsif most_recent_enemy == :a and just_started_taking_damage?
- x,y = current_location
- # Archer is shooting at us. They have a range of 2 squares.
- # i.e. |@ a| is sufficient for them to hit the warrior.
- @enemy_location = [x+3, y]
- end
- @enemy_location
- end
-
- # Returns a direction that will bring the warrior closer to the given location.
- def towards(location)
- target_x, target_y = location
- current_x, current_y = current_location
- current_x > target_x ? :backward : :forward
- end
-
- # Returns a direction that will bring the warrior farther away from the given location.
- def away_from(location)
- opposite_direction_of(towards(location))
- end
-
- # Register the most recent enemy. We need to keep track of their health!
- def register_most_recent_enemy
- return if most_recent_enemy.nil?
- info = get_most_recent_enemy_info
- @enemy_location_to_info[info[:location]] ||= info
- end
-
- # Removes most recent enemy from @enemy_location_to_info hash
- def unregister_most_recent_enemy!
- info = get_most_recent_enemy_info
- @enemy_location_to_info.delete(info[:location])
- end
-
- # Returns a Hash of info about most recent enemy. Hash is empty if
- # no enemies have been encountered yet.
- def get_most_recent_enemy_info
- return {} if most_recent_enemy.nil?
- info = {}
- info[:location] = location_of_most_recent_enemy
- info[:direction] = towards(info[:location])
- info[:character] = most_recent_enemy
- info.merge!(ENEMY[info[:character]])
-
- info
- end
-
- # Decrement most recent enemy's health, unregistering them if they died.
- def decrement_most_recent_enemys_health_by(amount)
- register_most_recent_enemy
- info = get_most_recent_enemy_info
- @enemy_location_to_info[info[:location]][:health] -= amount
- if @enemy_location_to_info[info[:location]][:health] <= 0
- # Enemy died
- unregister_most_recent_enemy!
- end
- end
-
- # Get info about a specific enemy
- def get_info_about_enemy_at(location)
- @enemy_location_to_info[location]
- end
-
- # Get number of squares between warrior and given location
- def get_distance_away(location)
- target_x, target_y = location
- current_x, current_y = current_location
- distance = (((target_x - current_x).to_f ** 2) + ((target_y - current_y).to_f ** 2)) ** 0.5
- distance = distance.ceil
- distance - 1
- end
end
Please sign in to comment.
Something went wrong with that request. Please try again.