Exemplo n.º 1
0
 def newTilePositions(self):
     """returns list(TileAttr) for all tiles except bonus tiles.
     The tiles are not associated to any board."""
     result = list()
     isScoringGame = self.player.game.isScoringGame()
     newUpperMelds = list(self.player.exposedMelds)
     if isScoringGame:
         newLowerMelds = list(self.player.concealedMelds)
     else:
         if self.player.concealedMelds:
             newLowerMelds = sorted(self.player.concealedMelds, key=meldKey)
         else:
             tileStr = 'R' + ''.join(self.player.concealedTileNames)
             handStr = ' '.join([tileStr, self.player.mjString()])
             content = Hand.cached(self.player, handStr)
             newLowerMelds = list(Meld(x) for x in content.sortedMeldsContent.split())
             if newLowerMelds:
                 if self.rearrangeMelds:
                     if newLowerMelds[0].pairs[0] == 'Xy':
                         newLowerMelds = sorted(newLowerMelds, key=len, reverse=True)
                 else:
                     # generate one meld with all sorted tiles
                     newLowerMelds = [Meld(sorted(sum((x.pairs for x in newLowerMelds), []), key=elementKey))]
     for yPos, melds in ((0, newUpperMelds), (self.lowerY, newLowerMelds)):
         meldDistance = self.concealedMeldDistance if yPos else self.exposedMeldDistance
         meldX = 0
         for meld in melds:
             for idx in range(len(meld)):
                 result.append(TileAttr(self, meld, idx, meldX, yPos))
                 meldX += 1
             meldX += meldDistance
     return sorted(result, key=lambda x: x.yoffset * 100 + x.xoffset)
Exemplo n.º 2
0
 def exposeMeld(self, meldTiles, calledTile=None):
     """exposes a meld with meldTiles: removes them from concealedTileNames,
     adds the meld to exposedMelds and returns it
     calledTile: we got the last tile for the meld from discarded, otherwise
     from the wall"""
     game = self.game
     game.activePlayer = self
     allMeldTiles = meldTiles[:]
     if calledTile:
         allMeldTiles.append(calledTile.element if isinstance(calledTile, Tile) else calledTile)
     if len(allMeldTiles) == 4 and allMeldTiles[0].islower():
         tile0 = allMeldTiles[0].lower()
         # we are adding a 4th tile to an exposed pung
         self._exposedMelds = [meld for meld in self._exposedMelds if meld.pairs != [tile0] * 3]
         meld = Meld(tile0 * 4)
         self.__concealedTileNames.remove(allMeldTiles[3])
         self.visibleTiles[tile0] += 1
     else:
         allMeldTiles = sorted(allMeldTiles) # needed for Chow
         meld = Meld(allMeldTiles)
         for meldTile in meldTiles:
             self.__concealedTileNames.remove(meldTile)
         for meldTile in allMeldTiles:
             self.visibleTiles[meldTile.lower()] += 1
         meld.expose(bool(calledTile))
     self._exposedMelds.append(meld)
     self.__hand = None
     game.computeDangerous(self)
     adding = [calledTile] if calledTile else None
     self.syncHandBoard(adding=adding)
     return meld
Exemplo n.º 3
0
 def declaredMahJongg(self, concealed, withDiscard, lastTile, lastMeld):
     """player declared mah jongg. Determine last meld, show concealed tiles grouped to melds"""
     assert not isinstance(lastTile, Tile)
     lastMeld = Meld(lastMeld) # do not change the original!
     self.game.winner = self
     if withDiscard:
         self.lastTile = withDiscard
         self.lastMeld = lastMeld
         assert withDiscard == self.game.lastDiscard.element, 'withDiscard: %s lastDiscard: %s' % (
             withDiscard, self.game.lastDiscard.element)
         self.addConcealedTiles(self.game.lastDiscard)
         melds = [Meld(x) for x in concealed.split()]
         if self.lastSource != 'k':   # robbed the kong
             self.lastSource = 'd'
         # the last claimed meld is exposed
         assert lastMeld in melds, '%s: concealed=%s melds=%s lastMeld=%s lastTile=%s withDiscard=%s' % (
                 self.__concealedTileNames, concealed,
                 meldsContent(melds), ''.join(lastMeld.pairs), lastTile, withDiscard)
         melds.remove(lastMeld)
         self.lastTile = self.lastTile.lower()
         lastMeld.pairs.toLower()
         self._exposedMelds.append(lastMeld)
         for tileName in lastMeld.pairs:
             self.visibleTiles[tileName] += 1
     else:
         melds = [Meld(x) for x in concealed.split()]
         self.lastTile = lastTile
         self.lastMeld = lastMeld
     self._concealedMelds = melds
     self.__concealedTileNames = []
     self.__hand = None
     self.syncHandBoard()
