#include "TargetEvaluator.h"
#include "UnitModel.h"
#include "UnitManager.h"
#include "Army.h"

TargetEvaluator::TargetEvaluator( UnitModel* o )
{
	owner = o;
	valuePosition = 0;
}

TargetEvaluator::TargetEvaluator( UnitManager* o )
{
	unitManager = o;
}

int TargetEvaluator::calculateValueOf( BWAPI::Unit* u , int penalty)
{
	int targetScore = penalty;
	if(u->isStasised()) {
		return -100000;
	}
	UnitType targetType = u->getType();
	UnitType ownerType = owner->getType();

	if(u->isDetected()) {
		targetScore +=1000;
	} else {
		targetScore -=1000;
	}
	if(targetType.isFlyer()) {
		targetScore += 1000;
		if(targetType == UnitTypes::Terran_Valkyrie) {
			targetScore += 1000;
		}
	}
	// firstly, we care about the owner size - prefer to target things that we're good at killing
	if(ownerType == UnitTypes::Protoss_Dragoon) {
		if(targetType.size() == UnitSizeTypes::Large) {
			targetScore += 100;
		}
		if(targetType.size() == UnitSizeTypes::Medium) {
			targetScore += 75;
		}
		if(targetType.size() == UnitSizeTypes::Small) {
			targetScore += 50;
		}
	}
	

	// next, more importantly somewhat, we care about how much HP and shields they have left

	int targetMaxHP = targetType.maxHitPoints();
	int targetMaxShields = targetType.maxShields();

	float hprp = 100.0/targetMaxHP;
	float sprp = 100.0/targetMaxShields;

	float qhp = u->getHitPoints()*hprp;
	float qsh = u->getShields()*sprp;

	int toAdd = (25*(100-(qhp)));;
	if(u->getType().isBuilding()) {
		if(u->getType() != UnitTypes::Protoss_Photon_Cannon && u->getType() != UnitTypes::Terran_Bunker && u->getType() != UnitTypes::Zerg_Sunken_Colony) {
			toAdd *= 0.3;
		} else {
			if(owner->getUnit()->isInWeaponRange(u)) {
			toAdd *= 1.2;
			}
		}
	}
	targetScore += toAdd;

	if(u->getType().getRace() == BWAPI::Races::Protoss) {
		
		int toAdd = (10*(100-(qsh)));
		if(u->getType().isBuilding()) {
			if(u->getType() != UnitTypes::Protoss_Photon_Cannon && u->getType() != UnitTypes::Terran_Bunker && u->getType() != UnitTypes::Zerg_Sunken_Colony) {
				toAdd *= 0.3;
			} else {
				if(owner->getUnit()->isInWeaponRange(u)) {
					toAdd *= 1.2;
				}
			}
		}
		targetScore += toAdd;
	}
	

	// but also, we should prefer things that are close to us, somewhat
	float dist = owner->getPosition().getDistance(u->getPosition());
	if(u->getType() == UnitTypes::Terran_Firebat || u->getType() == UnitTypes::Zerg_Zergling || u->getType() == UnitTypes::Protoss_Zealot) {
		if(dist < 64) {
			targetScore+=500;
		} else {
			targetScore-=500;
		}
	}
	int modifier = 2;
	if(owner->getType() == UnitTypes::Protoss_Zealot || owner->getType() == UnitTypes::Protoss_Dark_Templar) {
		modifier = 4;
		targetScore += modifier*(1000-dist);
	}
	
	
	// next, we care about whether we can hit something
	if(owner->getUnit()->isInWeaponRange(u)) {
		targetScore += 1000;
	} else {
		targetScore -= 1000;
	}



	// here we have some special cases
	if(u->getType() == UnitTypes::Terran_Medic) {
		// everyone hates medics!
		targetScore += 550;
	}
	if(u->getType() == UnitTypes::Protoss_High_Templar || u->getType() == UnitTypes::Protoss_Dark_Templar) {
		// everyone hates medics!
		targetScore += 2550;
	}
	if(u->getType() == UnitTypes::Terran_Marine || u->getType() == UnitTypes::Terran_Medic) {
		if(u->isBeingHealed()) {
			targetScore-=500;
		}

		std::set<Unit*> supporters = Broodwar->getUnitsInRadius(u->getPosition(), 96);
		for(std::set<Unit*>::const_iterator i = supporters.begin(); i != supporters.end(); i++) {
			Unit* cur = *i;
			if(cur == u || cur->getPlayer() == Broodwar->self()) {
				continue;
			}

				if(cur->getType() == UnitTypes::Terran_Medic) {
					targetScore-=100;
				} else {
					targetScore+=100;
				}

		}
	}

	if(u->getType().isDetector()) {
		targetScore+=200;
		if(owner->getUnit()->isCloaked()) {
			targetScore+=500;
		}
	}
	if(targetType == UnitTypes::Terran_Siege_Tank_Siege_Mode) {
		targetScore+=850;
		if(owner->getType() == UnitTypes::Protoss_Zealot) {
			targetScore+=400;
		}
	}

	if(u->getType() == UnitTypes::Protoss_Pylon) {
		//NOTE: this is an approximation of the real ellipse calculation
		std::set<BWAPI::Unit*> supporters = Broodwar->getUnitsInRadius(u->getPosition(), UnitTypes::Protoss_Pylon.sightRange());
		for (std::set<Unit*>::iterator i = supporters.begin(); i != supporters.end(); ++i)
		{
			BWAPI::Unit* cur = *i;
			int tarYpos = cur->getPosition().y();
			int pylYpos = u->getPosition().y();
			float yRange = UnitTypes::Protoss_Pylon.sightRange()*0.6;
			if(abs(tarYpos-pylYpos) >= yRange) {
				continue;
			}
			if(cur->getType() == UnitTypes::Protoss_Photon_Cannon) {
				
				// if the pylon is closer to me than the turrett
				// and i'm out of the turret's range
				// i should attack the pylon, not the turrett

				int distanceToPylon = owner->getPosition().getDistance(u->getPosition());
				int distanceToThisTurrett = owner->getPosition().getDistance(cur->getPosition());

				if(distanceToPylon < distanceToThisTurrett) {
					if(distanceToThisTurrett >= UnitTypes::Protoss_Photon_Cannon.groundWeapon().maxRange()*1.2) {
						targetScore+=500;
						continue;
					}
				}
				targetScore-=2000;

			}
		}

	}



	if(u->getType().isBuilding()) {
		if(u->getType() == UnitTypes::Terran_Bunker || u->getType() == UnitTypes::Zerg_Sunken_Colony || u->getType() == UnitTypes::Protoss_Photon_Cannon) {
			if(owner->getUnit()->getPosition().getDistance(u->getPosition()) <= owner->getType().sightRange()) {
				targetScore+=10000;
			}
	
		} else {
			targetScore-=5000;
			if(owner->isBeingTargetted()) {
				targetScore-=2000;
			}
		}
	} else {
		targetScore+=2000;
		if(u->getType().isWorker()) {
			if(u->isVisible()) {
				if(u->isConstructing() || u->isRepairing()) {
					targetScore+=1000;
				}
			}
		}
	}

	if(u->getTarget() != NULL) {
		if(u->getTarget()->getType().isWorker()) {
			targetScore+=1000;
		}
		if(u->getTarget()->getType() == UnitTypes::Protoss_High_Templar) {
			targetScore+=1000;
		}
		if(u->getTarget()->getType() == UnitTypes::Protoss_Shuttle) {
			targetScore+=1000;
		}
		if(u->getTarget()->getType() == UnitTypes::Protoss_Reaver) {
			targetScore+=1000;
		}
		if(u->getTarget()->getType() == UnitTypes::Protoss_Arbiter) {
			targetScore+=5000;
		}
	}



	return targetScore;
}

