Allow filtering Mega, Shadow, and Legendary Pokémon

This commit is contained in:
Zoé Cassiopée Gauthier 2024-04-11 16:22:24 -04:00
parent 8e1952072d
commit f453a41a29
3 changed files with 40 additions and 6 deletions

View File

@ -19,3 +19,12 @@ ase-cli --level 30 POKEMON_TYPE_GRASS # Level 30 Grass attackers, no Par
ase-cli --party 2 POKEMON_TYPE_GRASS # Level 40 Grass attackers, Party Power with two trainers. ase-cli --party 2 POKEMON_TYPE_GRASS # Level 40 Grass attackers, Party Power with two trainers.
ase-cli POKEMON_TYPE_DARK POKEMON_TYPE_GHOST # Combined Dark and Ghost attackers. ase-cli POKEMON_TYPE_DARK POKEMON_TYPE_GHOST # Combined Dark and Ghost attackers.
``` ```
The list of attackers can be filtered to exclude Mega, Shadow, or Legendary Pokémon. The simulations can also exclude
exclusive moves, also called legacy or elite moves. For example:
```console
ase-cli --no-mega --no-shadow POKEMON_TYPE_FIRE # Non-shadow, non-mega Fire attackers.
ase-cli --no-legendary POKEMON_TYPE_FIRE # Non-legendary Fire attackers.
ase-cli --no-legacy POKEMON_TYPE_FIRE # Fire attackers, excluding any legacy move.
```

View File

@ -17,6 +17,9 @@ from pogo_scaled_estimators.utilities import format_move_name, format_pokemon_na
class Filter(Flag): class Filter(Flag):
NO_FILTER = 0 NO_FILTER = 0
DISALLOW_LEGACY_MOVES = auto() DISALLOW_LEGACY_MOVES = auto()
DISALLOW_MEGA_POKEMON = auto()
DISALLOW_SHADOW_POKEMON = auto()
DISALLOW_LEGENDARY_POKEMON = auto()
@final @final
@ -32,6 +35,7 @@ class Calculator:
attackers = { attackers = {
attacker: {"RAID_LEVEL_3": [], "RAID_LEVEL_5": [], "RAID_LEVEL_MEGA": []} attacker: {"RAID_LEVEL_3": [], "RAID_LEVEL_5": [], "RAID_LEVEL_MEGA": []}
for attacker in self._pokebattler_proxy.with_charged_moves(self.attacker_types) for attacker in self._pokebattler_proxy.with_charged_moves(self.attacker_types)
if self._allowed_attacker(attacker)
} }
with self._progress: with self._progress:
@ -51,7 +55,9 @@ class Calculator:
self._progress.update(task, advance=1) self._progress.update(task, advance=1)
raid = Raid(raid_tier, defender, level, party) raid = Raid(raid_tier, defender, level, party)
results = { results = {
attacker: [moveset for moveset in movesets if self._viable_move(attacker, moveset.charged_move)] attacker: [
moveset for moveset in movesets if self._allowed_move(attacker, moveset.charged_move)
]
for attacker, movesets in self._pokebattler_proxy.simulate(raid).items() for attacker, movesets in self._pokebattler_proxy.simulate(raid).items()
if attacker in attackers if attacker in attackers
} }
@ -82,7 +88,21 @@ class Calculator:
f"[bold]{format_pokemon_name(attacker, attacker_type)}[/bold] ({format_move_name(fast_move, fast_move_type)}/{format_move_name(charged_move, charged_move_type)}): {ase:.2f}" f"[bold]{format_pokemon_name(attacker, attacker_type)}[/bold] ({format_move_name(fast_move, fast_move_type)}/{format_move_name(charged_move, charged_move_type)}): {ase:.2f}"
) )
def _viable_move(self, pokemon_id: str, move_id: str) -> bool: def _allowed_attacker(self, pokemon_id: str) -> bool:
if Filter.DISALLOW_MEGA_POKEMON in self.filters and ("_MEGA" in pokemon_id or "_PRIMAL" in pokemon_id):
return False
if Filter.DISALLOW_SHADOW_POKEMON in self.filters and "_SHADOW_FORM" in pokemon_id:
return False
pokemon = self._pokebattler_proxy.find_pokemon(pokemon_id)
if Filter.DISALLOW_LEGENDARY_POKEMON in self.filters and pokemon.get("rarity") in [
"POKEMON_RARITY_LEGENDARY",
"POKEMON_RARITY_MYTHIC",
"POKEMON_RARITY_ULTRA_BEAST",
]:
return False
return True
def _allowed_move(self, pokemon_id: str, move_id: str) -> bool:
move = self._pokebattler_proxy.find_move(move_id) move = self._pokebattler_proxy.find_move(move_id)
if move.typing not in self.attacker_types: if move.typing not in self.attacker_types:
return False return False

View File

@ -5,7 +5,9 @@
# https://opensource.org/licenses/MIT. # https://opensource.org/licenses/MIT.
import argparse import argparse
import operator
import sys import sys
from functools import reduce
from pogo_scaled_estimators.calculator import Calculator, Filter from pogo_scaled_estimators.calculator import Calculator, Filter
@ -15,12 +17,15 @@ def main_cli():
_ = parser.add_argument("type", nargs="+", help="an attacker type") _ = parser.add_argument("type", nargs="+", help="an attacker type")
_ = parser.add_argument("--level", type=int, default=40) _ = parser.add_argument("--level", type=int, default=40)
_ = parser.add_argument("--party", type=int, default=1) _ = parser.add_argument("--party", type=int, default=1)
_ = parser.add_argument("--no-elite", action="store_true") _ = parser.add_argument("--no-legacy", dest="filters", action="append_const", const=Filter.DISALLOW_LEGACY_MOVES)
_ = parser.add_argument("--no-mega", dest="filters", action="append_const", const=Filter.DISALLOW_MEGA_POKEMON)
_ = parser.add_argument("--no-shadow", dest="filters", action="append_const", const=Filter.DISALLOW_SHADOW_POKEMON)
_ = parser.add_argument(
"--no-legendary", dest="filters", action="append_const", const=Filter.DISALLOW_LEGENDARY_POKEMON
)
args = parser.parse_args() args = parser.parse_args()
filters = Filter.NO_FILTER filters = reduce(operator.or_, args.filters, Filter.NO_FILTER)
if args.no_elite:
filters |= Filter.DISALLOW_LEGACY_MOVES
calculator = Calculator(args.type, filters) calculator = Calculator(args.type, filters)
calculator.calculate(level=args.level, party=args.party) calculator.calculate(level=args.level, party=args.party)