Exemplo n.º 4
0
 def computeLastMeld(self):
     """compile hand info into a string as needed by the scoring engine"""
     if self.scoringDialog:
         cbLastMeld = self.scoringDialog.cbLastMeld
         idx = cbLastMeld.currentIndex()
         if idx >= 0:
             return Meld(str(cbLastMeld.itemData(idx).toString()))
     return Meld()
Exemplo n.º 5
0
    def __parseString(self, inString):
        """parse the string passed to Hand()"""
        # pylint: disable=too-many-branches
        tileStrings = []
        for part in inString.split():
            partId = part[0]
            if partId == 'm':
                if len(part) > 1:
                    try:
                        self.__lastSource = TileSource.byChar[part[1]]
                    except KeyError:
                        raise Exception('{} has unknown lastTile {}'.format(inString, part[1]))
                    if len(part) > 2:
                        self.__announcements = set(part[2])
            elif partId == 'L':
                if len(part[1:]) > 8:
                    raise Exception(
                        'last tile cannot complete a kang:' + inString)
                if len(part) > 3:
                    self.__lastMeld = Meld(part[3:])
                self.__lastTile = Tile(part[1:3])
            else:
                if part != 'R':
                    tileStrings.append(part)
        self.bonusMelds, tileStrings = self.__separateBonusMelds(tileStrings)
        tileString = ' '.join(tileStrings)
        self.tiles = TileList(tileString.replace(' ', '').replace('R', ''))
        self.tiles.sort()
        for part in tileStrings[:]:
            if part[:1] != 'R':
                self.melds.append(Meld(part))
                tileStrings.remove(part)

        self.values = tuple(x.value for x in self.tiles)
        self.suits = set(x.lowerGroup for x in self.tiles)
        self.declaredMelds = MeldList(x for x in self.melds if x.isDeclared)
        declaredTiles = list(sum((x for x in self.declaredMelds), []))
        self.tilesInHand = TileList(x for x in self.tiles
                                    if x not in declaredTiles)
        self.lenOffset = (len(self.tiles) - 13
                          - sum(x.isKong for x in self.melds))

        assert len(tileStrings) < 2, tileStrings
        self.__rest = TileList()
        if len(tileStrings):
            self.__rest.extend(TileList(tileStrings[0][1:]))

        last = self.__lastTile
        if last and not last.isBonus:
            assert last in self.tiles, \
                'lastTile %s is not in hand %s' % (last, str(self))
            if self.__lastSource is TileSource.RobbedKong:
                assert self.tiles.count(last.exposed) + \
                    self.tiles.count(last.concealed) == 1, (
                        'Robbing kong: I cannot have '
                        'lastTile %s more than once in %s' % (
                            last, ' '.join(self.tiles)))
Exemplo n.º 6
0
 def computeLastMeld(self):
     """compile hand info into a string as needed by the scoring engine"""
     if self.scoringDialog:
         # is None while ScoringGame is created
         cbLastMeld = self.scoringDialog.cbLastMeld
         idx = cbLastMeld.currentIndex()
         if idx >= 0:
             return Meld(cbLastMeld.itemData(idx))
     return Meld()
Exemplo n.º 7
0
 def rearrange(dummyHand, pairs):
     result = []
     for tileName in pairs[:]:
         if pairs.count(tileName) >= 2:
             result.append(Meld([tileName, tileName]))
             pairs.remove(tileName)
             pairs.remove(tileName)
         elif pairs.count(tileName) == 1:
             result.append(Meld([tileName]))
             pairs.remove(tileName)
     return result, pairs
