Fix up breeding

This commit is contained in:
Petr Viktorin 2011-04-27 00:51:40 +03:00
parent 8dee48d966
commit 4f8108d61b

View file

@ -292,7 +292,7 @@ class MovesetSearch(object):
self.evolution_moves[evolution_chain] = move required for evolution self.evolution_moves[evolution_chain] = move required for evolution
self.babies[egg_group_id] = set of baby pokemon self.babies[egg_group_id] = set of baby pokemon
self.hatch_counters[pokemon] = hatch counter self.hatch_counters[pokemon] = hatch counter
self.gender_rates[pokemon] = gender rate self.gender_rates[evolution_chain] = gender rate
""" """
eg1 = tables.PokemonEggGroup eg1 = tables.PokemonEggGroup
eg2 = aliased(tables.PokemonEggGroup) eg2 = aliased(tables.PokemonEggGroup)
@ -324,7 +324,7 @@ class MovesetSearch(object):
item_baby_chains = set() # evolution chains with baby-trigger items item_baby_chains = set() # evolution chains with baby-trigger items
for pokemon, evolution_chain, parent, g1, g2, baby_item, hatch_counter, gender_rate in query: for pokemon, evolution_chain, parent, g1, g2, baby_item, hatch_counter, gender_rate in query:
self.hatch_counters[pokemon] = hatch_counter self.hatch_counters[pokemon] = hatch_counter
self.gender_rates[pokemon] = gender_rate self.gender_rates[evolution_chain] = gender_rate
if g1 in bad_groups: if g1 in bad_groups:
unbreedable[pokemon] = evolution_chain unbreedable[pokemon] = evolution_chain
else: else:
@ -483,9 +483,9 @@ class MovesetSearch(object):
return success return success
for group in goal_egg_groups: for group in goal_egg_groups:
handle(group, self.goal_moves, ()) handle(group, self.goal_moves, ())
for moves in powerset(self.goal_moves.difference(self.egg_moves)): for moves in powerset(self.goal_moves):
if moves: if moves:
breeds_required[group][frozenset(moves) | self.egg_moves] = 1 breeds_required[group][frozenset(moves)] = 1
self.breeds_required = breeds_required self.breeds_required = breeds_required
if self.debug: if self.debug:
@ -567,7 +567,7 @@ class MovesetSearch(object):
### ###
default_costs = { default_costs = {
# Costs for learning a move in verious ways # Costs for learning a move in various ways
'level-up': 20, # The normal way 'level-up': 20, # The normal way
'machine': 40, # Machines are slightly inconvenient. 'machine': 40, # Machines are slightly inconvenient.
'machine-once': 2000, # before gen. 5, TMs only work once. Avoid. 'machine-once': 2000, # before gen. 5, TMs only work once. Avoid.
@ -592,7 +592,7 @@ default_costs = {
'form-change': 100, 'form-change': 100,
# Other actions. # Other actions.
# Breeding should cost more than 3 times than a lv-up/machine/tutor move. # Breeding should cost more than 3 times a lv-up/machine/tutor move.
'evolution': 100, # We have to do this anyway, usually. 'evolution': 100, # We have to do this anyway, usually.
'evolution-delayed': 50, # *in addition* to evolution. Who wants to mash B on every level. 'evolution-delayed': 50, # *in addition* to evolution. Who wants to mash B on every level.
'breed': 400, # Breeding's a pain. 'breed': 400, # Breeding's a pain.
@ -620,7 +620,7 @@ default_costs = {
class Facade(object): class Facade(object):
@property @property
def pokemon(self): def pokemon(self):
return self.search.get_by_id(tables.Pokemon, self.pokemon_) return self.search.session.query(tables.Pokemon).filter_by(id=self.pokemon_).one()
@property @property
def version_group(self): def version_group(self):
@ -768,7 +768,7 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
level_difference = level - self.level level_difference = level - self.level
if level_difference > 0 or ( if level_difference > 0 or (
level_difference == 0 and self.new_level): level_difference == 0 and self.new_level):
cost += level_difference * search.costs['per-level'] cost += level - self.level * search.costs['per-level']
yield self._learn(move, method, cost, yield self._learn(move, method, cost,
level=level, new_level=True) level=level, new_level=True)
else: else:
@ -870,14 +870,29 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
cost = search.costs['breed'] cost = search.costs['breed']
cost += search.costs['egg'] * len(moves) cost += search.costs['egg'] * len(moves)
cost += search.costs['breed-penalty'] * len(search.egg_moves - moves) cost += search.costs['breed-penalty'] * len(search.egg_moves - moves)
for group in egg_groups: gender_rate = search.gender_rates[evo_chain]
if moves in breeds_required[group]: if 0 <= gender_rate:
yield cost, None, BreedNode(search=self.search, dummy='breed', # Only pokemon that have males can pas down moves to other species
group_=group, version_group_=self.version_group_, # (and the other species must have females: checked in BreedNode)
moves_=self.moves_) for group in egg_groups:
if moves in breeds_required[group]:
yield cost, None, BreedNode(search=self.search, dummy='b',
group_=group, version_group_=self.version_group_,
moves_=self.moves_)
# Since the target family is not included in our breed graph, we
# breed with it explicitly. But again, there must be a female to
# breed with.
if search.gender_rates[search.goal_evolution_chain] > 0:
yield cost, None, GoalBreedNode(search=self.search, dummy='g',
version_group_=self.version_group_, moves_=self.moves_)
elif evo_chain == search.goal_evolution_chain:
# Single-gender & genderless pokemon can pass on moves via
# breeding with Ditto, to produce the same species again. Obviously
# this is only useful when breeding the goal species.
yield cost, None, GoalBreedNode(search=self.search, dummy='g',
version_group_=self.version_group_, moves_=self.moves_)
class BreedNode(Node, namedtuple('BreedNode', class BaseBreedNode(Node):
'search dummy group_ version_group_ moves_')):
"""Breed node """Breed node
This serves to prevent duplicate breeds, by storing only the needed info This serves to prevent duplicate breeds, by storing only the needed info
in the namedtuple. in the namedtuple.
@ -889,22 +904,19 @@ class BreedNode(Node, namedtuple('BreedNode',
vg = self.version_group_ vg = self.version_group_
gen = search.generation_id_by_version_group[vg] gen = search.generation_id_by_version_group[vg]
hatch_level = 5 if (gen < 4) else 1 hatch_level = 5 if (gen < 4) else 1
for baby in search.babies[self.group_]: for baby in self.babies():
bred_moves = self.moves_ bred_moves = self.moves_
gender_rate = search.gender_rates[baby] moves = search.pokemon_moves[baby][vg]
baby_chain = search.evolution_chains[baby] if not bred_moves.issubset(moves):
if bred_moves.issubset(search.movepools[baby_chain]): continue
if len(bred_moves) < 4: if len(bred_moves) < 4:
moves = search.pokemon_moves[baby][self.version_group_] for move, methods in moves.items():
for move, methods in moves.items(): if 'light-ball-pichu' in methods:
if 'light-ball-pichu' in methods: bred_moves.add(move)
bred_moves.add(move) cost = search.costs['per-hatch-counter'] * search.hatch_counters[baby]
cost = search.costs['per-hatch-counter'] * search.hatch_counters[baby] yield 0, BreedAction(self.search, baby, bred_moves), PokemonNode(
yield 0, BreedAction(self.search, baby, bred_moves), PokemonNode( search=self.search, pokemon_=baby, level=hatch_level,
search=self.search, pokemon_=baby, level=hatch_level, version_group_=vg, moves_=bred_moves, new_level=True)
version_group_=vg, moves_=bred_moves, new_level=True)
return
yield
@property @property
def pokemon(self): def pokemon(self):
@ -913,6 +925,26 @@ class BreedNode(Node, namedtuple('BreedNode',
def estimate(self, g): def estimate(self, g):
return 0 return 0
class BreedNode(BaseBreedNode, namedtuple('BreedNode',
'search dummy group_ version_group_ moves_')):
def babies(self):
search = self.search
for baby in search.babies[self.group_]:
baby_chain = search.evolution_chains[baby]
if self.moves_.issubset(search.movepools[baby_chain]) and (
search.gender_rates[baby_chain] > 0):
yield baby
class GoalBreedNode(BaseBreedNode, namedtuple('InbreedNode',
'search dummy version_group_ moves_')):
def babies(self):
search = self.search
goal_family = search.goal_evolution_chain
group = search.egg_groups[goal_family][0]
for baby in search.pokemon_by_evolution_chain[goal_family]:
if baby in search.babies[group]:
yield baby
class GoalNode(PokemonNode): class GoalNode(PokemonNode):
def expand(self): def expand(self):
return () return ()