![alt text](https://2.bp.blogspot.com/-DNNiOXduuvQ/Vh-FR-qbKXI/AAAAAAAAEOA/HT0IzJ36zW4/s1600/voz.jpg)

Create a class called `Warrior` which calculates and keeps track of their level and skills, and ranks them as the warrior they've proven to be.

Business Rules:

- A warrior starts at level 1 and can progress all the way to 100.
- A warrior starts at rank `"Pushover"` and can progress all the way to `"Greatest"`.
- The only acceptable range of rank values is `"Pushover", "Novice", "Fighter", "Warrior", "Veteran", "Sage", "Elite", "Conqueror", "Champion", "Master", "Greatest"`.
- Warriors will compete in battles. Battles will always accept an enemy level to match against your own.
- With each battle successfully finished, your warrior's experience is updated based on the enemy's level.
- The experience earned from the battle is relative to what the warrior's current level is compared to the level of the enemy.
- A warrior's experience starts from 100. Each time the warrior's experience increases by another 100, the warrior's level rises to the next level.
- A warrior's experience is cumulative, and does not reset with each rise of level. The only exception is when the warrior reaches level 100, with which the experience stops at 10000
- At every 10 levels, your warrior will reach a new rank tier. (ex. levels 1-9 falls within `"Pushover"` tier, levels 80-89 fall within `"Champion"` tier, etc.)
- A warrior cannot progress beyond level 100 and rank `"Greatest"`.

Battle Progress Rules & Calculations:

- If an enemy level does not fall in the range of 1 to 100, the battle cannot happen and should return `"Invalid level"`.
- Completing a battle against an enemy with the same level as your warrior will be worth 10 experience points.
- Completing a battle against an enemy who is one level lower than your warrior will be worth 5 experience points.
- Completing a battle against an enemy who is two levels lower or more than your warrior will give 0 experience points.
- Completing a battle against an enemy who is one level higher or more than your warrior will accelarate your experience gaining. The greater the difference between levels, the more experinece your warrior will gain. The formula is `20 * diff * diff` where `diff` equals the difference in levels between the enemy and your warrior.
- However, if your warrior is at least one rank lower than your enemy, and at least 5 levels lower, your warrior cannot fight against an enemy that strong and must instead return `"You've been defeated"`.
- Every successful battle will also return one of three responses: `"Easy fight", "A good fight", "An intense fight"`. Return `"Easy fight"` if your warrior is 2 or more levels higher than your enemy's level. Return `"A good fight"` if your warrior is either 1 level higher or equal to your enemy's level. Return `"An intense fight"` if your warrior's level is lower than the enemy's level.

Logic Examples:

- If a warrior level 1 fights an enemy level 1, they will receive 10 experience points.
- If a warrior level 1 fights an enemy level 3, they will receive 80 experience points.
- If a warrior level 5 fights an enemy level 4, they will receive 5 experience points.
- If a warrior level 3 fights an enemy level 9, they will receive 720 experience points, resulting in the warrior rising up by at least 7 levels.
- If a warrior level 8 fights an enemy level 13, they will receive 0 experience points and return `"You've been defeated"`. (Remember, difference in rank & enemy level being 5 levels higher or more must be established for this.)
- If a warrior level 6 fights an enemy level 2, they will receive 0 experience points.

 Training Rules & Calculations:
- In addition to earning experience point from battles, warriors can also gain experience points from training.
- Training will accept an array of three elements (except in java where you'll get 3 separated arguments): the description, the experience points your warrior earns, and the minimum level requirement.
- If the warrior's level meets the minimum level requirement, the warrior will receive the experience points from it and store the description of the training. It should end up returning that description as well.
- If the warrior's level does not meet the minimum level requirement, the warrior doesn not receive the experience points and description and instead returns `"Not strong enough"`, without any archiving of the result.

 Code Examples:
```python
bruce_lee = Warrior()
bruce_lee.level         # => 1
bruce_lee.experience    # => 100
bruce_lee.rank          # => "Pushover"
bruce_lee.achievements  # => []
bruce_lee.training(["Defeated Chuck Norris", 9000, 1]) # => "Defeated Chuck Norris"
bruce_lee.experience    # => 9100
bruce_lee.level         # => 91
bruce_lee.rank          # => "Master"
bruce_lee.battle(90)    # => "A good fight"
bruce_lee.experience    # => 9105
bruce_lee.achievements  # => ["Defeated Chuck Norris"]
```

Difficulty: MEDIUM_HARD

Starter code:
def __init__(self):
	

Solutions:
class Warrior:

	def __init__(self):
		self._experience = 100
		self.rs = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']
		self.achievements = []

	def training(self, train):
		if train[2] > self.level:
			return 'Not strong enough'
		self._experience += train[1]
		self.achievements.append(train[0])
		return train[0]

	def battle(self, lvl):
		diff = lvl - self.level
		if 0 >= lvl or lvl > 100:
			return 'Invalid level'
		if diff >= 5 and lvl // 10 > self.level // 10:
			return "You've been defeated"
		if diff > 0:
			self._experience += 20 * diff * diff
			return 'An intense fight'
		if diff > -2:
			self._experience += 5 if diff == -1 else 10
			return 'A good fight'
		return 'Easy fight'

	@property
	def level(self):
		return self.experience // 100

	@property
	def rank(self):
		return self.rs[self.experience // 1000]

	@property
	def experience(self):
		return min(10000, self._experience)


class Warrior(object):
	MAX_LVL = 100
	MAX_XPS = 10000
	LVL_XP_RATIO = 100
	RANKS = ['', 'Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']
	DEF_RET_ACHIEV = 'Not strong enough'
	INVALID_BATTLE = 'Invalid level'
	FAILED_BATTLE = "You've been defeated"
	STR_BATTLE = ['A good fight', 'An intense fight', 'Easy fight']

	def __init__(self):
		(self.xps, self.achiev) = (self.LVL_XP_RATIO, [])

	@property
	def level(self):
		return self.xps // self.LVL_XP_RATIO

	@property
	def rank(self):
		return self.RANKS[self.getRank(self.xps)]

	@property
	def experience(self):
		return self.xps

	@property
	def achievements(self):
		return self.achiev[:]

	def getRank(self, xps):
		return xps // 1000 + 1

	def updateXps(self, xp):
		self.xps = min(self.xps + xp, self.MAX_XPS)

	def battle(self, oLvl):
		diff = oLvl - self.level
		if not 1 <= oLvl <= self.MAX_LVL:
			return self.INVALID_BATTLE
		if diff >= 5 and self.getRank(self.xps) < self.getRank(oLvl * self.LVL_XP_RATIO):
			return self.FAILED_BATTLE
		xpGain = 20 * diff ** 2 if diff > 0 else max(0, 10 + 5 * diff)
		iRet = (diff > 0) - (diff < 0) if diff != -1 else 0
		self.updateXps(xpGain)
		return self.STR_BATTLE[iRet]

	def training(self, event):
		(ach, xpGain, minLvl) = event
		if self.level < minLvl:
			return self.DEF_RET_ACHIEV
		self.updateXps(xpGain)
		self.achiev.append(ach)
		return ach


class Warrior:

	def __init__(self):
		self.level = 1
		self.experience = 100
		self.rank = 'Pushover'
		self.achievements = []
		self.max_level = 100
		self.available_ranks = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']

	def battle(self, enemy_level):
		if enemy_level < 1 or enemy_level > 100:
			return 'Invalid level'
		if enemy_level <= self.level:
			diff = self.level - enemy_level
			self._get_experience(10 // (diff + 1))
			if diff > 1:
				return 'Easy fight'
			else:
				return 'A good fight'
		else:
			diff = enemy_level - self.level
			if diff >= 5 and enemy_level // 10 > self.level // 10:
				return "You've been defeated"
			else:
				self._get_experience(20 * diff * diff)
				return 'An intense fight'

	def training(self, achievement):
		description = achievement[0]
		experience = achievement[1]
		min_level = achievement[2]
		if self.level >= min_level:
			self.achievements.append(description)
			self._get_experience(experience)
			return description
		else:
			return 'Not strong enough'

	def _get_experience(self, experience):
		if experience >= 5:
			self.experience += experience
			self.level = self.experience // 100
			if self.level >= self.max_level:
				self.level = self.max_level
				self.experience = self.max_level * 100
			self.rank = self.available_ranks[self.experience // 1000]


class Warrior:

	def __init__(self):
		self.ranks = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']
		self._experience = 100
		self.achievements = []

	@property
	def experience(self):
		return self._experience

	@experience.setter
	def experience(self, value):
		self._experience = value
		if self._experience >= 10000:
			self._experience = 10000

	@property
	def rank_tier(self):
		return self.level // 10

	@property
	def rank(self):
		return self.ranks[self.rank_tier]

	@property
	def level(self):
		return self.experience // 100

	def battle(self, enemy_level):
		if enemy_level > 100 or enemy_level < 1:
			return 'Invalid level'
		elif enemy_level // 10 > self.rank_tier and enemy_level >= self.level + 5:
			return "You've been defeated"
		elif enemy_level == self.level:
			self.experience += 10
			return 'A good fight'
		elif enemy_level == self.level - 1:
			self.experience += 5
			return 'A good fight'
		elif enemy_level <= self.level - 2:
			self.experience += 0
			return 'Easy fight'
		elif enemy_level > self.level:
			self.experience += 20 * (enemy_level - self.level) ** 2
			return 'An intense fight'

	def training(self, fight):
		(description, exp_earned, level_requirement) = fight
		if self.level >= level_requirement:
			self.experience += exp_earned
			self.achievements.append(description)
			return description
		else:
			return 'Not strong enough'


class Warrior:

	def __init__(self):
		self.xp = 100
		self.ranks = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']
		self.achievements = []

	@property
	def experience(self):
		return min(self.xp, 10000)

	@property
	def level(self):
		return self.experience // 100

	@property
	def rank(self):
		return self.ranks[self.level // 10]

	def battle(self, level):
		diff = level - self.level
		if not 0 < level <= 100:
			return 'Invalid level'
		elif diff > 4 and self.ranks.index(self.ranks[level // 10]) > self.ranks.index(self.rank):
			return "You've been defeated"
		elif diff > 0:
			self.xp += 20 * diff * diff
			return 'An intense fight'
		elif not diff:
			self.xp += 10
			return 'A good fight'
		elif diff == -1:
			self.xp += 5
			return 'A good fight'
		return 'Easy fight'

	def training(self, arr):
		if self.level >= arr[2]:
			self.xp += arr[1]
			self.achievements.append(arr[0])
			return arr[0]
		return 'Not strong enough'


class Warrior:
	rank_list = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']

	def __init__(self):
		self.level = 1
		self.experience = 100
		self.achievements = []

	@property
	def rank(self):
		return self.rank_list[self.level // 10]

	def get_experience(self, point):
		exp = self.experience + point
		self.experience = (exp, 10000)[exp >= 10000]
		self.level = self.experience // 100

	def training(self, lst):
		if lst[-1] <= self.level:
			achiev = lst[0]
			self.achievements.append(achiev)
			self.get_experience(lst[1])
			return achiev
		return 'Not strong enough'

	def battle(self, enemy_level):
		if 0 < enemy_level < 101:
			return self.get_result(enemy_level)
		return 'Invalid level'

	def get_result(self, enemy_level):
		diff = enemy_level - self.level
		if diff >= 5 and enemy_level // 10 - self.level // 10 > 0:
			return "You've been defeated"
		fight_result = {(1, 0, 1): 'Easy fight', (1, 1, 0): 'A good fight'}
		point = {-2: 0, -1: 5, 0: 10}.get((diff, -2)[diff < -1], 20 * (diff * diff))
		self.get_experience(point)
		return fight_result.get((point <= 10, point > 0, point == 0), 'An intense fight')


class Warrior:

	def __init__(self):
		self.rankList = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']
		self.level = 1
		self.experience = 100
		self.rank = 'Pushover'
		self.achievements = []
		pass

	def gainXP(self, xp):
		if self.experience + xp <= 10000:
			self.experience += xp
			self.level = int(self.experience / 100)
			self.rank = self.rankList[int(self.level / 10)]
		else:
			self.experience = 10000
			self.level = 100
			self.rank = self.rankList[int(self.level / 10)]

	def battle(self, enemyLevel):
		print(str(self.level) + ' VS ' + str(enemyLevel))
		if enemyLevel < 1 or enemyLevel > 100:
			return 'Invalid level'
		if enemyLevel == self.level:
			self.gainXP(10)
			return 'A good fight'
		elif enemyLevel == self.level - 1:
			self.gainXP(5)
			return 'A good fight'
		elif int(enemyLevel / 10) > int(self.level / 10) and enemyLevel - 4 > self.level:
			return "You've been defeated"
		elif enemyLevel > self.level:
			self.gainXP(20 * (enemyLevel - self.level) * (enemyLevel - self.level))
			return 'An intense fight'
		else:
			return 'Easy fight'

	def training(self, array):
		if self.level >= array[2]:
			self.gainXP(array[1])
			self.achievements.append(array[0])
			return array[0]
		else:
			return 'Not strong enough'


class Warrior:

	def __init__(self):
		self.level = 1
		self.maxLevel = 100
		self.experience = 100
		self.ranks = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']
		self.rank = 'Pushover'
		self.achievements = []

	def calculateRank(self, enemyLevel=None):
		if not enemyLevel:
			try:
				self.rank = self.ranks[int(self.level / 10)]
				return self.rank
			except Exception as e:
				self.rank = 'Greatest'
				return 'Greatest'
		else:
			return self.ranks[int(enemyLevel / 10)]

	def calculateLevel(self):
		self.level = int(self.experience / 100)
		self.calculateRank()

	def increaseExperience(self, amount):
		if self.experience + amount > 10000:
			self.experience = 10000
		else:
			self.experience += amount
		self.calculateLevel()

	def battle(self, enemyLevel):
		if enemyLevel > 100 or enemyLevel < 1:
			return 'Invalid level'
		levelDiff = self.level - enemyLevel
		if enemyLevel == self.level:
			self.increaseExperience(10)
			return 'A good fight'
		if levelDiff == 1:
			self.increaseExperience(5)
			return 'A good fight'
		if levelDiff >= 2:
			return 'Easy fight'
		if levelDiff < 0:
			enemyRankIndex = self.ranks.index(self.calculateRank(enemyLevel=enemyLevel))
			warriorRankIndex = self.ranks.index(self.calculateRank())
			higherLevel = levelDiff * -1
			if enemyRankIndex - warriorRankIndex >= 1 and higherLevel >= 5:
				return "You've been defeated"
			experienceGained = 20 * higherLevel * higherLevel
			self.increaseExperience(experienceGained)
			return 'An intense fight'

	def training(self, args):
		note = args[0]
		experienceEarned = args[1]
		minLevel = args[2]
		if self.level >= minLevel:
			self.increaseExperience(experienceEarned)
			self.achievements.append(note)
			return note
		else:
			return 'Not strong enough'


class Warrior:
	ranks = ['Pushover', 'Novice', 'Fighter', 'Warrior', 'Veteran', 'Sage', 'Elite', 'Conqueror', 'Champion', 'Master', 'Greatest']

	def __init__(self):
		self.experience = 100
		self.achievements = []

	@property
	def level(self):
		return self.experience // 100

	@property
	def rank(self):
		return self.ranks[self.level // 10]

	def __incr_exp(self, exp):
		self.experience = min(10000, self.experience + exp)

	def training(self, L):
		(desc, exp, lvl) = L
		if self.level < lvl:
			return 'Not strong enough'
		self.__incr_exp(exp)
		self.achievements.append(desc)
		return desc

	def battle(self, lvl):
		if not 1 <= lvl <= 100:
			return 'Invalid level'
		diff = lvl - self.level
		if diff < -1:
			return 'Easy fight'
		if diff < 1:
			self.__incr_exp(5 * (diff + 2))
			return 'A good fight'
		if diff < 5 or self.level // 10 == lvl // 10:
			self.__incr_exp(20 * diff * diff)
			return 'An intense fight'
		return "You've been defeated"