int TargetEvaluator::calculateValueOf( Unit* u )
{
	return calculateValueOf( u, 0 );
}

int TargetEvaluator::calculateValueOf( UnitModel* u)
{
		return calculateValueOf( u, 0 );
}


int TargetEvaluator::calculateValueOf( UnitModel* u, int penalty )
{

	if(u->isStasised()) {
		return -100000;
	}
	int targetScore = penalty;
	UnitType targetType = u->getType();
	UnitType ownerType = owner->getType();

	if(u->getUnit()->isDetected()) {
		targetScore +=1000;
	} else {
		targetScore -=1000;
	}

	// firstly, we care about the owner size - prefer to target things that we're good at killing
	if(ownerType == UnitTypes::Protoss_Dragoon) {
		if(targetType.size() == UnitSizeTypes::Large) {
			targetScore += 100;
		}
		if(targetType.size() == UnitSizeTypes::Medium) {
			targetScore += 75;
		}
		if(targetType.size() == UnitSizeTypes::Small) {
			targetScore += 50;
		}
	}

	// next, more importantly somewhat, we care about how much HP and shields they have left
	int toAdd = (25*(100-u->getQualitativeHP()));;
	if(u->getType().isBuilding()) {
		if(u->getType() != UnitTypes::Protoss_Photon_Cannon && u->getType() != UnitTypes::Terran_Bunker && u->getType() != UnitTypes::Zerg_Sunken_Colony) {
			toAdd *= 0.3;
		} else {
			if(owner->getUnit()->isInWeaponRange(u->getUnit())) {
				toAdd *= 1.2;
			}
		}
	}
	targetScore += toAdd;

	if(u->getType().getRace() == BWAPI::Races::Protoss) {

		int toAdd = (25*(100-(u->getQualitativeShields())));
		if(u->getType().isBuilding()) {
			if(u->getType() != UnitTypes::Protoss_Photon_Cannon && u->getType() != UnitTypes::Terran_Bunker && u->getType() != UnitTypes::Zerg_Sunken_Colony) {
				toAdd *= 0.3;
			} else {
				if(owner->getUnit()->isInWeaponRange(u->getUnit())) {
					toAdd *= 1.2;
				}
			}
		}
		if(u->getShields() == 0) {
			targetScore+=1000;
		}
		targetScore += toAdd;
	
	}


	// but also, we should prefer things that are close to us, somewhat
	float dist = owner->getPosition().getDistance(u->getPosition());
	int modifier = 1;
	if(owner->getType() == UnitTypes::Protoss_Zealot || owner->getType() == UnitTypes::Protoss_Dark_Templar || owner->getType() == UnitTypes::Protoss_Archon) {
		modifier = 3;
		targetScore += (1000)-dist;
		if(u->getType() == UnitTypes::Protoss_Dragoon) {
			targetScore += 500;
		}
	}
	// next, we care about whether we can hit something
	if(owner->getType() == UnitTypes::Protoss_Zealot || owner->getType() == UnitTypes::Protoss_Dark_Templar|| owner->getType() == UnitTypes::Protoss_Archon) {
		if(owner->getPosition().getDistance(u->getPosition()) <= 64) {
			targetScore += modifier*1500;
			if(owner->getUnit()->isInWeaponRange(u->getUnit())) {
				targetScore += 5000;
			}
		} else {
			targetScore -= (modifier*1500);
		}
	} else {
		if(owner->getPosition().getDistance(u->getPosition()) <= Broodwar->self()->groundWeaponMaxRange(ownerType)) {
			targetScore += (modifier*1500);
		} else {
			targetScore -= modifier*1500;
		}
	}


	if(owner->getType() == UnitTypes::Protoss_Photon_Cannon) {
		if(u->getType() == UnitTypes::Terran_Firebat || u->getType() == UnitTypes::Protoss_Zealot || u->getType() == UnitTypes::Zerg_Zergling) {
			if(dist > 64) {
				targetScore-=1000;
			} else {
				targetScore+=1000;
			}
		}
	}

	if(u->getType() == UnitTypes::Protoss_High_Templar || u->getType() == UnitTypes::Protoss_Dark_Templar) {
		targetScore += 2550;
	}

	if(u->getUnit()->getTarget() != NULL) {
	if(u->getUnit()->getTarget()->getType() == UnitTypes::Protoss_High_Templar) {
		targetScore+=3000;
	}
	if(u->getUnit()->getTarget()->getType() == UnitTypes::Protoss_Shuttle) {
		targetScore+=2000;
	}
	if(u->getUnit()->getTarget()->getType() == UnitTypes::Protoss_Reaver) {
		targetScore+=4000;
	}
	if(u->getUnit()->getTarget()->getType() == UnitTypes::Protoss_Arbiter) {
		targetScore+=4000;
	}
	}	
	if(owner->getType() == UnitTypes::Protoss_Reaver) {
		if(u->getType() == UnitTypes::Protoss_Photon_Cannon || u->getType() == UnitTypes::Terran_Bunker || u->getType() == UnitTypes::Zerg_Sunken_Colony) {
			if(u->getUnit()->isInWeaponRange(owner->getUnit())) {
				targetScore+=10000;
			} else {
				targetScore -= 2000;
			}
			
		}
	}
	if(u->getType() == UnitTypes::Protoss_Pylon) {
		//NOTE: this is an approximation of the real ellipse calculation
		std::set<BWAPI::Unit*> supporters = Broodwar->getUnitsInRadius(u->getPosition(), UnitTypes::Protoss_Pylon.sightRange());
		for (std::set<Unit*>::iterator i = supporters.begin(); i != supporters.end(); ++i)
		{
			BWAPI::Unit* cur = *i;
			int tarYpos = cur->getPosition().y();
			int pylYpos = u->getPosition().y();
			float yRange = UnitTypes::Protoss_Pylon.sightRange()*0.6;
			if(abs(tarYpos-pylYpos) >= yRange) {
				continue;
			}
			if(cur->getType() == UnitTypes::Protoss_Photon_Cannon) {

				// if the pylon is closer to me than the turrett
				// and i'm out of the turret's range
				// i should attack the pylon, not the turrett

				int distanceToPylon = owner->getPosition().getDistance(u->getPosition());
				int distanceToThisTurrett = owner->getPosition().getDistance(cur->getPosition());

				if(distanceToPylon < distanceToThisTurrett) {
					if(distanceToThisTurrett >= UnitTypes::Protoss_Photon_Cannon.groundWeapon().maxRange()*1.2) {
						targetScore+=500;
						continue;
					}
				}
				targetScore-=2000;
			}
		}
	}
	if(u->getType() == UnitTypes::Terran_Marine || u->getType() == UnitTypes::Terran_Medic || u->getType() == UnitTypes::Terran_Firebat) {
		if(u->getUnit()->isBeingHealed()) {
			targetScore-=1000;
		}
	}

	if(owner->getType() == UnitTypes::Protoss_Archon) {

		if(u->getType() == UnitTypes::Zerg_Mutalisk) {
			targetScore += 500;
		}

		std::set<BWAPI::Unit*> supporters = Broodwar->getUnitsInRadius(u->getPosition(), 64);
		for (std::set<Unit*>::iterator i = supporters.begin(); i != supporters.end(); ++i)
		{
			if((*i) == u->getUnit()) {
				continue;
			}
			targetScore+=100;
		}
	}


	if(u->getType().isBuilding()) {
		if(u->getType() == UnitTypes::Terran_Bunker || u->getType() == UnitTypes::Zerg_Sunken_Colony || u->getType() == UnitTypes::Protoss_Photon_Cannon) {
			if(owner->getUnit()->getPosition().getDistance(u->getPosition()) <= owner->getType().sightRange()) {
				targetScore+=10000;
			}
		} else {
			targetScore -= 5000;
			if(owner->isBeingTargetted() || owner->getUnit()->isUnderAttack()) {
				targetScore-=5000;
			}
		}
	} else {
		targetScore+=5000;
		if(u->getType().isWorker()) {
			if(u->getUnit()->isVisible()) {
				if(u->getUnit()->isConstructing() || u->getUnit()->isRepairing()) {
					targetScore+=1000;
				}
			}
		}
	}


	if(owner->getUnit()->hasPath(u->getPosition())) {
		targetScore+= 50;
	}
	if(owner->getUnit()->isCloaked() && u->getType().isDetector()) {
		targetScore+=500;
	}
	if(targetType == UnitTypes::Terran_Siege_Tank_Siege_Mode) {
		targetScore+=850;
		if(owner->getType() == UnitTypes::Protoss_Zealot || owner->getType() == UnitTypes::Protoss_Dark_Templar || owner->getType() == UnitTypes::Protoss_Archon) {
			targetScore+=700;
		}
	}



	return targetScore;
}

