Skip to content
Jarod42 edited this page Sep 27, 2010 · 2 revisions
require 'set'

class Player

	def initialize()
		@archerInLine = false
		@knowEnemy = Set.new
		@seenStairs = false
	end

	def play_turn(warrior)
		updateInfoBeginTurn(warrior)
		action(warrior)
	end

	def getNextUnit(warrior, dir = :forward)
		warrior.look(dir).each do |space|
			return space.unit if !space.empty?
		end
		return nil
	end

	def unitType(unit)
		return nil if unit == nil
		return unit.character
	end

	def rangeunit?(warrior, dir = :forward)
		unitType = unitType(getNextUnit(warrior, dir))
		["a", "w"].each do |c| return true if c == unitType end
		return false
	end
	
	def updateInfoBeginTurn(warrior)
		warrior.look(:backward).each do |space|
			@knowEnemy.add(space.unit) if space.enemy? != nil
			@seenStairs = true if space.stairs?
		end
		warrior.look(:forward).each do |space|
			@knowEnemy.add(space.unit) if space.enemy? != nil
			@seenStairs = true if space.stairs?
		end
		@archerInLine = (rangeunit?(warrior) or rangeunit?(warrior, :backward))
	end

	def action(warrior)
		if rescueAround(warrior) or finish(warrior) or attack(warrior) or restore(warrior)
			return
		else
			move(warrior)
		end
	end

	def neededMinHealth(warrior)
		wantedHeath = 1
		wantedHeath += 6 if !@seenStairs
		@knowEnemy.each do |enemy|
			case unitType(enemy)
			when "S" then wantedHeath += 0
			when "s" then wantedHeath += 4
			when "a" then wantedHeath += 6
			else wantedHeath += 0
			end
		end
		return wantedHeath
	end
	
	def restore(warrior)

		if warrior.health < neededMinHealth(warrior)
			warrior.rest!
			return true
		end
		return false
	end

	def attack(warrior)
		nextUnit = getNextUnit(warrior)

		case unitType(nextUnit)
		when "w" then warrior.shoot!
		when "a" then
			if warrior.feel.enemy?
				warrior.attack!
			elsif nextUnit.health <= 3
				warrior.shoot!
			elsif warrior.look[1].enemy? or warrior.health - 3 > neededMinHealth(warrior)
				warrior.walk!
			else
				warrior.shoot!
			end
		when "s" then # smaa(-3) or ssssm
			if warrior.feel.enemy?
				warrior.attack!
			elsif nextUnit.health > 9
				warrior.shoot!
			else
				warrior.walk!
			end
		when "S" then
			if warrior.feel.enemy?
				warrior.attack!
			elsif (@archerInLine or nextUnit.health <= 5 or warrior.look[1].empty? \
				or (warrior.health - 6 > neededMinHealth(warrior) and nextUnit.health <= 15))
				warrior.walk!
			else
				puts ("neededHealth = #{neededMinHealth(warrior)}")
				warrior.shoot!
			end
		else return false
		end
		@knowEnemy.subtract([nextUnit]) # it may die
		return true
	end

	def finish(warrior, dir = :forward)
		space = warrior.look(dir).each do |space|
			break if (space.empty? and space.stairs?)
			return false if !space.empty?
		end
		warrior.walk!
		return true
	end

	def move(warrior)
		if (warrior.feel.wall? \
			or (warrior.feel.empty? and warrior.look[1].wall?))
			warrior.pivot!
		else
			warrior.walk!
		end
	end

	def rescueAround(warrior)
		for dir in [:backward, :forward]
			if (warrior.feel(dir).captive?)
				warrior.rescue!(dir)
				return true
			end
			if (warrior.feel(dir).empty?)
				for i in (1 .. 2)
					if (warrior.look(dir)[i].captive?)
						warrior.walk!(dir)
						return true
					elsif (!warrior.look(dir)[i].empty?)
						break
					end
				end
			end
		end
		return false
	end
end