def _useless_self_hit(self, battle, order: BattleOrder): # Eliminate easy conditions in which this is not a useless self hit if not order or not order.is_move(): return False if not (order.order.damage or order.order.base_power > 0): return False if order.order.self_switch: return False # If it's a self-hit affected_targets = BattleOrder.get_affected_targets(battle, order) if affected_targets and min(affected_targets) < 0: # Get the mon who is going to be hit target_mon = battle.active_pokemon[min(affected_targets)] # Only allow this as a potential move under these conditions if target_mon.item == 'weaknesspolicy' and order.order.type.damage_multiplier( *target_mon.types) >= 2: return True elif target_mon.ability == 'Berserk': return False elif target_mon.ability == 'Justified' and order.order.type == 'DARK': return False elif target_mon.ability == 'Water Absorb' and order.order.type == 'WATER': return False elif target_mon.ability == 'Volt Absorb' and order.order.type == 'ELECTRIC': return False elif target_mon.ability == 'Flash Fire' and order.order.type == 'FIRE': return False else: return True return False
def choose_move(self, battle): best_order = DefaultBattleOrder() # If we're not being forced to switch and are choosing our moves if not any(battle.force_switch): # Go through and get actions, filter them down to what's possible, and then eliminate ones that dont make sense orders = self.get_all_doubles_moves(battle) filtered_orders = list( filter(lambda x: x and DoubleBattleOrder.is_valid(battle, x), orders)) # Iterate through all actions to pick best short-term move. These are our stored values most_damage, best_switch_multiplier = 0, 0 # Go through every reasonable pair of actions and pick the pair that does the most high damage moves and multipliers of switch for double_order in filtered_orders: damage, switch_multiplier = 0, 0 # Add up damage I'm probably going to do and switch multipliers compared to active pokemon for order in [ double_order.first_order, double_order.second_order ]: if not order: continue # If damaging move, Go through each potential target and add up damage (subtract if self-damage) if order.is_move() and (order.order.damage or order.order.base_power > 0): targets = BattleOrder.get_affected_targets( battle, order) if targets == None: targets = [] for target in targets: stab = 1.5 if order.order.type in order.actor.types else 1 target_mon = utils.showdown_target_to_mon( battle, target) effectiveness = order.order.type.damage_multiplier( *target_mon.types ) if target_mon is not None else 1 base_power = order.order.base_power damage += base_power * stab * effectiveness * ( -1 if target < 0 else 1) if order.dynamax: damage += 1 # Calculate whether we're going to switch into an good environment (wrt types) elif order.is_switch(): switch_multiplier += np.mean([ compute_type_advantage(order.actor, opp) for opp in filter(lambda x: x is not None, battle.opponent_active_pokemon) ]) # Choose move if it does highest damage, and then if tied, the one that has the best switch if damage > most_damage: best_order, most_damage, best_switch_multiplier = double_order, damage, switch_multiplier elif damage == most_damage and switch_multiplier >= best_switch_multiplier: best_order, most_damage, best_switch_multiplier = double_order, damage, switch_multiplier # Force Switch situation; pick switch that has the best type advantage against the opponent's active mons else: orders = self.get_all_doubles_moves(battle) filtered_orders = list( filter(lambda x: DoubleBattleOrder.is_valid(battle, x), orders)) # Go through every possible switch and choose one that has best type advantage against opponent's mon multiplier = -np.inf for double_order in filtered_orders: if not double_order.first_order or not double_order.first_order.is_switch( ): continue # Store the score if there's a better switch multipliers = [] for opp in battle.opponent_active_pokemon: if opp is not None: multipliers.append( compute_type_advantage( double_order.first_order.actor, opp)) if np.mean(multipliers) > multiplier: best_order, multiplier = double_order, np.mean(multipliers) return best_order