float TargetEvaluator::calculateValueOf( BWTA::Region* r )
{

	/*
		The score of a region is the value of the region minus the danger of attacking it.
		A high score is best - this means that the region is valuable and undefended.
	*/

	// so, first of all, lets see what we believe to be in this region
	std::vector<UnitModel*> unitsInRegion = unitManager->getAllEnemyUnitsInRegion(r);

	// but also, what ISN'T in this region? so, what COULD potentially come to help out our enemy?
	std::vector<UnitModel*> unitsNotInRegion = unitManager->getAllEnemyUnitsNotInRegion(r);
	float regionScore = 1.0;
	float baseValue = 1.0;
	float defenseValue = 1.0;
	float defenderDPF = 1.0;
	float numUnitDefenders = 1.0;
	// first lets calculate the score of the potential defenders we know about
	for (std::vector<UnitModel*>::iterator i = unitsNotInRegion.begin(); i != unitsNotInRegion.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->getType().isBuilding() || cur->getType().isWorker()) {
			// do nothing - we don't care about these things here!
		} else {
			if(!cur->getType().isSpellcaster()) {
			float damage = cur->getType().groundWeapon().damageAmount();
			float attackSpeed = cur->getType().groundWeapon().damageCooldown();
			defenderDPF += (damage/attackSpeed);
			defenseValue += (cur->getType().mineralPrice()+cur->getType().gasPrice());
			numUnitDefenders++;
			}
		}
	}
	
	// so now we need to figure out how to interpret this information
	// how important is it that a unit might be a potential defender?
	// one idea might be to scale the score based on how far away from the region's centre
	// the unit is. then we scale the overall score by some degree to figure out how much we
	// actually care about this information. so this slider can be changed.
	// for now we just do the scaling
	
	// so this is the importance of the effective damage-per-frame of everything outside of the region
	float DPF_IMPORTANCE = 0.25;

	// this is the importance of the general value of the defenders
	float DEFENSE_IMPORTANCE = 0.35;

	float externalForceDPF = (defenderDPF)*DPF_IMPORTANCE;
	defenseValue = defenseValue*DEFENSE_IMPORTANCE;


	// ok so reset this and lets calculate the actual believed regional score
	numUnitDefenders = 1;
	defenderDPF = 1.0;

	// now lets calculate the actual regional score
	for (std::vector<UnitModel*>::iterator i = unitsInRegion.begin(); i != unitsInRegion.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->getType().isBuilding() || cur->getType().isWorker()) {
			baseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();

			if(cur->getType() == UnitTypes::Protoss_Photon_Cannon || cur->getType() == UnitTypes::Zerg_Sunken_Colony) {
				float damage = cur->getType().groundWeapon().damageAmount();
				float attackSpeed = cur->getType().groundWeapon().damageCooldown();
				if(attackSpeed == 0.0) {
					attackSpeed = 1.0;
				}
				defenderDPF += (damage/attackSpeed);
				defenseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();
				numUnitDefenders++;
			}
		} else {
			if(!cur->getType().isSpellcaster()) {
			float damage = cur->getType().groundWeapon().damageAmount();
			float attackSpeed = cur->getType().groundWeapon().damageCooldown();
			if(attackSpeed == 0.0) {
				attackSpeed = 1.0;
			}
			defenderDPF += (damage/attackSpeed);
			defenseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();
			numUnitDefenders++;
			}
		}
	}
	// this is the believed DPF of all the units we know about
	//forceDPF = externalForceDPF+(forceDPF);
	//////Broodwar->drawTextScreen32,112,"defenders dpf: %f", defenderDPF);

	// so what do we do with this now?
	// well we could use it as a multiplier for the defense value
	// what else?
	regionScore = (defenseValue);
	
	// we also want to consider a region less desirable to attack if it features small choke points
	for (std::set<Chokepoint*>::const_iterator i = r->getChokepoints().begin(); i != r->getChokepoints().end(); ++i)
	{
		Chokepoint* cp = *i;
		if(cp->getWidth() < 100) {
			regionScore += 250;
		} else {
			regionScore -= 200;
		}
	}

	if(valuePosition < 10) {
		recentValues[valuePosition] = regionScore;
		valuePosition++;
	} else {
		valuePosition = 0;
	}

	if(Broodwar->getFrameCount() > 25) {
		float sum = 1.0;
		for(int i = 0; i < 10; i++) {
			if(recentValues[i] != 0) {
				sum += recentValues[i];
			}
		}
		sum = sum/10.0;
		
		return sum;
	} else {
		return 0.1;
	}
}

