def attack_or_switch(self): if self.user.last_used_move[1].startswith("switch"): return "ATTACK" if self.user.active.hp == 0: return "SWITCH" waitingPkm = False; for pkm in self.user.reserve: if not pkm.fainted: waitingPkm = True break if not waitingPkm: return "ATTACK" battle_copy = deepcopy(self) battle_copy.opponent.lock_moves() try: pokemon_sets = get_pokemon_sets(battle_copy.opponent.active.name) except KeyError: logger.warning("No set for {}".format(battle_copy.opponent.active.name)) return opponent_possible_moves = sorted(pokemon_sets[MOVES_STRING], key=lambda x: x[1], reverse=True) worstCaseDmgTaken = 0 for move in opponent_possible_moves: if move[0].startswith("hiddenpower"): continue selfCopy = deepcopy(self) state = selfCopy.create_state() damageEstimate = _calculate_damage(state.opponent.active,state.self.active,move[0]) if damageEstimate != None: if damageEstimate[0] > worstCaseDmgTaken: worstCaseDmgTaken = damageEstimate[0] bestCaseDmgGiven = 0 for move in self.user.active.moves: if move.name.startswith("hiddenpower"): continue selfCopy = deepcopy(self) state = selfCopy.create_state() attacking_move = deepcopy(all_move_json.get(move.name, None)) attacking_type = attacking_move.get(constants.CATEGORY) if attacking_type == constants.STATUS: score = 40 else: score = _calculate_damage(state.self.active,state.opponent.active,move.name)[0] if score != None: if score > bestCaseDmgGiven: bestCaseDmgGiven = score if bestCaseDmgGiven >= worstCaseDmgTaken: return "ATTACK" else: return "SWITCH"
def find_best_switch(self): #build tree switchRoot = Tree() # find worst case move used on each possible switched in Pokemon battle_copy = deepcopy(self) battle_copy.opponent.lock_moves() try: pokemon_sets = get_pokemon_sets(battle_copy.opponent.active.name) except KeyError: logger.warning("No set for {}".format(battle_copy.opponent.active.name)) return opponent_possible_moves = sorted(pokemon_sets[MOVES_STRING], key=lambda x: x[1], reverse=True) for reservePkm in self.user.reserve: if reservePkm.hp == 0: continue worstCase = 0 for move in opponent_possible_moves: if move[0].startswith("hiddenpower"): continue selfCopy = deepcopy(self) selfCopy.user.active = reservePkm state = selfCopy.create_state() damageEstimate = _calculate_damage(state.opponent.active,state.self.active,move[0]) if damageEstimate != None: if damageEstimate[0] > worstCase: worstCase = damageEstimate[0] switchNode = Tree() switchNode.data = "switch " + reservePkm.name switchNode.maximinScore = worstCase*-0.667 switchRoot.children.append(switchNode) # traverse Tree with root switchRoot return treeTraversalDFS(switchRoot)
def find_best_attack(self): #build tree attackRoot = Tree() # find worst case move used on each possible switched in Pokemon battle_copy = deepcopy(self) battle_copy.opponent.lock_moves() if self.user.active.hp == 0: return attackRoot for move in self.user.active.moves: if move.name.startswith("hiddenpower"): continue if move.current_pp == 0: continue selfCopy = deepcopy(self) state = selfCopy.create_state() attacking_move = deepcopy(all_move_json.get(move.name, None)) attacking_type = attacking_move.get(constants.CATEGORY) if attacking_type == constants.STATUS: score = 25 else: score = _calculate_damage(state.self.active,state.opponent.active,move.name)[0] switchNode = Tree() switchNode.data = move.name switchNode.maximinScore = score attackRoot.children.append(switchNode) return treeTraversalDFS(attackRoot)
def test_4x_resistance_calculates_properly(self): move = 'gigadrain' dmg = _calculate_damage(self.venusaur, self.charizard, move, calc_type='max') self.assertEqual([27], dmg)
def test_fire_blast_from_charizard_to_venusaur_without_modifiers(self): move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, calc_type='max') self.assertEqual([300], dmg)
def test_stab_without_weakness_calculates_properly(self): move = 'sludgebomb' dmg = _calculate_damage(self.venusaur, self.charizard, move, calc_type='max') self.assertEqual([130], dmg)
def test_immunity_calculates_properly(self): move = 'earthquake' dmg = _calculate_damage(self.venusaur, self.charizard, move, calc_type='max') self.assertEqual([0], dmg)
def test_4x_weakness_calculates_properly(self): move = 'rockslide' dmg = _calculate_damage(self.venusaur, self.charizard, move, calc_type='max') self.assertEqual([268], dmg)
def test_flashfire_increases_fire_move_damage(self): move = 'fireblast' self.charizard.volatile_status.add('flashfire') dmg = _calculate_damage(self.charizard, self.venusaur, move, calc_type='max') self.assertEqual([450], dmg)
def test_move_versus_completely_typeless_pokemon(self): self.venusaur.types = ["typeless"] move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, calc_type='max') self.assertEqual([150], dmg)
def test_move_versus_partially_typeless_pokemon_with_question_mark_type( self): self.venusaur.types = ["???", "grass"] move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, calc_type='max') self.assertEqual([300], dmg)
def test_boosts_properly_affect_damage_calculation(self): self.charizard.special_attack_boost = 2 move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, calc_type='max') self.assertEqual([597], dmg)
def test_burn_modifier_properly_halves_physical_damage(self): move = 'rockslide' self.venusaur.status = constants.BURN dmg = _calculate_damage(self.venusaur, self.charizard, move, calc_type='max') self.assertEqual([134], dmg)
def test_burn_does_not_modify_special_move(self): move = 'fireblast' self.venusaur.status = constants.BURN dmg = _calculate_damage(self.charizard, self.venusaur, move, calc_type='max') self.assertEqual([300], dmg)
def test_rain_properly_reduces_fire_damage(self): conditions = {'weather': constants.RAIN} move = 'fireblast' dmg = _calculate_damage(self.venusaur, self.charizard, move, conditions, calc_type='max') self.assertEqual([26], dmg)
def test_rain_properly_amplifies_water_damage(self): conditions = {'weather': constants.RAIN} move = 'surf' dmg = _calculate_damage(self.venusaur, self.charizard, move, conditions, calc_type='max') self.assertEqual([261], dmg)
def test_reflect_properly_halves_damage(self): conditions = {'reflect': 1} move = 'rockslide' dmg = _calculate_damage(self.venusaur, self.charizard, move, conditions, calc_type='max') self.assertEqual([134], dmg)
def test_sun_weakens_water_moves(self): conditions = {'weather': constants.SUN} move = 'surf' dmg = _calculate_damage(self.venusaur, self.charizard, move, conditions, calc_type='max') self.assertEqual([87], dmg)
def test_sun_stab_and_2x_weakness(self): conditions = {'weather': constants.SUN} move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') self.assertEqual([450], dmg)
def test_aurora_veil_properly_halves_damage(self): conditions = {'auroraveil': 1} move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') self.assertEqual([150], dmg)
def test_psychic_terrain_does_not_affect_priority_on_non_grounded(self): conditions = {constants.TERRAIN: constants.PSYCHIC_TERRAIN} move = 'machpunch' dmg = _calculate_damage(self.venusaur, self.charizard, move, conditions, calc_type='max') self.assertNotEqual([0], dmg)
def test_light_screen_properly_halves_damage(self): conditions = {'lightscreen': 1} move = 'psychic' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') self.assertEqual([82], dmg)
def test_sand_increases_rock_spdef(self): self.venusaur.types = ['rock'] conditions = {'weather': constants.SAND} move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') self.assertEqual([51], dmg)
def test_sand_does_not_double_ground_spdef(self): self.venusaur.types = ['water'] conditions = {'weather': constants.SAND} move = 'fireblast' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') self.assertEqual([75], dmg)
def test_damage_is_not_increased_if_attacker_is_not_grounded(self): self.charizard.types = ['fire', 'flying'] conditions = {constants.TERRAIN: constants.PSYCHIC_TERRAIN} move = 'psychic' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') self.assertEqual([164], dmg)
def test_psychic_terrain_makes_priority_move_do_nothing(self): self.charizard.types = ['fire'] conditions = {constants.TERRAIN: constants.PSYCHIC_TERRAIN} move = 'machpunch' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') self.assertEqual([0], dmg)
def test_psychic_terrain_increases_psychic_damage(self): self.charizard.types = ['fire'] conditions = {constants.TERRAIN: constants.PSYCHIC_TERRAIN} move = 'psychic' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') # normally this is 164 self.assertEqual([213], dmg)
def test_grassy_terrain_increases_grass_type_move(self): self.charizard.types = ['fire'] conditions = {constants.TERRAIN: constants.GRASSY_TERRAIN} move = 'gigadrain' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') # normally this is 17 self.assertEqual([22], dmg)
def test_misty_terrain_halves_dragon_moves(self): self.charizard.types = ['fire'] conditions = {constants.TERRAIN: constants.MISTY_TERRAIN} move = 'outrage' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') # normally this is 103 self.assertEqual([51], dmg)
def test_electric_terrain_increases_electric_damage_for_grounded_pokemon( self): self.charizard.types = ['fire'] conditions = {constants.TERRAIN: constants.ELECTRIC_TERRAIN} move = 'thunderbolt' dmg = _calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max') # normally this is 41 self.assertEqual([53], dmg)