hsahovic / poke-env

A python interface for training Reinforcement Learning bots to battle on pokemon showdown
https://poke-env.readthedocs.io/
MIT License
282 stars 93 forks source link

Duplicate pokemon/nicknames cause issues with available information #415

Open entropiccode opened 10 months ago

entropiccode commented 10 months ago

If an opposing team has two or more of the same species of Pokemon, the information available to a bot starts to become inaccurate.

Example:: I am battling my bot in a 1v1 battle, custom gen9 format with team preview disabled.

The bot is configured to print a number of details every turn, including the "battle.opponent_team" object, using this code:

print("Opponent Team:", flush=True)
for i in battle.opponent_team.values():
    print(i)

My team consists of 2 Heliolisk and 1 Pelipper. The Heliolisk are different levels (75 and 100), genders, and one is shiny. Bot team consists of 1 Mew.

At the start of the battle, I lead with the non-shiny, lower leveled Heliolisk. The opponent team output looks like this:

Opponent Team: heliolisk (pokemon object) [Active: True, Status: None]

In the Pokemon Showdown client, my team is represented as a Heliolisk and two pokeballs.

On turn 1, I switch to Pelipper. As turn 2 begins, the opponent team output now looks like this:

Opponent Team: heliolisk (pokemon object) [Active: False, Status: None] pelipper (pokemon object) [Active: True, Status: None]

In the client, my team is represented as a Heliolisk, a Pelipper, and a pokeball. So far everything lines up.

On turn 2, I switch from Pelipper into the higher level shiny Heliolisk and this is where the issue arises. The showdown client is displaying my team as a Heliolisk, a Pelipper, and a Heliolisk. The opponent team output, however, looks like this:

Opponent Team: heliolisk (pokemon object) [Active: True, Status: None] pelipper (pokemon object) [Active: False, Status: None]

As a result other information returned is inaccurate. This can be seen further by modifying the code to return the pokemon's level, gender and shiny state as well, like so:

print("Opponent Team:", flush=True)
for i in battle.opponent_team.values():
    print(i, i.level, i.gender, i.shiny)

Repeating the above sequence leaves us with this series of outputs: Turn 1:

Opponent Team: heliolisk (pokemon object) [Active: True, Status: None] 75 FEMALE (pokemon gender) object False

Turn 2:

Opponent Team: heliolisk (pokemon object) [Active: False, Status: None] 75 FEMALE (pokemon gender) object False pelipper (pokemon object) [Active: True, Status: None] 100 FEMALE (pokemon gender) object False

Turn 3:

Opponent Team: heliolisk (pokemon object) [Active: True, Status: None] 100 MALE (pokemon gender) object True pelipper (pokemon object) [Active: False, Status: None] 100 FEMALE (pokemon gender) object False

As you can see, it simply overwrites existing data of the pokemon of the same species instead of treating it as a different member of the opposing team. This causes difficulty when trying to utilize data such as the opponent's ability.

When the pokemon are nicknamed with unique nicknames, the issue seems to go away:

Opponent Team: heliolisk (pokemon object) [Active: False, Status: None] 75 FEMALE (pokemon gender) object False pelipper (pokemon object) [Active: False, Status: None] 100 FEMALE (pokemon gender) object False heliolisk (pokemon object) [Active: True, Status: None] 100 MALE (pokemon gender) object True

However, if all pokemon on the team share a nickname the issue is even worse, as the first entry in the opponent_team dictionary will always be overwritten with the data of the active opponent Pokemon.

entropiccode commented 10 months ago

After testing a format with Team Preview enabled, I can confirm this issue occurs in formats with Team Preview enabled as well.

hsahovic commented 9 months ago

Hi @entropiccode,

Thanks for opening this issue. This problem is a known edge case for poke-env, that I never really looked into. It is a blocker for some very reasonable edge cases though, and I'd like to take a look at it, to check if there is a simple fix for it. Could you provide a minimal script to setup a game between two agents where this issue would arise, as a starting point to debug it?

entropiccode commented 9 months ago

Hi @entropiccode,

Thanks for opening this issue. This problem is a known edge case for poke-env, that I never really looked into. It is a blocker for some very reasonable edge cases though, and I'd like to take a look at it, to check if there is a simple fix for it. Could you provide a minimal script to setup a game between two agents where this issue would arise, as a starting point to debug it?

Sure thing. Attached are 3 different versions that demonstrate the various elements with different teams (duplicate Pokemon with no nicknames, duplicate Pokemon with nicknames, different Pokemon with a shared nickname). Creates two bots that will battle against each other. Scripts are designed to run against a locally hosted showdown server but configurable in a variable. I've also added some informational output that can be un-commented to see how the data updates on a turn by turn basis.

Probably could be more minimal but I wanted to get something together quickly. test_cases.zip

hsahovic commented 9 months ago

Thanks @entropiccode ! I'll dive into it next weekend

hsahovic commented 8 months ago

I looked into this a bit - it is a bit more work that I feel inclined to put for this feature at this stage. Unless you are interested in implementing this yourself (in which case I'd be happy to give you some pointers) or more interest in formats where this would be required arises, I won't implement this feature for now.

entropiccode commented 8 months ago

I looked into this a bit - it is a bit more work that I feel inclined to put for this feature at this stage. Unless you are interested in implementing this yourself (in which case I'd be happy to give you some pointers) or more interest in formats where this would be required arises, I won't implement this feature for now.

To be quite honest this was more of a niche bug I discovered while I was testing static bot logic. It doesn't impact too much in most formats, although definitely something that should be improved long term. Issues like #411 are definitely more pressing.