Exemplo n.º 8
0
 def claimTile(self, player, claim, meldTiles, nextMessage):
     """a player claims a tile for pung, kong or chow.
     meldTiles contains the claimed tile, concealed"""
     if not self.running:
         return
     lastDiscard = self.game.lastDiscard
     # if we rob a tile, self.game.lastDiscard has already been set to the
     # robbed tile
     hasTiles = Meld(meldTiles[:])
     discardingPlayer = self.game.activePlayer
     hasTiles = hasTiles.without(lastDiscard)
     meld = Meld(meldTiles)
     if len(meld) != 4 and not (meld.isPair or meld.isPungKong
                                or meld.isChow):
         msg = i18nE('%1 wrongly said %2 for meld %3')
         self.abort(msg, player.name, claim.name, str(meld))
         return
     if not player.hasConcealedTiles(hasTiles):
         msg = i18nE(
             '%1 wrongly said %2: claims to have concealed tiles %3 but only has %4'
         )
         self.abort(msg, player.name, claim.name, ' '.join(hasTiles),
                    ''.join(player.concealedTiles))
         return
     # update our internal state before we listen to the clients again
     self.game.discardedTiles[lastDiscard.exposed] -= 1
     self.game.activePlayer = player
     if lastDiscard:
         player.lastTile = lastDiscard.exposed
         player.lastSource = TileSource.LivingWallDiscard
     player.exposeMeld(hasTiles, lastDiscard)
     self.game.lastDiscard = None
     block = DeferredBlock(self)
     if (nextMessage != Message.Kong
             and self.game.dangerousFor(discardingPlayer, lastDiscard)
             and discardingPlayer.playedDangerous):
         player.usedDangerousFrom = discardingPlayer
         if Debug.dangerousGame:
             logDebug('%s claims dangerous tile %s discarded by %s' %
                      (player, lastDiscard, discardingPlayer))
         block.tellAll(player,
                       Message.UsedDangerousFrom,
                       source=discardingPlayer.name)
     block.tellAll(player, nextMessage, meld=meld)
     if claim == Message.Kong:
         block.callback(self.pickKongReplacement)
     else:
         block.callback(self.moved)
Exemplo n.º 9
0
 def clientAction(self, client, move):
     """mirror the action locally"""
     prevMove = client.game.lastMoves(only=[Message.DeclaredKong]).next()
     prevKong = Meld(prevMove.source)
     prevMove.player.robTile(prevKong.pairs[0].capitalize())
     move.player.lastSource = 'k'
     client.game.addCsvTag('robbedKong', forAllPlayers=True)
Exemplo n.º 10
0
 def receive(self, tile=None, meld=None):
     """receive a tile or meld and return the meld this tile becomes part of"""
     if tile:
         if tile.isBonus():
             if tile.board == self:
                 return
             meld = Meld(tile)
         else:
             meld = self.__chooseDestinationMeld(tile, meld) # from selector board.
             # if the source is a Handboard, we got a Meld, not a Tile
             if not meld:
                 # user pressed ESCAPE
                 return None
         assert not tile.element.istitle() or meld.pairs[0] != 'Xy', tile
     senderBoard = meld[0].board
     senderBoard.removing(meld=meld)
     if senderBoard == self:
         self.player.moveMeld(meld)
         self.sync()
     else:
         self.player.addMeld(meld)
         self.sync(adding=meld.tiles)
         senderBoard.remove(meld=meld)
     meld.tiles = sorted(meld.tiles, key=lambda x: x.xoffset)
     if any(x.focusable for x in meld.tiles):
         for idx, tile in enumerate(meld.tiles):
             tile.focusable = idx == 0
     return meld
Exemplo n.º 11
0
 def splitRegex(self, rest):
     """split rest into melds as good as possible"""
     rest = ''.join(rest)
     melds = []
     for rule in self.ruleset.splitRules:
         splits = rule.apply(rest)
         while len(splits) > 1:
             for split in splits[:-1]:
                 melds.append(Meld(split))
             rest = splits[-1]
             splits = rule.apply(rest)
         if len(splits) == 0:
             break
     if len(splits) == 1:
         assert Meld(splits[0]).isValid()  # or the splitRules are wrong
     return melds
