Created
May 13, 2012 21:15
-
-
Save lstejskal/2690239 to your computer and use it in GitHub Desktop.
rubywarrior player script - intermediate level
This file contains 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 | |
DIRECTIONS = [ :forward, :backward, :left, :right ] | |
# this logs your path through the level | |
# PS: we might need this in order to return to safety when injured | |
PATH = [] | |
MIN_HEALTH = 18 | |
CRITICAL_HEALTH = 10 | |
attr_reader :health, :direction, :area_explored | |
# TODO score path: don't recover health if there are no enemies left | |
def play_turn(w) | |
# set initial states | |
@health ||= w.health | |
@direction ||= :forward | |
# or: ascend the stairs to next level? | |
@area_explored ||= false | |
display_health_info(w) | |
puts "ENEMIES: #{enemy_directions(w).join(', ')}" | |
# puts "CAPTIVES: #{captive_directions(w).join(', ')}" | |
=begin | |
if w.feel(@direction).wall? or (w.feel(@direction).stairs? and not area_explored?) | |
# PS: so we don't ascend the stairs before we've explored the whole area | |
@area_explored = true | |
w.pivot! | |
=end | |
# prioritize rescuing captives if they are rigged with bomb | |
if captives_left?(w) && (captives_ticking?(w) or not enemies_nearby?(w)) | |
rescue_or_advance!(w) | |
elsif enemies_nearby?(w) && (enemies_nearby_nr(w) > 1) | |
w.bind!(enemy_directions(w).first) | |
elsif injured?(w) and not taking_damage?(w) | |
w.rest! | |
# if you're critically injured, attempt to retreat into safety, where you can rest | |
=begin | |
elsif critically_injured?(w) | |
if can_retreat?(w) | |
w.walk!(opposite_direction(@direction)) | |
# here goes nothing | |
else | |
attack_or_advance!(w) | |
end | |
=end | |
else | |
attack_or_advance!(w) | |
end | |
# update health for next turn | |
@health = w.health | |
end | |
def area_explored? | |
@area_explored | |
end | |
# Returns units left on the level | |
def units_left(w) | |
w.listen | |
end | |
def units_left?(w) | |
not units_left(w).empty? | |
end | |
# if there more than one enemy nearby | |
# bind them and try to escape | |
def attack_or_advance!(w) | |
if enemies_nearby?(w) | |
w.attack!(enemy_directions(w).first) | |
elsif units_left?(w) | |
walk_to_unit(w, units_left(w).first) | |
else | |
PATH << w.direction_of_stairs | |
w.walk!(w.direction_of_stairs) | |
end | |
end | |
def rescue_or_advance!(w) | |
if captives_nearby?(w) | |
w.rescue! captive_direction(w) | |
else | |
w.walk! captive_direction(w) | |
end | |
end | |
=begin | |
def enemies_ahead?(w) | |
w.look(@direction).each do |space| | |
if space.empty? | |
next | |
elsif space.enemy? | |
return true | |
else # captive, wall... | |
return false | |
end | |
end | |
false # nothing ahead but empty spaces | |
end | |
=end | |
# walk to unit, avoid stairs | |
def walk_to_unit(w, unit) | |
direction = w.direction_of(unit) | |
if w.feel(direction).stairs? | |
DIRECTIONS.each do |d| | |
if w.feel(d).empty? and not w.feel(d).stairs? | |
direction = d | |
break | |
end | |
end | |
end | |
w.walk!(direction) | |
end | |
# Return array of directions pointing to nearby enemies | |
# | |
# TODO make _directions and _nearby methods more generic | |
def enemy_directions(w) | |
DIRECTIONS.select { |d| w.feel(d).enemy? } | |
end | |
def enemies_nearby?(w) | |
not enemy_directions(w).empty? | |
end | |
def enemies_nearby_nr(w) | |
enemy_directions(w).size | |
end | |
def captives(w, nearby_only = false) | |
if nearby_only | |
DIRECTIONS.select { |d| w.feel(d).captive? } | |
else | |
w.listen.map { |u| u if u.captive? }.compact | |
end | |
end | |
def captive_direction(w) | |
if captives_nearby?(w) | |
return captives(w, true).first | |
end | |
cs = captives(w) | |
cs.each { |c| return w.direction_of(c) if c.ticking? } | |
w.direction_of(cs.first) | |
end | |
def captives_nearby?(w) | |
not captives(w, true).empty? | |
end | |
def captives_left?(w) | |
not captives(w).empty? | |
end | |
def captives_ticking?(w) | |
not captives(w).map { |c| c.ticking? }.compact.empty? | |
end | |
# PS: score patch: don't waste time recovering health if there are no enemies left | |
# FIXME detect just enemies, not captives | |
def injured?(w, min_health = MIN_HEALTH) | |
(w.health < min_health) and units_left?(w) | |
end | |
def critically_injured?(w, min_health = CRITICAL_HEALTH) | |
injured?(w, min_health) | |
end | |
# Compares health between turns | |
# | |
def taking_damage?(w) | |
w.health < @health | |
end | |
def can_retreat?(w) | |
not w.feel( opposite_direction(@direction) ).wall? | |
end | |
# Returns opposite direction to current @direction | |
# | |
def opposite_direction(direction = :forward) | |
case direction | |
when :forward then :backward | |
when :backward then :forward | |
else raise "Invalid direction: #{direction}" | |
end | |
end | |
def display_health_info(w) | |
health_diff = w.health - @health | |
puts "HEALTH: %s %s" % [ @health, ("(#{health_diff})" unless health_diff == 0) ] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment