Skip to content

Instantly share code, notes, and snippets.

@lstejskal
Created May 13, 2012 21:15
Show Gist options
  • Save lstejskal/2690239 to your computer and use it in GitHub Desktop.
Save lstejskal/2690239 to your computer and use it in GitHub Desktop.
rubywarrior player script - intermediate level
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