Exemplo n.º 12
0
 def __setLastTile(self):
     """sets lastTile, lastSource, announcements"""
     self.__announcements = ''
     self.__lastTile = None
     self.__lastSource = None
     parts = self.mjStr.split()
     for part in parts:
         if part[0] == 'L':
             part = part[1:]
             if len(part) > 2:
                 self.__lastMeld = Meld(part[2:])
             self.__lastTile = part[:2]
         elif part[0] == 'M':
             if len(part) > 3:
                 self.__lastSource = part[3]
                 if len(part) > 4:
                     self.__announcements = part[4:]
     if self.__lastTile:
         assert self.__lastTile in self.tileNames, 'lastTile %s is not in tiles %s, mjStr=%s' % (
             self.__lastTile, ' '.join(self.tileNames), self.mjStr)
         if self.__lastSource == 'k':
             assert self.tileNames.count(self.__lastTile.lower()) + \
                 self.tileNames.count(self.__lastTile.capitalize()) == 1, \
                 'Robbing kong: I cannot have lastTile %s more than once in %s' % (
                 self.__lastTile, ' '.join(self.tileNames))
Exemplo n.º 13
0
 def __init__(self, player, command, kwargs):
     if isinstance(command, Message):
         self.message = command
     else:
         self.message = Message.defined[command]
     self.table = None
     self.notifying = False
     self._player = weakref.ref(player) if player else None
     self.token = kwargs['token']
     self.kwargs = kwargs.copy()
     del self.kwargs['token']
     self.score = None
     self.lastMeld = None
     for key, value in kwargs.items():
         assert not isinstance(value, bytes), 'value is bytes:{}'.format(
             repr(value))
         if value is None:
             self.__setattr__(key, None)
         else:
             if key.lower().endswith('tile'):
                 self.__setattr__(key, Tile(value))
             elif key.lower().endswith('tiles'):
                 self.__setattr__(key, TileList(value))
             elif key.lower().endswith('meld'):
                 self.__setattr__(key, Meld(value))
             elif key.lower().endswith('melds'):
                 self.__setattr__(key, MeldList(value))
             elif key == 'playerNames':
                 if Internal.isServer:
                     self.__setattr__(key, value)
                 else:
                     self.__setattr__(key, self.__convertWinds(value))
             else:
                 self.__setattr__(key, value)
Exemplo n.º 14
0
 def computeLastMelds(cls, hand):
     """returns all possible last melds"""
     if not hand.lastTile:
         return []
     couples, rest = cls.findCouples(hand)
     assert not rest, '%s: couples=%s rest=%s' % (hand.string, couples,
                                                  rest)
     return [Meld(x) for x in couples if hand.lastTile in x]
Exemplo n.º 15
0
 def computeLastMelds(self, hand):
     """returns all possible last melds"""
     if not hand.lastTile:
         return
     triples, rest = self.findTriples(hand)
     assert len(rest) == 2
     triples.append(rest)  # just a list of tuples
     return [Meld(x) for x in triples if hand.lastTile in x]
Exemplo n.º 16
0
 def rearrange(self, hand, pairs):
     melds = []
     for triple in self.findTriples(hand)[0]:
         melds.append(Meld(triple))
         pairs.remove(triple[0])
         pairs.remove(triple[1])
         pairs.remove(triple[2])
     while len(pairs) >= 2:
         for value in set(x[1] for x in pairs):
             suits = set(x[0] for x in pairs if x[1] == value)
             if len(suits) < 2:
                 return melds, pairs
             pair = (suits.pop() + value, suits.pop() + value)
             melds.append(Meld(sorted(pair, key=elementKey)))
             pairs.remove(pair[0])
             pairs.remove(pair[1])
     return melds, pairs
Exemplo n.º 17
0
 def rearrange(dummyHand, pairs):
     melds = []
     for pair in set(pairs) & elements.mAJORS:
         while pairs.count(pair) >= 2:
             melds.append(Meld(pair * 2))
             pairs.remove(pair)
             pairs.remove(pair)
     return melds, pairs