float TargetEvaluator::calculateValueOf( Army* a, BWTA::Region* r )
{
		/*
		The score of a region is the value of the region minus the danger of attacking it.
		A high score is best - this means that the region is valuable and undefended.
	*/

	// so, first of all, lets see what we believe to be in this region
	std::vector<UnitModel*> unitsInArmy = a->getMembers();
	if(unitsInArmy.empty()) {
		return 1.0;
	}
	// but also, what ISN'T in this region? so, what COULD potentially come to help out our enemy?
	float forceValue = 1.0;
	int numAttackers = 1;
	float forceDPF = 1.0;
	// first lets calculate the score of the potential defenders we know about
	for (std::vector<UnitModel*>::iterator i = unitsInArmy.begin(); i != unitsInArmy.end(); ++i)
	{
			UnitModel* cur = *i;
			float damage = cur->getType().groundWeapon().damageAmount();
			float attackSpeed = cur->getType().groundWeapon().damageCooldown();
			forceDPF += (damage/attackSpeed);
			forceValue += (cur->getType().mineralPrice()+cur->getType().gasPrice());

			// increase the perceived strength of our army if we have cloaking technology and
			// our opponent won't be able to detect us
			if(cur->getType() == UnitTypes::Protoss_Arbiter) {
			int numMissileTowers = unitManager->getAllEnemyUnitsOfTypeInRegion(UnitTypes::Terran_Missile_Turret, r).size();
			int numSporeColonies = unitManager->getAllEnemyUnitsOfTypeInRegion(UnitTypes::Zerg_Spore_Colony, r).size();
			int numPhotonCannons = unitManager->getAllEnemyUnitsOfTypeInRegion(UnitTypes::Protoss_Photon_Cannon, r).size();
			int numScienceVessels = unitManager->getAllEnemyUnitsOfTypeInRegion(UnitTypes::Terran_Science_Vessel, r).size();
			int numObservers = unitManager->getAllEnemyUnitsOfTypeInRegion(UnitTypes::Protoss_Observer, r).size();
			int numComsatStations = unitManager->getAllEnemyUnitsOfTypeInRegion(UnitTypes::Terran_Comsat_Station, r).size();

			int numDetectors = numMissileTowers + numSporeColonies + numPhotonCannons + numScienceVessels + numObservers;

			// so, lets score each detector at 100, 
			forceValue += (1000-(numDetectors*100));
			}
				numAttackers++;
	}

	forceDPF = (forceDPF);
//	////Broodwar->drawTextScreen32,96,"army dpf: %f", forceDPF);

	return forceValue;
}

