Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 203 lines (175 sloc) 6.012 kB
b15e523 @gabebw Refactor methods into Map class
authored
1 require './map'
4e2b5f1 @gabebw Initial commit: Level 1
authored
2 class Player
1a0bccb @gabebw Cosmetic fixes
authored
3 ATTACK_POWER = 5 # Damage warrior deals per turn
4 MAX_HEALTH = 20 # Maximum health of warrior
5 # We want to have at least this % health
3250d1a @gabebw More abstraction; use location, not direction, to decide what to do
authored
6 MINIMUM_PERCENT_HEALTH = 50
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
7
389ef2d @gabebw Move variable setting to its own method
authored
8 def set_variables!(warrior)
b15e523 @gabebw Refactor methods into Map class
authored
9 @previous_health = current_health
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
10 @previous_direction = nil
11 # If recuperating is true, then rest until at max health before continuing
389ef2d @gabebw Move variable setting to its own method
authored
12 @recuperating = false
b15e523 @gabebw Refactor methods into Map class
authored
13 @map = Map.new(self, warrior)
389ef2d @gabebw Move variable setting to its own method
authored
14
15 @already_set_variables = true
16 end
17
b15e523 @gabebw Refactor methods into Map class
authored
18 attr_accessor :direction
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
19 attr_reader :previous_direction
b15e523 @gabebw Refactor methods into Map class
authored
20
389ef2d @gabebw Move variable setting to its own method
authored
21 def play_turn(warrior)
b15e523 @gabebw Refactor methods into Map class
authored
22 @warrior = warrior # yes, you have to set this each time
1a0bccb @gabebw Cosmetic fixes
authored
23 set_variables!(warrior) unless @already_set_variables
b15e523 @gabebw Refactor methods into Map class
authored
24 @map.update!(warrior)
59723f4 @gabebw Stairs space may not be empty
authored
25
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
26 perform_action!(warrior)
27
3250d1a @gabebw More abstraction; use location, not direction, to decide what to do
authored
28 # Set variables for next turn
b15e523 @gabebw Refactor methods into Map class
authored
29 previous_health = current_health
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
30 @previous_direction = warrior.action[1] # may be nil!
b15e523 @gabebw Refactor methods into Map class
authored
31 @map.previous_location = current_location
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
32 end
33
34 # Performs a bang-action, e.g. walk!
35 def perform_action!(warrior)
3122e4f @gabebw Finished level 4
authored
36 # available methods for a Space (returned by warrior.feel)
ff8ec53 @gabebw More abstraction, and start tracking where enemies are
authored
37 # TESTERS
38 # stairs?
39 # empty?
40 # enemy?
41 # captive?
42 # wall?
43 # ticking? (OMINOUS!)
44 # TYPE GETTERS
45 # unit (e.g. "Thick Sludge", may be nil)
46 # location - An [X-coord, Y-coord] pair
47 # - A coordinate may be < 0, e.g. if you're at [0, 0],
48 # then warrior.feel(:backward).location = [-1, 0]
49 # character (e.g. "S" for a thick sludge, may be nil)
50 # Note that the stairs space is empty (unless a unit is on it), i.e.
51 # space.empty? returns true for the stairs space, so explicitly check
52 # for stairs.
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
53
54 # We can get away with only feeling in one direction, for now.
55 space = warrior.feel(direction)
56
57 # The stairs space may not be empty, e.g. if an enemy or captive is on
58 # it
59 if space.stairs? and space.empty?
60 warrior.walk!(direction)
3250d1a @gabebw More abstraction; use location, not direction, to decide what to do
authored
61 elsif current_location == [1, 0] and warrior.feel(:backward).empty?
62 # Nothing more to do here
63 @direction = :forward
64 warrior.walk!(direction)
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
65 elsif @map.just_killed_an_enemy
66 if @map.is_safe_location?(current_location)
67 puts "current location is safe"
68 if warrior.health < MAX_HEALTH
69 warrior.rest!
70 else
71 # OK, forget about that enemy we just killed.
72 # WE'RE AT MAX HEALTH AND READY TO ROCK!
73 @map.just_killed_an_enemy = false
74 @direction = @map.towards_current_enemy
75 warrior.walk!(direction)
76 end
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
77 else
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
78 puts "current location is NOT safe"
b15e523 @gabebw Refactor methods into Map class
authored
79 reverse_direction!
80 @direction = @map.towards_safe_space
81 warrior.walk!(direction)
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
82 end
83 elsif space.captive?
84 warrior.rescue!(direction)
85 elsif space.enemy?
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
86 @map.register_enemy_at!(space.location, space.character)
87 @map.decrement_enemys_health_at(space.location)
b15e523 @gabebw Refactor methods into Map class
authored
88 warrior.attack!(direction)
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
89 elsif space.empty?
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
90 warrior.walk!(direction)
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
91 elsif space.wall?
92 # Hit a wall, switch direction and retry
c2e0569 @gabebw Re-organize player methods, rename switch_direction! to reverse_direc…
authored
93 reverse_direction!
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
94 perform_action!(warrior)
95 else
3250d1a @gabebw More abstraction; use location, not direction, to decide what to do
authored
96 puts "!!! Weird space: #{space.inspect}"
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
97 warrior.walk!(direction)
98 end
4e2b5f1 @gabebw Initial commit: Level 1
authored
99 end
03daf98 @gabebw Abstraction FTW
authored
100
1a0bccb @gabebw Cosmetic fixes
authored
101 ####################
102 # STATE CHANGERS #
103 ####################
03daf98 @gabebw Abstraction FTW
authored
104
c2e0569 @gabebw Re-organize player methods, rename switch_direction! to reverse_direc…
authored
105 def reverse_direction!
b15e523 @gabebw Refactor methods into Map class
authored
106 @direction = @map.opposite_direction_of(direction)
03daf98 @gabebw Abstraction FTW
authored
107 end
108
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
109 #############
110 # TESTERS #
111 #############
c2e0569 @gabebw Re-organize player methods, rename switch_direction! to reverse_direc…
authored
112
113 # Is this space safe to rest in?
114 # Note that it doesn't take into account whether the warrior is taking
115 # damage.
116 def in_safe_space?
117 not taking_damage? and not next_to_enemy?
03daf98 @gabebw Abstraction FTW
authored
118 end
119
c2e0569 @gabebw Re-organize player methods, rename switch_direction! to reverse_direc…
authored
120 # Should the warrior rest? Note that this doesn't take into account
121 # whether it's safe for the warrior to rest, it just recommends that he
122 # should.
123 def should_rest?
124 # No need to rest when we're about to clear the level
ab0a7dc @gabebw Allow warrior to recuperate and get all health back
authored
125 return false if @warrior.feel(direction).stairs?
126 return false if @warrior.health == MAX_HEALTH
127
128 if @recuperating
129 # Stop recuperating if at max health
130 @recuperating = @warrior.health < MAX_HEALTH
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
131 @recuperating
ab0a7dc @gabebw Allow warrior to recuperate and get all health back
authored
132 else
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
133 low_on_health? or not healthy_enough_to_beat_enemy_at?(@map.location_of_closest_enemy)
ab0a7dc @gabebw Allow warrior to recuperate and get all health back
authored
134 end
c2e0569 @gabebw Re-organize player methods, rename switch_direction! to reverse_direc…
authored
135 end
136
137 # Is an enemy in an adjacent space?
138 def next_to_enemy?
b15e523 @gabebw Refactor methods into Map class
authored
139 Map::DIRECTIONS.any? { |dir| @warrior.feel(dir).enemy? }
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
140 end
141
03daf98 @gabebw Abstraction FTW
authored
142 def taking_damage?
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
143 current_health < @previous_health
144 end
145
146 def taking_damage_from_afar?
c2e0569 @gabebw Re-organize player methods, rename switch_direction! to reverse_direc…
authored
147 taking_damage? and not next_to_enemy?
03daf98 @gabebw Abstraction FTW
authored
148 end
149
3250d1a @gabebw More abstraction; use location, not direction, to decide what to do
authored
150 # Did we just start taking damage this turn?
151 def just_started_taking_damage?
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
152 taking_damage? and @map.is_safe_location?(@map.previous_location)
3250d1a @gabebw More abstraction; use location, not direction, to decide what to do
authored
153 end
154
03daf98 @gabebw Abstraction FTW
authored
155 def low_on_health?
156 percent_health = (current_health.to_f / MAX_HEALTH) * 100
157 percent_health < MINIMUM_PERCENT_HEALTH
158 end
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
159
c7ece16 @gabebw Don't track current enemy, just find closest enemy as needed
authored
160 # Do we have enough health to engage in battle?
161 def healthy_enough_to_beat_enemy_at?(enemy_location)
162 turns = turns_required_to_beat_enemy_at(enemy_location)
163 enemy_info = @map.get_info_about_enemy_at(enemy_location)
164 # Archers attack from a distance of 2 squares, but if we're right next
165 # to them then we need fewer turns
166 turns += [2, @map.get_distance_away(enemy_info[:location])].min if enemy_info[:character] == :a
167 predicted_damage_taken = turns * enemy_info[:damage]
168 predicted_damage_taken < current_health
169 end
170
1a0bccb @gabebw Cosmetic fixes
authored
171 ###############
172 # ACCESSORS #
173 ###############
c2e0569 @gabebw Re-organize player methods, rename switch_direction! to reverse_direc…
authored
174
175 def current_health
176 @warrior.health
177 end
178
b70bcd0 @gabebw Move actions to perform_action!() method, add direction sensing
authored
179 # Get direction warrior is walking in. Defaults to :backward.
180 def direction
181 @direction ||= :backward
182 end
ff8ec53 @gabebw More abstraction, and start tracking where enemies are
authored
183
1a0bccb @gabebw Cosmetic fixes
authored
184 #############
185 # UTILITY #
186 #############
187
1567889 @gabebw Track HP and location of enemies
authored
188 # Pass in an enemy location to determine how many turns it
0a0508f @gabebw Focus on most recent enemy, not closest enemy
authored
189 # will take to kill it once you're next to it.
1567889 @gabebw Track HP and location of enemies
authored
190 def turns_required_to_beat_enemy_at(enemy_location)
b15e523 @gabebw Refactor methods into Map class
authored
191 info = @map.get_info_about_enemy_at(enemy_location)
192 turns = (info[:health].to_f / ATTACK_POWER).ceil
1567889 @gabebw Track HP and location of enemies
authored
193 turns
3250d1a @gabebw More abstraction; use location, not direction, to decide what to do
authored
194 end
195
b15e523 @gabebw Refactor methods into Map class
authored
196 def current_location
197 backward = @warrior.feel(:backward).location
198 x_coord = backward[0] + 1
199 y_coord = backward[1]
200 [x_coord, y_coord]
201 end
4e2b5f1 @gabebw Initial commit: Level 1
authored
202 end
Something went wrong with that request. Please try again.