Skip to content

Commit

Permalink
Integrate doubles baselines into regular baselines
Browse files Browse the repository at this point in the history
  • Loading branch information
hsahovic committed Apr 21, 2024
1 parent f5d6455 commit 4f69a94
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 134 deletions.
3 changes: 0 additions & 3 deletions src/poke_env/environment/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,6 @@ def category(self) -> MoveCategory:
:return: The move category.
:rtype: MoveCategory
"""
if "category" not in self.entry:
print(self, self.entry)

if self._gen <= 3 and self.entry["category"].upper() in {
"PHYSICAL",
"SPECIAL",
Expand Down
2 changes: 0 additions & 2 deletions src/poke_env/player/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from poke_env.concurrency import POKE_LOOP
from poke_env.player import env_player, openai_api, player, random_player, utils
from poke_env.player.baselines import MaxBasePowerPlayer, SimpleHeuristicsPlayer
from poke_env.player.doubles_baselines import DoublesMaxBasePowerPlayer
from poke_env.player.battle_order import (
BattleOrder,
DefaultBattleOrder,
Expand Down Expand Up @@ -61,5 +60,4 @@
"DoubleBattleOrder",
"MaxBasePowerPlayer",
"SimpleHeuristicsPlayer",
"DoublesMaxBasePowerPlayer",
]
73 changes: 73 additions & 0 deletions src/poke_env/player/baselines.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,93 @@
import random
from typing import List

from poke_env.environment.abstract_battle import AbstractBattle
from poke_env.environment.double_battle import DoubleBattle
from poke_env.environment.move_category import MoveCategory
from poke_env.environment.pokemon import Pokemon
from poke_env.environment.side_condition import SideCondition
from poke_env.environment.target import Target
from poke_env.player.battle_order import (
BattleOrder,
DefaultBattleOrder,
DoubleBattleOrder,
)
from poke_env.player.player import Player


class MaxBasePowerPlayer(Player):
def choose_move(self, battle: AbstractBattle):
if self.format_is_doubles:
return self.choose_doubles_move(battle) # type: ignore
else:
return self.choose_singles_move(battle)

def choose_singles_move(self, battle: AbstractBattle):
if battle.available_moves:
best_move = max(battle.available_moves, key=lambda move: move.base_power)
return self.create_order(best_move)
return self.choose_random_move(battle)

def choose_doubles_move(self, battle: DoubleBattle):
orders = []
switched_in = None

if any(battle.force_switch):
return self.choose_random_doubles_move(battle)

can_target_first_opponent = (
battle.opponent_active_pokemon[0]
and not battle.opponent_active_pokemon[0].fainted
)
can_target_second_opponent = (
battle.opponent_active_pokemon[1]
and not battle.opponent_active_pokemon[1].fainted
)
can_double_target = can_target_first_opponent and can_target_second_opponent

for mon, moves, switches in zip(
battle.active_pokemon, battle.available_moves, battle.available_switches
):
switches = [s for s in switches if s != switched_in]

if not mon or mon.fainted:
orders.append(DefaultBattleOrder())
continue
elif not moves and switches:
mon_to_switch_in = random.choice(switches)
orders.append(BattleOrder(mon_to_switch_in))
switched_in = mon_to_switch_in
continue
elif not moves:
orders.append(DefaultBattleOrder())
continue

def move_power_with_double_target(move):
if move.target in {Target.NORMAL, Target.ANY} or not can_double_target:
return move.base_power
return move.base_power * 1.5

best_move = max(moves, key=move_power_with_double_target)

# randomly picks between the two opponents for normal move targeting
targets = battle.get_possible_showdown_targets(best_move, mon)
opp_targets = [
t
for t in targets
if t in {battle.OPPONENT_1_POSITION, battle.OPPONENT_2_POSITION}
]
if opp_targets:
target = random.choice(opp_targets)
else:
target = random.choice(targets)

orders.append(BattleOrder(best_move, move_target=target))

if orders[0] or orders[1]:
return DoubleBattleOrder(orders[0], orders[1])

return self.choose_random_move(battle)


class SimpleHeuristicsPlayer(Player):
ENTRY_HAZARDS = {
Expand Down
49 changes: 0 additions & 49 deletions src/poke_env/player/doubles_baselines.py

This file was deleted.

115 changes: 66 additions & 49 deletions src/poke_env/player/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,27 @@ def choose_default_move(self) -> DefaultBattleOrder:
def choose_random_doubles_move(self, battle: DoubleBattle) -> BattleOrder:
active_orders: List[List[BattleOrder]] = [[], []]

if any(battle.force_switch):
first_order = None
second_order = None

if battle.force_switch[0] and battle.available_switches[0]:
first_switch_in = random.choice(battle.available_switches[0])
first_order = BattleOrder(first_switch_in)
else:
first_switch_in = None

if battle.force_switch[1] and battle.available_switches[1]:
available_switches = [s for s in battle.available_switches[1] if s != first_switch_in]

if available_switches:
second_switch_in = random.choice(available_switches)
second_order = BattleOrder(second_switch_in)

if first_order and second_order:
return DoubleBattleOrder(first_order, second_order)
return DoubleBattleOrder(first_order or second_order, None)

for (
orders,
mon,
Expand All @@ -513,61 +534,57 @@ def choose_random_doubles_move(self, battle: DoubleBattle) -> BattleOrder:
battle.can_dynamax,
battle.can_tera,
):
if mon:
targets = {
move: battle.get_possible_showdown_targets(move, mon)
if not mon:
continue

targets = {
move: battle.get_possible_showdown_targets(move, mon) for move in moves
}
orders.extend(
[
BattleOrder(move, move_target=target)
for move in moves
}
for target in targets[move]
]
)
orders.extend([BattleOrder(switch) for switch in switches])

if can_mega:
orders.extend(
[
BattleOrder(move, move_target=target)
BattleOrder(move, move_target=target, mega=True)
for move in moves
for target in targets[move]
]
)
orders.extend([BattleOrder(switch) for switch in switches])

if can_mega:
orders.extend(
[
BattleOrder(move, move_target=target, mega=True)
for move in moves
for target in targets[move]
]
)
if can_z_move:
available_z_moves = set(mon.available_z_moves)
orders.extend(
[
BattleOrder(move, move_target=target, z_move=True)
for move in moves
for target in targets[move]
if move in available_z_moves
]
)

if can_dynamax:
orders.extend(
[
BattleOrder(move, move_target=target, dynamax=True)
for move in moves
for target in targets[move]
]
)
if can_z_move:
available_z_moves = set(mon.available_z_moves)
orders.extend(
[
BattleOrder(move, move_target=target, z_move=True)
for move in moves
for target in targets[move]
if move in available_z_moves
]
)

if can_tera:
orders.extend(
[
BattleOrder(move, move_target=target, terastallize=True)
for move in moves
for target in targets[move]
]
)
if can_dynamax:
orders.extend(
[
BattleOrder(move, move_target=target, dynamax=True)
for move in moves
for target in targets[move]
]
)

if sum(battle.force_switch) == 1:
if orders:
return orders[int(random.random() * len(orders))]
return self.choose_default_move()
if can_tera:
orders.extend(
[
BattleOrder(move, move_target=target, terastallize=True)
for move in moves
for target in targets[move]
]
)

orders = DoubleBattleOrder.join_orders(*active_orders)

Expand Down Expand Up @@ -623,10 +640,10 @@ def choose_random_move(self, battle: AbstractBattle) -> BattleOrder:
:return: Move order
:rtype: str
"""
if isinstance(battle, Battle):
return self.choose_random_singles_move(battle)
elif isinstance(battle, DoubleBattle):
if isinstance(battle, DoubleBattle):
return self.choose_random_doubles_move(battle)
elif isinstance(battle, Battle):
return self.choose_random_singles_move(battle)
else:
raise ValueError(
"battle should be Battle or DoubleBattle. Received %d" % (type(battle))
Expand Down
3 changes: 0 additions & 3 deletions unit_tests/environment/test_double_battle.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,6 @@ def test_one_mon_left_in_double_battles_results_in_available_move_in_the_correct
["", "swap", "p1b: Cresselia", "0", "[from] move: Ally Switch"]
)