float TargetEvaluator::calculateEnemyDPFValueOf( BWTA::Region* r )
{

	// so, first of all, lets see what we believe to be in this region
	std::vector<UnitModel*> unitsInRegion = unitManager->getAllEnemyUnitsInRegion(r);

	// but also, what ISN'T in this region? so, what COULD potentially come to help out our enemy?
	std::vector<UnitModel*> unitsNotInRegion = unitManager->getAllEnemyUnitsNotInRegion(r);
	float regionScore = 1.0;
	float baseValue = 1.0;
	float defenseValue = 0.0;
	float defenderDPF = 0.0;
	float numUnitDefenders = 1.0;
	// first lets calculate the score of the potential defenders we know about
	for (std::vector<UnitModel*>::iterator i = unitsNotInRegion.begin(); i != unitsNotInRegion.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->getType().isBuilding() || cur->getType().isWorker()) {
			// do nothing - we don't care about these things here!
		} else {
			float damage = cur->getType().groundWeapon().damageAmount();
	
			float attackSpeed = cur->getType().groundWeapon().damageCooldown();
			defenderDPF += (damage);
			defenseValue += (cur->getType().mineralPrice()+cur->getType().gasPrice());
			numUnitDefenders++;
		}
	}
	
	// so now we need to figure out how to interpret this information
	// how important is it that a unit might be a potential defender?
	// one idea might be to scale the score based on how far away from the region's centre
	// the unit is. then we scale the overall score by some degree to figure out how much we
	// actually care about this information. so this slider can be changed.
	// for now we just do the scaling
	
	// so this is the importance of the effective damage-per-frame of everything outside of the region
	float DPF_IMPORTANCE = 0.25;

	// this is the importance of the general value of the defenders
	float DEFENSE_IMPORTANCE = 0.35;

	float externalForceDPF = (defenderDPF)*DPF_IMPORTANCE;
	defenseValue = defenseValue*DEFENSE_IMPORTANCE;


	// ok so reset this and lets calculate the actual believed regional score
	defenderDPF = externalForceDPF;

	// now lets calculate the actual regional score
	for (std::vector<UnitModel*>::iterator i = unitsInRegion.begin(); i != unitsInRegion.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		if(cur->getType().isBuilding() || cur->getType().isWorker()) {
			baseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();

			if(cur->getType() == UnitTypes::Terran_Bunker || cur->getType() == UnitTypes::Protoss_Photon_Cannon || cur->getType() == UnitTypes::Zerg_Sunken_Colony) {

				float damage = cur->getType().groundWeapon().damageAmount();
					if(cur->getType() == UnitTypes::Terran_Bunker) {
						damage += ((UnitTypes::Terran_Marine.groundWeapon().damageAmount()*4)*1.2);
					}
				//float attackSpeed = cur->getType().groundWeapon().damageCooldown();
				float attackSpeed = 1.0;
				defenderDPF += (damage);
				defenseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();
				numUnitDefenders++;
			}
		} else {
			float damage = cur->getType().groundWeapon().damageAmount();
			//float attackSpeed = cur->getType().groundWeapon().damageCooldown();
			defenderDPF += (damage);
			defenseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();
			numUnitDefenders++;
		}
	}
	// this is the believed DPF of all the units we know about
	//forceDPF = externalForceDPF+(forceDPF);
	return defenderDPF/numUnitDefenders;
}

