pmariglia / showdown

A Pokemon Showdown Battle Bot written in Python
GNU General Public License v3.0
258 stars 176 forks source link

trying to calculate the maximum damage each mon deal to the opponent #26

Closed mancho1987 closed 4 years ago

mancho1987 commented 4 years ago

This is the code I have. Please excuse how bad it is, I am just starting and I am learning by reading your code.

` def find_most_damage_move(state, pkmn, opponent_pokemon):

Here I was trying to make a switch before getting all state options, as mentioned in the previous message. I realize this way to do it doesn't work.

poke = state.self.active
state.self.active = pkmn

my_options, opponent_options = state.get_all_options()
moves = []
switches = []
for option in my_options:
    if option.startswith(constants.SWITCH_STRING + " "):
        switches.append(option)
    else:
        moves.append(option)

conditions = {
    constants.REFLECT: state.opponent.side_conditions[constants.REFLECT],
    constants.LIGHT_SCREEN: state.opponent.side_conditions[constants.LIGHT_SCREEN],
    constants.AURORA_VEIL: state.opponent.side_conditions[constants.AURORA_VEIL],
    constants.WEATHER: state.weather,
    constants.TERRAIN: state.field
}
most_damage = -1

#Here I was also trying to do for move in pkmn.moves:, which also didn't work. I need to be able to get here the 4 moves of 
#the current pokemon I am analyzing, in order to get the maximum damage it can inflict to the current opponent pokemon.
for move in moves:
    move_dict = all_move_json[move]
    attacking_move = update_attacking_move(
        pkmn,
        opponent_pokemon,
        move_dict,
        {},
        False,
        state.weather
    )
    damage_amounts = calculate_damage(pkmn, opponent_pokemon, attacking_move, conditions=conditions)
    damage = damage_amounts[0] if damage_amounts else 0

    if damage > most_damage:
        most_damage = damage

#this is just what I was trying to switch back the pokemon to the active spot.  

state.self.active = poke

return round(most_damage)

I also need to calculate the maximum damage each opponent pokemon can inflict on each of the bot's

def find_most_damage_move_opponent(state, pkmn, opponent_pokemon):

poke = state.opponent.active
state.opponent.active = pkmn

my_options, opponent_options = state.get_all_options()
moves = []
switches = []
for option in opponent_options:
    if option.startswith(constants.SWITCH_STRING + " "):
        switches.append(option)
    else:
        moves.append(option)

conditions = {
    constants.REFLECT: state.opponent.side_conditions[constants.REFLECT],
    constants.LIGHT_SCREEN: state.opponent.side_conditions[constants.LIGHT_SCREEN],
    constants.AURORA_VEIL: state.opponent.side_conditions[constants.AURORA_VEIL],
    constants.WEATHER: state.weather,
    constants.TERRAIN: state.field
}
most_damage = -1

for move in moves:
    move_dict = all_move_json[move]
    attacking_move = update_attacking_move(
        pkmn,
        opponent_pokemon,
        move_dict,
        {},
        False,
        state.weather
    )
    damage_amounts = calculate_damage(pkmn, opponent_pokemon, attacking_move, conditions=conditions)
    damage = damage_amounts[0] if damage_amounts else 0

    if damage > most_damage:

        most_damage = damage
state.opponent.active = poke

return round(most_damage)

Here is how I count how many opponent pokemon each of the bot's kills in one hit given their #current hp and the current conditions of the state.

def how_many_each_sweeps(state, user_pkmn):

count = 0
#I was also trying to make it with this filter, but was not working, I think the wrong part was the x.is_alive()
#for pkmn in filter(lambda x: x.is_alive(), state.opponent.reserve):
if state.opponent.active.hp > 0:
    if find_most_damage_move(state, user_pkmn, state.opponent.active) >= state.opponent.active.hp:
            count = count + 1
for pkmn in state.opponent.reserve.values():
    if pkmn.hp > 0:
        if find_most_damage_move(state, user_pkmn, pkmn) >= pkmn.hp:
            count = count + 1
return count

def how_many_each_sweeps_opponent(state, opponent_pkmn):

count = 0
if state.self.active.hp > 0:
    if find_most_damage_move_opponent(state, opponent_pkmn, state.self.active) >= state.self.active.hp:
            count = count + 1
for pkmn in state.self.reserve.values():
    if pkmn.hp > 0:

        if find_most_damage_move_opponent(state, opponent_pkmn, pkmn) >= pkmn.hp:
            count = count + 1
return count

`

pmariglia commented 4 years ago

So you'll need to assemble the state such that each side has the active pokemon you want,.

It's really hacky, but this should get you the most damaging move for either side. Notice calculate_damage has been changed on the master branch from the version I see you were using. You may want to get the latest changes.

from showdown.engine import calculate_damage
def find_most_damage_move(state, side_string):
    # `side_string` is either constants.SELF or constants.OPPONENT

    my_options, opponent_options = state.get_all_options()
    moves = []
    switches = []
    for option in my_options:
        if option.startswith(constants.SWITCH_STRING + " "):
            switches.append(option)
        else:
            moves.append(option)

    most_damage = -1

    for move in moves:
        damage_amounts = calculate_damage(state, side_string, move, constants.DO_NOTHING_MOVE)
        damage = damage_amounts[0] if damage_amounts else 0

        if damage > most_damage:
            most_damage = damage

    return round(most_damage)

side_string should indicate which side you want to find the most damaging move for. You can use this function for both sides.

To repeat this for each matchup, you'll need to modify your other functions to change the active pokemon in the state each time find_most_damage_move is called.

This is REALLY hacky, but something like:

from copy import deepcopy
import constants
def how_many_each_sweeps(state, side, other_side):
    how_many = dict()
    for pkmn in ([side.active] + list(side.reserve.values())):
        count = 0
        if pkmn.hp == 0:
            continue
        for other_pkmn in ([other_side.active] + list(other_side.reserve.values())):
            if other_pkmn.hp == 0:
                continue
            state_copy = deepcopy(state)
            state_copy.self.active = pkmn
            state_copy.opponent.active = other_pkmn

            # use SELF to indicate we want to look at how much damage the active pokemon in state.self does
            if find_most_damage_move(state_copy, constants.SELF) > (other_pkmn.hp / 2):
                count += 1

        how_many[pkmn.id] = count

    return how_many

my_state = State(...)
how_many = how_many_each_sweeps(state, state.self, state.opponent)

and how_many will be a dictionary representing how many pokemon each pokemon sweeps.

To do this for the opponent, you can simply reverse the order of sending in state.self and state.opponent

pmariglia commented 4 years ago

closing this as we have discussed this privately