def __findAllCallingHands(self): """always try to find all of them""" result = [] string = self.string if ' x' in string or self.lenOffset: return result candidates = [] for rule in self.ruleset.mjRules: cand = rule.winningTileCandidates(self) if Debug.hand and cand: # Py2 and Py3 show sets differently candis = ''.join(str(x) for x in sorted(cand)) # pylint: disable=unused-variable self.debug(fmt('callingHands found {candis} for {rule}')) candidates.extend(x.concealed for x in cand) for tile in sorted(set(candidates)): if sum(x.exposed == tile.exposed for x in self.tiles) == 4: continue hand = self + tile if hand.won: result.append(hand) if Debug.hand: _hiderules = ', '.join(set(x.mjRule.name for x in result)) if _hiderules: self.debug(fmt('Is calling {_hiderules}')) return result
def __init__(self, player, string, prevHand=None): """evaluate string for player. rules are to be applied in any case""" if hasattr(self, 'string'): # I am from cache return # shortcuts for speed: self._player = weakref.ref(player) self.ruleset = player.game.ruleset self.intelligence = player.intelligence if player else AIDefault() self.string = string self.__robbedTile = Tile.unknown self.prevHand = prevHand self.__won = None self.__score = None self.__callingHands = None self.__mjRule = None self.ruleCache = {} self.__lastTile = None self.__lastSource = TileSource.Unknown self.__announcements = set() self.__lastMeld = 0 self.__lastMelds = MeldList() self.tiles = None self.melds = MeldList() self.bonusMelds = MeldList() self.usedRules = [] self.__rest = TileList() self.__arranged = None self.__parseString(string) self.__won = self.lenOffset == 1 and player.mayWin if Debug.hand or (Debug.mahJongg and self.lenOffset == 1): self.debug(fmt('{callers}', callers=callers(exclude=['__init__']))) Hand.indent += 1 _hideString = string self.debug(fmt('New Hand {_hideString} {self.lenOffset}')) try: self.__arrange() self.__calculate() self.__arranged = True except Hand.__NotWon as notwon: if Debug.mahJongg: self.debug(fmt(str(notwon))) self.__won = False self.__score = Score() finally: self._fixed = True if Debug.hand or (Debug.mahJongg and self.lenOffset == 1): _hideSelf = str(self) _hideScore = str(self.score) self.debug(fmt( 'Fixing {_hideSelf} {self.won} {_hideScore}')) Hand.indent -= 1
def __applyBestLastMeld(self): """select the last meld giving the highest score (only winning variants)""" assert len(self.lastMelds) > 1 totals = [] prev = self.lastMeld for rule in self.usedRules: assert isinstance(rule, UsedRule) for lastMeld in self.lastMelds: self.__lastMeld = lastMeld try: self.__applyRules() totals.append((self.__totalScore().total(), lastMeld)) except Hand.__NotWon: pass if totals: totals = sorted(totals) # sort by totalScore maxScore = totals[-1][0] totals = list(x[1] for x in totals if x[0] == maxScore) # now we have a list of only lastMelds reaching maximum score if prev not in totals or self.__lastMeld not in totals: if Debug.explain and prev not in totals: if not self.player.game.belongsToRobotPlayer(): self.debug(fmt( 'replaced last meld {prev} with {totals[0]}')) self.__lastMeld = totals[0] self.__applyRules()
def __checkHasExclusiveRules(self): """if we have one, remove all others""" exclusive = list(x for x in self.usedRules if 'absolute' in x.rule.options) if exclusive: self.usedRules = exclusive self.__score = self.__totalScore() if self.__won and not bool(self.__maybeMahjongg()): raise Hand.__NotWon(fmt('exclusive rule {exclusive} does not win'))
def __maybeMahjongg(self): """check if this is a mah jongg hand. Return a sorted list of matching MJ rules, highest total first. If no rule matches, return None""" if self.lenOffset == 1 and self.player.mayWin: matchingMJRules = [x for x in self.ruleset.mjRules if x.appliesToHand(self)] if matchingMJRules: if self.robbedTile and self.robbedTile.isConcealed: # Millington 58: robbing hidden kong is only # allowed for 13 orphans matchingMJRules = [ x for x in matchingMJRules if 'mayrobhiddenkong' in x.options] result = sorted(matchingMJRules, key=lambda x: -x.score.total()) if Debug.mahJongg: self.debug(fmt('{callers} Found {matchingMJRules}', callers=callers())) return result