float TargetEvaluator::calculateDPFValueOf( Army* a )
{
		/*
		The score of a region is the value of the region minus the danger of attacking it.
		A high score is best - this means that the region is valuable and undefended.
	*/

	// so, first of all, lets see what we believe to be in this region
	std::vector<UnitModel*> unitsInArmy = a->getMembers();
	if(unitsInArmy.empty()) {
		return 1.0;
	}
	// but also, what ISN'T in this region? so, what COULD potentially come to help out our enemy?
	float forceValue = 0.0;
	int numAttackers = 0;
	float forceDPF = 0.0;
	// first lets calculate the score of the potential defenders we know about
	for (std::vector<UnitModel*>::iterator i = unitsInArmy.begin(); i != unitsInArmy.end(); ++i)
	{
			UnitModel* cur = *i;
			if(!cur->isAlive()) {
				continue;
			}
			float damage = cur->getType().groundWeapon().damageAmount();
			if(cur->getType() == UnitTypes::Protoss_Zealot) {
				damage *=2;
			}
			forceDPF += (damage);

	}

	return forceDPF;
}

float TargetEvaluator::calculateEnemyArmyValueOf( BWTA::Region* r )
{

	// so, first of all, lets see what we believe to be in this region
	std::vector<UnitModel*> unitsInRegion = unitManager->getAllEnemyUnitsInRegion(r);

	// but also, what ISN'T in this region? so, what COULD potentially come to help out our enemy?
	std::vector<UnitModel*> unitsNotInRegion = unitManager->getAllEnemyUnitsNotInRegion(r);
	float regionScore = 1.0;
	float baseValue = 1.0;
	float defenseValue = 0.0;
	float defenderCost = 0.0;
	float numUnitDefenders = 1.0;
	// first lets calculate the score of the potential defenders we know about
	for (std::vector<UnitModel*>::iterator i = unitsNotInRegion.begin(); i != unitsNotInRegion.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->getType().isBuilding() || cur->getType().isWorker()) {
			// do nothing - we don't care about these things here!
		} else {
			//float damage = cur->getType().groundWeapon().damageAmount();

			//float attackSpeed = cur->getType().groundWeapon().damageCooldown();
			defenderCost += cur->getType().mineralPrice();
			//defenseValue += (cur->getType().mineralPrice()+cur->getType().gasPrice());
			numUnitDefenders++;
		}
	}

	// so now we need to figure out how to interpret this information
	// how important is it that a unit might be a potential defender?
	// one idea might be to scale the score based on how far away from the region's centre
	// the unit is. then we scale the overall score by some degree to figure out how much we
	// actually care about this information. so this slider can be changed.
	// for now we just do the scaling

	// so this is the importance of the effective damage-per-frame of everything outside of the region
	float EXTERN_COST_IMPORTANCE = 0.25;

	// this is the importance of the general value of the defenders
	float DEFENSE_IMPORTANCE = 0.35;

	float externalForceDPF = (defenderCost)*EXTERN_COST_IMPORTANCE;


	// ok so reset this and lets calculate the actual believed regional score
	defenderCost = externalForceDPF;

	// now lets calculate the actual regional score
	for (std::vector<UnitModel*>::iterator i = unitsInRegion.begin(); i != unitsInRegion.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		if(cur->getType().isBuilding() || cur->getType().isWorker()) {
			baseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();

			if(cur->getType() == UnitTypes::Terran_Bunker || cur->getType() == UnitTypes::Protoss_Photon_Cannon || cur->getType() == UnitTypes::Zerg_Sunken_Colony) {

				float cost = cur->getType().mineralPrice();
				if(cur->getType() == UnitTypes::Terran_Bunker) {
					cost += ((UnitTypes::Terran_Marine.mineralPrice()*4)*1.2);
				}
				//float attackSpeed = cur->getType().groundWeapon().damageCooldown();
				//float attackSpeed = 1.0;
				defenderCost += cost;
				//defenseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();
				numUnitDefenders++;
			}
		} else {
			//float damage = cur->getType().groundWeapon().damageAmount();
			//float attackSpeed = cur->getType().groundWeapon().damageCooldown();
			defenderCost += UnitTypes::Terran_Marine.mineralPrice();
			//defenseValue += cur->getType().mineralPrice()+cur->getType().gasPrice();
			numUnitDefenders++;
		}
	}
	// this is the believed DPF of all the units we know about
	//forceDPF = externalForceDPF+(forceDPF);
	return defenderCost;
}