print(battle.available_moves)
print(battle.active_pokemon)

assert battle.available_moves[0] == []
assert [m.id for m in battle.available_moves[1]] == ["recover", "haze"]
assert battle.active_pokemon[0] is None
Expand Down
4 changes: 0 additions & 4 deletions unit_tests/environment/test_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ def test_flags():
flame_thrower = Move("flamethrower", gen=8)
sludge_bomb = Move("sludgebomb", gen=8)

print(flame_thrower.flags)
assert flame_thrower.flags == {"metronome", "protect", "mirror"}
assert sludge_bomb.flags == {"bullet", "metronome", "protect", "mirror"}
for move in move_generator():
Expand Down Expand Up @@ -343,8 +342,6 @@ def test_secondary():
assert acid_armor.secondary == []

for move in move_generator():
if move.secondary:
print(move.id, move.secondary)
assert isinstance(move.secondary, list)
for secondary in move.secondary:
assert isinstance(secondary, dict)
Expand Down Expand Up @@ -714,7 +711,6 @@ def test_dynamax_moves_base_power():
}

for move_name, bp in move_to_dynamax_power.items():
print("Expecting", move_name, "to have", bp, "base power once dynamaxed")
move = Move(move_name, gen=8)
dynamaxed = move.dynamaxed
assert dynamaxed == move.dynamaxed == move._dynamaxed_move # testing caching
Expand Down
Loading

0 comments on commit 4f69a94

Please sign in to comment.