Exemplo n.º 18
0
 def computeLastMelds(cls, hand):
     """returns all possible last melds"""
     if not hand.lastTile:
         return
     triples, rest = cls.findTriples(hand)
     assert len(rest) == 2
     triples = list(triples)
     triples.append(rest)
     return [Meld(x) for x in triples if hand.lastTile in x]
Exemplo n.º 19
0
 def __separateBonusMelds(tileString):
     """keep them separate. One meld per bonus tile. Others depend on that."""
     result = []
     if 'f' in tileString or 'y' in tileString:
         for pair in Pairs(tileString.replace(' ', '').replace('R', '')):
             if pair[0] in 'fy':
                 result.append(Meld(pair))
                 tileString = tileString.replace(pair, '', 1)
     return result, tileString
Exemplo n.º 20
0
 def __computeDragonWindMelds(tileString):
     """returns lists with melds containing all (even single)
     dragons respective winds"""
     dragonMelds = []
     windMelds = []
     for split in tileString.split():
         if split[0] == 'R':
             pairs = Pairs(split[1:])
             for lst, tiles in ((windMelds, elements.wINDS),
                                (dragonMelds, elements.dRAGONS)):
                 for tile in tiles:
                     count = pairs.count(tile)
                     if count:
                         lst.append(Meld([tile] * count))
         elif split[0] in 'dD':
             dragonMelds.append(Meld(split))
         elif split[0] in 'wW':
             windMelds.append(Meld(split))
     return dragonMelds, windMelds
Exemplo n.º 21
0
 def rearrange(self, hand, pairs):
     melds = []
     for couple in self.findCouples(hand)[0]:
         if couple[0].islower():
             # this is the mj pair, lower after claiming
             continue
         melds.append(Meld(couple))
         pairs.remove(couple[0])
         pairs.remove(couple[1])
     return melds, pairs
Exemplo n.º 22
0
 def rearrange(cls, hand, rest):
     melds = []
     for couple in cls.findCouples(hand, rest)[0]:
         if couple[0].islower():
             # this is the mj pair, lower after claiming
             continue
         melds.append(Meld(couple))
         rest.remove(couple[0])
         rest.remove(couple[1])
     yield tuple(melds), tuple(rest)
Exemplo n.º 23
0
 def __computeLenOffset(self, tileString):
     """lenOffset is <0 for short hand, 0 for correct calling hand, >0 for long hand.
     Of course ignoring bonus tiles.
     if there are no kongs, 13 tiles will return 0"""
     result = len(self.tileNames) - 13
     for split in tileString.split():
         if split[0] != 'R':
             if Meld(split).isKong():
                 result -= 1
     return result
Exemplo n.º 24
0
def getMonth(month):
    folder = os.path.expanduser(
        '~/Documents/MJLogPython/log/{}/'.format(month))

    if not os.path.exists(folder):
        os.mkdir(folder)

    if month > '200801':
        ykmlist = os.path.expanduser(
            '~/Documents/MJLogPython/ykmjs/New/{}.txt'.format(month))
    else:
        #ykmlist = os.path.expanduser('~/Documents/MJLogPython/ykmjs/New/{}.txt'.format(month))
        raise ValueError("{} yakuman list is in an old format".format(month))
    if not os.path.isfile(ykmlist):
        raise ValueError("{} yakuman list was not prepared.".format(month))

    CharHaiDisp = [
        "<1m>", "<2m>", "<3m>", "<4m>", "<5m>", "<6m>", "<7m>", "<8m>", "<9m>",
        "<1p>", "<2p>", "<3p>", "<4p>", "<5p>", "<6p>", "<7p>", "<8p>", "<9p>",
        "<1s>", "<2s>", "<3s>", "<4s>", "<5s>", "<6s>", "<7s>", "<8s>", "<9s>",
        "<東>", "<南>", "<西>", "<北>", "<白>", "<發>", "<中>"
    ]
    #cnt, cnt1 = 0, 0
    with open(ykmlist, 'rb') as file_:
        next(file_)
        next(file_)
        #                        ' time ','  name  ','[table,[   hand   ],[chiiponkon],last]' ,[yakuman(s)],'link info'
        ykmline = re.finditer(
            r'\'.{11}\',\'[^\']+\',\'\[\d+,\[([\d,]+)\],\[([\d,]*)\],\d+\]\',\[([\d,]*)\],\'([^\']+)\'',
            next(file_).decode('utf-8'))
        for ykm in ykmline:
            #cnt += 1
            hand, furu, ykmstr, info = ykm.groups()
            # print(ykm.groups())
            try:
                ykmtypes = {int(_) for _ in ykmstr.split(',')}
            except:
                # 数え役満
                s = ''.join(CharHaiDisp[int(tile) >> 2]
                            for tile in hand.split(','))
                if len(furu) > 0:
                    s += ', ' + ', '.join(
                        Meld(_).getInfo() for _ in furu.split(','))
                print(info)
                print(s)
            #if (37 in ykmtypes) or (38 in ykmtypes): # 天和,地和
            #    #cnt1 += 1
            #    a = PaifuParseTool(info)
            #    a.printHaiPai()

    #print(cnt, cnt1)
    return None
