mirror of
https://github.com/veekun/pokedex.git
synced 2024-08-20 18:16:34 +00:00
Take Shedinja's 'shed' evolution into account.
This commit is contained in:
parent
11d803fd63
commit
5fb0eed9dc
2 changed files with 76 additions and 39 deletions
|
@ -27,6 +27,7 @@ NO happiny softboiled
|
||||||
NO mamoswine bite body-slam curse double-edge
|
NO mamoswine bite body-slam curse double-edge
|
||||||
OK shedinja swords-dance
|
OK shedinja swords-dance
|
||||||
NO shedinja swords-dance screech
|
NO shedinja swords-dance screech
|
||||||
|
OK shedinja baton-pass grudge
|
||||||
OK shedinja screech double-team fury-cutter x-scissor
|
OK shedinja screech double-team fury-cutter x-scissor
|
||||||
OK raichu volt-tackle
|
OK raichu volt-tackle
|
||||||
OK raichu surf -v gold
|
OK raichu surf -v gold
|
||||||
|
@ -78,5 +79,9 @@ if __name__ == '__main__':
|
||||||
cases = list(test_cases())
|
cases = list(test_cases())
|
||||||
cProfile.runctx("[(run_case(f, argv)) for f, argv in cases]",
|
cProfile.runctx("[(run_case(f, argv)) for f, argv in cases]",
|
||||||
globals(), locals(), filename=filename)
|
globals(), locals(), filename=filename)
|
||||||
print "{0} tests: {1[0]} OK, {1[1]} failed".format(sum(ok_fail), ok_fail)
|
if ok_fail[1]:
|
||||||
|
print '*** FAILED ***'
|
||||||
|
print "{0} tests: {1[0]} OK, {1[1]} failed".format(sum(ok_fail), ok_fail)
|
||||||
|
else:
|
||||||
|
print "{0} tests: OK".format(sum(ok_fail), ok_fail)
|
||||||
print 'Profile stats saved to', filename
|
print 'Profile stats saved to', filename
|
||||||
|
|
|
@ -901,58 +901,45 @@ class Action(Facade):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class StartAction(Action, namedtuple('StartAcion', 'search pokemon_ version_group_')):
|
class StartAction(Action, namedtuple('StartAcion', 'search pokemon_ version_group_')):
|
||||||
keyword = 'start'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
vers = ' or '.join(v.name for v in self.versions)
|
vers = ' or '.join(v.name for v in self.versions)
|
||||||
return u"Start with {0.pokemon.name} in {1}".format(self, vers)
|
return u"Start with {0.pokemon.name} in {1}".format(self, vers)
|
||||||
|
|
||||||
class LearnAction(Action, namedtuple('LearnAction', 'search move_ move_method_')):
|
class LearnAction(Action, namedtuple('LearnAction', 'search move_ move_method_')):
|
||||||
keyword = 'start'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Learn {0.move.name} by {0.move_method.name}".format(self)
|
return u"Learn {0.move.name} by {0.move_method.name}".format(self)
|
||||||
|
|
||||||
class RelearnAction(Action, namedtuple('RelearnAction', 'search move_')):
|
class RelearnAction(Action, namedtuple('RelearnAction', 'search move_')):
|
||||||
keyword = 'start'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Relearn {0.move.name}".format(self)
|
return u"Relearn {0.move.name}".format(self)
|
||||||
|
|
||||||
class ForgetAction(Action, namedtuple('ForgetAction', 'search move_')):
|
class ForgetAction(Action, namedtuple('ForgetAction', 'search move_')):
|
||||||
keyword = 'forget'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Forget {0.move.name}".format(self)
|
return u"Forget {0.move.name}".format(self)
|
||||||
|
|
||||||
class TradeAction(Action, namedtuple('TradeAction', 'search version_group_')):
|
class TradeAction(Action, namedtuple('TradeAction', 'search version_group_')):
|
||||||
keyword = 'trade'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
vers = ' or '.join(v.name for v in self.versions)
|
vers = ' or '.join(v.name for v in self.versions)
|
||||||
return u"Trade to {1}".format(self, vers)
|
return u"Trade to {1}".format(self, vers)
|
||||||
|
|
||||||
class EvolutionAction(Action, namedtuple('EvolutionAction', 'search pokemon_ evolution_trigger_')):
|
class EvolutionAction(Action, namedtuple('EvolutionAction', 'search pokemon_ evolution_trigger_ moves_')):
|
||||||
keyword = 'evolution'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Evolve to {0.pokemon.name} by {0.evolution_trigger.name}".format(self)
|
return u"Evolve to {0.pokemon.name} by {0.evolution_trigger.name}".format(self)
|
||||||
|
|
||||||
class GrowAction(Action, namedtuple('GrowAction', 'search level')):
|
class ShedEvolutionAction(EvolutionAction, namedtuple('EvolutionAction', 'search pokemon_ evolution_trigger_ moves_')):
|
||||||
keyword = 'grow'
|
def __unicode__(self):
|
||||||
|
mvs = ', '.join(m.name for m in self.moves)
|
||||||
|
return u"Co-evolve to {0.pokemon.name}, learning {1}".format(self, mvs)
|
||||||
|
|
||||||
|
class GrowAction(Action, namedtuple('GrowAction', 'search level')):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Grow to level {0.level}".format(self)
|
return u"Grow to level {0.level}".format(self)
|
||||||
|
|
||||||
class SketchAction(Action, namedtuple('SketchAction', 'search move_')):
|
class SketchAction(Action, namedtuple('SketchAction', 'search move_')):
|
||||||
keyword = 'grow'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Sketch {0.move.name}".format(self)
|
return u"Sketch {0.move.name}".format(self)
|
||||||
|
|
||||||
class BreedAction(Action, namedtuple('BreedAction', 'search pokemon_ moves_')):
|
class BreedAction(Action, namedtuple('BreedAction', 'search pokemon_ moves_')):
|
||||||
keyword = 'grow'
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
mvs = ', '.join(m.name for m in self.moves)
|
mvs = ', '.join(m.name for m in self.moves)
|
||||||
return u"Breed {0.pokemon.name} with {1}".format(self, mvs)
|
return u"Breed {0.pokemon.name} with {1}".format(self, mvs)
|
||||||
|
@ -964,21 +951,31 @@ class BreedAction(Action, namedtuple('BreedAction', 'search pokemon_ moves_')):
|
||||||
class InitialNode(Node, namedtuple('InitialNode', 'search')):
|
class InitialNode(Node, namedtuple('InitialNode', 'search')):
|
||||||
def expand(self):
|
def expand(self):
|
||||||
search = self.search
|
search = self.search
|
||||||
|
pokemon_vgs = []
|
||||||
for pokemon, version_groups in search.pokemon_moves.items():
|
for pokemon, version_groups in search.pokemon_moves.items():
|
||||||
egg_groups = search.egg_groups[search.evolution_chains[pokemon]]
|
egg_groups = search.egg_groups[search.evolution_chains[pokemon]]
|
||||||
if any(search.breeds_required[group] for group in egg_groups) or (
|
if any(search.breeds_required[group] for group in egg_groups):
|
||||||
search.evolution_chains[pokemon] == search.goal_evolution_chain):
|
|
||||||
for version_group in version_groups:
|
for version_group in version_groups:
|
||||||
action = StartAction(search, pokemon, version_group)
|
pokemon_vgs.append((pokemon, version_group))
|
||||||
node = PokemonNode(
|
for pokemon in search.pokemon_by_evolution_chain[search.goal_evolution_chain]:
|
||||||
search=search,
|
# We treat Shedinja as learning Ninjask moves by evolution itself.
|
||||||
pokemon_=pokemon,
|
# Nincada doesn't learn the moves and therefore may not be in
|
||||||
level=0,
|
# pokemon_moves, but is required for getting them. So we have to
|
||||||
version_group_=version_group,
|
# include Nincada among the initial nodes explicitly.
|
||||||
moves_=frozenset(),
|
# (For everybody else, three duplicate nodes aren't a problem)
|
||||||
new_level=True,
|
for version_group in search.generation_id_by_version_group:
|
||||||
)
|
pokemon_vgs.append((pokemon, version_group))
|
||||||
yield 0, action, node
|
for pokemon, version_group in pokemon_vgs:
|
||||||
|
action = StartAction(search, pokemon, version_group)
|
||||||
|
node = PokemonNode(
|
||||||
|
search=search,
|
||||||
|
pokemon_=pokemon,
|
||||||
|
level=0,
|
||||||
|
version_group_=version_group,
|
||||||
|
moves_=frozenset(),
|
||||||
|
new_level=True,
|
||||||
|
)
|
||||||
|
yield 0, action, node
|
||||||
|
|
||||||
def is_goal(self):
|
def is_goal(self):
|
||||||
return False
|
return False
|
||||||
|
@ -998,8 +995,12 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
evo_chain = search.evolution_chains[self.pokemon_]
|
evo_chain = search.evolution_chains[self.pokemon_]
|
||||||
if not self.moves_:
|
if not self.moves_:
|
||||||
# Learn something first
|
# Learn something first
|
||||||
# (other expand_* may rely on there being a move)
|
# (other expand_* than listed here may rely on there being a move)
|
||||||
return self.expand_learn()
|
return itertools.chain(
|
||||||
|
self.expand_learn(),
|
||||||
|
# Shedinja actually learns stuff by evolution
|
||||||
|
self.expand_evolutions(),
|
||||||
|
)
|
||||||
elif self.moves_.difference(self.search.goal_moves):
|
elif self.moves_.difference(self.search.goal_moves):
|
||||||
# Learned too much!
|
# Learned too much!
|
||||||
# Moves that aren't in the goal set are either Sketch or evolution
|
# Moves that aren't in the goal set are either Sketch or evolution
|
||||||
|
@ -1114,12 +1115,25 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
cost = search.costs['evolution']
|
cost = search.costs['evolution']
|
||||||
if move and move not in self.moves_:
|
if move and move not in self.moves_:
|
||||||
continue
|
continue
|
||||||
|
if trigger == 'shed':
|
||||||
|
# Shedinja uses Ninjask's minimum level
|
||||||
|
for trigger2, move2, level2, child2 in search.evolutions[self.pokemon_]:
|
||||||
|
if child2 == child:
|
||||||
|
continue
|
||||||
|
level = level2
|
||||||
if level:
|
if level:
|
||||||
if level > self.level:
|
if level > self.level:
|
||||||
kwargs['level'] = level
|
kwargs['level'] = level
|
||||||
kwargs['new_level'] = True
|
kwargs['new_level'] = True
|
||||||
elif level == self.level and self.new_level:
|
elif level == self.level:
|
||||||
pass
|
if self.new_level:
|
||||||
|
# We just grew here
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Have to gain a level
|
||||||
|
kwargs['level'] = level + 1
|
||||||
|
kwargs['new_level'] = True
|
||||||
|
cost += search.costs['evolution-delayed']
|
||||||
else:
|
else:
|
||||||
cost += search.costs['evolution-delayed']
|
cost += search.costs['evolution-delayed']
|
||||||
if trigger in 'level-up use-item'.split():
|
if trigger in 'level-up use-item'.split():
|
||||||
|
@ -1127,11 +1141,29 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
elif trigger == 'trade':
|
elif trigger == 'trade':
|
||||||
kwargs['new_level'] = False
|
kwargs['new_level'] = False
|
||||||
elif trigger == 'shed':
|
elif trigger == 'shed':
|
||||||
# XXX: Shedinja!!
|
# Find the Ninjask
|
||||||
pass
|
for trigger2, move2, level2, child2 in search.evolutions[self.pokemon_]:
|
||||||
|
if child2 == child:
|
||||||
|
continue
|
||||||
|
additional_moves = defaultdict(set) # level -> moves
|
||||||
|
# Get all of Ninjask's moves nicely sorted
|
||||||
|
for move, levels_costs in search.pokemon_moves[child2][self.version_group_].items():
|
||||||
|
for level, cost in levels_costs.get('level-up', []):
|
||||||
|
additional_moves[level].add(move)
|
||||||
|
# Figure out at which level we're *really* evolving here
|
||||||
|
for new_level, moves in additional_moves.items():
|
||||||
|
if level >= level2:
|
||||||
|
shed_kwargs = dict(kwargs)
|
||||||
|
shed_kwargs['level'] = new_level
|
||||||
|
for shed_moves in powerset(moves):
|
||||||
|
shed_kwargs['moves_'] = new_moves = self.moves_.union(shed_moves)
|
||||||
|
yield cost, ShedEvolutionAction(search, child, trigger, new_moves), self._replace(
|
||||||
|
**shed_kwargs)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown evolution trigger %s' % trigger)
|
raise ValueError('Unknown evolution trigger %s' % trigger)
|
||||||
yield cost, EvolutionAction(search, child, trigger), self._replace(
|
# N.B. The Shedinja evolution relies on kwargs being final.
|
||||||
|
# Don't add anything between 'shed' and this!
|
||||||
|
yield cost, EvolutionAction(search, child, trigger, self.moves_), self._replace(
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def expand_breed(self):
|
def expand_breed(self):
|
||||||
|
|
Loading…
Reference in a new issue