float TargetEvaluator::calculateArmyValueOf( Army* a )
{
		/*
		The score of a region is the value of the region minus the danger of attacking it.
		A high score is best - this means that the region is valuable and undefended.
	*/

	// so, first of all, lets see what we believe to be in this region
	std::vector<UnitModel*> unitsInArmy = a->getMembers();
	if(unitsInArmy.empty()) {
		return 1.0;
	}
	// but also, what ISN'T in this region? so, what COULD potentially come to help out our enemy?
	float forceValue = 1.0;

	// first, upgrades
	int galevel = Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Protoss_Ground_Armor);
	switch(galevel) {
	case 0:

		break;
	case 1:
		forceValue+=200;
		break;
	case 2:
		forceValue+=350;
		break;
	case 3:
		forceValue+=500;
		break;
	}

	int shieldlevel = Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Protoss_Plasma_Shields);
	switch(shieldlevel) {
	case 0:

		break;
	case 1:
		forceValue+=200;
		break;
	case 2:
		forceValue+=300;
		break;
	case 3:
		forceValue+=400;
		break;
	}

	int weaponlevel = Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Protoss_Ground_Weapons);
	switch(weaponlevel) {
	case 0:

		break;
	case 1:
		forceValue+=200;
		break;
	case 2:
		forceValue+=400;
		break;
	case 3:
		forceValue+=600;
		break;
	}


	int numAttackers = 1;
	float forceDPF = 1.0;
	// first lets calculate the score of the potential defenders we know about
	for (std::vector<UnitModel*>::iterator i = unitsInArmy.begin(); i != unitsInArmy.end(); ++i)
	{
			UnitModel* cur = *i;
			if(!cur->isAlive()) {
				continue;
			}
			if(cur->getType().isSpellcaster()) {
				forceDPF += 112;
			} else {
			float damage = cur->getType().mineralPrice();
			forceDPF += (damage);
			}
	}

	return forceDPF;
}