Exemplo n.º 25
0
 def __arrange(self):
     """work hard to always return the variant with the highest Mah Jongg value."""
     if any(not x.isKnown for x in self.__rest):
         melds, rest = divmod(len(self.__rest), 3)
         self.melds.extend([Tile.unknown.pung] * melds)
         if rest:
             self.melds.append(Meld(Tile.unknown * rest))
         self.__rest = []
     if not self.__rest:
         self.melds.sort()
         mjRules = self.__maybeMahjongg()
         if self.won:
             if not mjRules:
                 # how could this ever happen?
                 raise Hand.__NotWon('Long Hand with no rest')
             self.mjRule = mjRules[0]
         return
     wonHands = []
     lostHands = []
     for mjRule, melds in self.__arrangements():
         allMelds = self.melds[:] + list(melds)
         lastTile = self.lastTile
         if self.lastSource and self.lastSource.isDiscarded:
             lastTile = lastTile.exposed
             lastMelds = sorted(
                 (x for x in allMelds if not x.isDeclared and lastTile.concealed in x),
                 key=lambda x: len(x)) # pylint: disable=unnecessary-lambda
             if lastMelds:
                 allMelds.remove(lastMelds[0])
                 allMelds.append(lastMelds[0].exposed)
         _ = self.newString(
             chain(allMelds, self.bonusMelds),
             rest=None, lastTile=lastTile, lastMeld=None)
         tryHand = Hand(self.player, _, prevHand=self)
         if tryHand.won:
             tryHand.mjRule = mjRule
             wonHands.append((mjRule, melds, tryHand))
         else:
             lostHands.append((mjRule, melds, tryHand))
     # we prefer a won Hand even if a lost Hand might have a higher score
     tryHands = wonHands if wonHands else lostHands
     bestRule, bestVariant, _ = max(tryHands, key=lambda x: x[2])
     if wonHands:
         self.mjRule = bestRule
     self.melds.extend(bestVariant)
     self.melds.sort()
     self.__rest = []
     self.ruleCache.clear()
     assert sum(len(x) for x in self.melds) == len(self.tiles), (
         '%s != %s' % (self.melds, self.tiles))
Exemplo n.º 26
0
 def claimMahJongg(self, msg):
     """a player claims mah jongg. Check this and
     if correct, tell all. Otherwise abort game, kajongg client is faulty"""
     if not self.running:
         return
     player = msg.player
     concealedMelds = MeldList(msg.args[0])
     withDiscard = Tile(msg.args[1]) if msg.args[1] else None
     lastMeld = Meld(msg.args[2])
     if self.game.ruleset.mustDeclareCallingHand:
         assert player.isCalling, '%s %s %s says MJ but never claimed: concmelds:%s withdiscard:%s lastmeld:%s' % (
             self.game.handId, player.hand, player, concealedMelds,
             withDiscard, lastMeld)
     discardingPlayer = self.game.activePlayer
     lastMove = next(self.game.lastMoves(withoutNotifications=True))
     robbedTheKong = lastMove.message == Message.DeclaredKong
     if robbedTheKong:
         player.robsTile()
         withDiscard = lastMove.meld[0].concealed
         lastMove.player.robTileFrom(withDiscard)
     msgArgs = player.showConcealedMelds(concealedMelds, withDiscard)
     if msgArgs:
         self.abort(*msgArgs)
         return
     player.declaredMahJongg(concealedMelds, withDiscard, player.lastTile,
                             lastMeld)
     if not player.hand.won:
         msg = i18nE('%1 claiming MahJongg: This is not a winning hand: %2')
         self.abort(msg, player.name, player.hand.string)
         return
     block = DeferredBlock(self)
     if robbedTheKong:
         block.tellAll(player, Message.RobbedTheKong, tile=withDiscard)
     if (player.lastSource is TileSource.LivingWallDiscard
             and self.game.dangerousFor(discardingPlayer, player.lastTile)
             and discardingPlayer.playedDangerous):
         player.usedDangerousFrom = discardingPlayer
         if Debug.dangerousGame:
             logDebug('%s wins with dangerous tile %s from %s' %
                      (player, self.game.lastDiscard, discardingPlayer))
         block.tellAll(player,
                       Message.UsedDangerousFrom,
                       source=discardingPlayer.name)
     block.tellAll(player,
                   Message.MahJongg,
                   melds=concealedMelds,
                   lastTile=player.lastTile,
                   lastMeld=lastMeld,
                   withDiscardTile=withDiscard)
     block.callback(self.endHand)
Exemplo n.º 27
0
 def genVariants(self, original0, maxPairs=1):
     """generates all possible meld variants out of original
     where original is a list of tile values like ['1','1','2']"""
     color = original0[0][0]
     original = [x[1] for x in original0]
     cVariants = []
     self.__recurse(cVariants, [], original, maxPairs, color)
     gVariants = []
     for cVariant in set(cVariants):
         melds = [Meld(x) for x in cVariant.split()]
         gVariants.append(melds)
     if not gVariants:
         gVariants.append(
             self.splitRegex(original0))  # fallback: nothing useful found
     return gVariants
Exemplo n.º 28
0
 def newLowerMelds(self):
     """a list of melds for the hand as it should look after sync"""
     if self.player.concealedMelds:
         result = MeldList(self.player.concealedMelds)
     elif self.player.concealedTiles:
         tileStr = 'R' + ''.join(x for x in self.player.concealedTiles)
         content = Hand(self.player, tileStr)
         result = MeldList(content.melds + content.bonusMelds)
     else:
         return []
     if not Internal.Preferences.rearrangeMelds:
         result = MeldList(Meld(x) for x in result.tiles())
         # one meld per tile
     result.sort()
     return result
Exemplo n.º 29
0
 def __chooseDestinationMeld(self, tile=None, meld=None):
     """returns a meld, lets user choose between possible meld types"""
     sourceBoard = tile.board
     if tile:
         assert not sourceBoard.isHandBoard # comes from SelectorBoard
         assert not meld
         result = self.chooseVariant(tile, sourceBoard.meldVariants(tile))
         if not result:
             return None
         for idx, myTile in enumerate(result.tiles):
             myTile.element = result.pairs[idx]
     else:
         assert meld
         assert sourceBoard.isHandBoard
         if tile.islower() and len(meld) == 4 and meld.state == CONCEALED:
             pair0 = meld.pairs[0].lower()
             meldVariants = [Meld(pair0*4), Meld(pair0*3 + pair0.capitalize())]
         else:
             result = self.chooseVariant(meld[0], meldVariants)
         if result:
             result.tiles = meld.tiles
             for tile, pair in zip(result.tiles, result.pairs):
                 tile.element = pair
     return result
Exemplo n.º 30
0
 def claimness(hand, discard):
     result = IntDict()
     if ThirteenOrphans.shouldTry(hand):
         doublesCount = hand.doublesEstimate()
         if hand.tileNames.count(discard) == 2:
             # TODO: compute scoring for resulting hand. If it is high anyway,
             # prefer pung over trying 13 orphans
             for rule in hand.ruleset.doublingMeldRules:
                 if rule.appliesToMeld(hand, Meld(discard.lower() * 3)):
                     doublesCount += 1
         if doublesCount < 2 or ThirteenOrphans.shouldTry(hand,
                                                          maxMissing=1):
             result[Message.Pung] = -999
             result[Message.Kong] = -999
             result[Message.Chow] = -999
     return result