예제 #1
0
 def _clientDiscarded4(self, dummyResults, msg, dangerousText,
                       mustPlayDangerous):
     """client told us he discarded a tile. Continue, check for dangerous game"""
     block = DeferredBlock(self)
     player = msg.player
     if dangerousText:
         if mustPlayDangerous and not player.lastSource.isDiscarded:
             if Debug.dangerousGame:
                 tile = Tile(msg.args[0])
                 logDebug(
                     '%s claims no choice. Discarded %s, keeping %s. %s' %
                     (player, tile, ''.join(
                         player.concealedTiles), ' / '.join(dangerousText)))
             player.claimedNoChoice = True
             block.tellAll(player,
                           Message.NoChoice,
                           tiles=TileList(player.concealedTiles))
         else:
             player.playedDangerous = True
             if Debug.dangerousGame:
                 tile = Tile(msg.args[0])
                 logDebug(
                     '%s played dangerous. Discarded %s, keeping %s. %s' %
                     (player, tile, ''.join(
                         player.concealedTiles), ' / '.join(dangerousText)))
             block.tellAll(player,
                           Message.DangerousGame,
                           tiles=TileList(player.concealedTiles))
     if msg.answer == Message.OriginalCall:
         player.isCalling = True
         block.callback(self.clientMadeOriginalCall, msg)
     else:
         block.callback(self._askForClaims, msg)
예제 #2
0
파일: hand.py 프로젝트: zero804/kajongg
    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)))
예제 #3
0
 def divided(self, dummyResults=None):
     """the wall is now divided for all clients"""
     if not self.running:
         return
     block = DeferredBlock(self)
     for clientPlayer in self.game.players:
         for player in self.game.players:
             if player == clientPlayer or self.game.playOpen:
                 tiles = player.concealedTiles
             else:
                 tiles = TileList(Tile.unknown * 13)
             block.tell(player,
                        clientPlayer,
                        Message.SetConcealedTiles,
                        tiles=TileList(chain(tiles, player.bonusTiles)))
     block.callback(self.dealt)
예제 #4
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)
예제 #5
0
파일: meld.py 프로젝트: zero804/kajongg
 def without(self, remove):
     """self without tile. The rest will be uppercased."""
     tiles = TileList()
     for tile in self:
         if tile is remove:
             remove = None
         else:
             tiles.append(tile.concealed)
     return tiles
예제 #6
0
 def __possibleChows(self):
     """returns a unique list of lists with possible claimable chow combinations"""
     if self.game.lastDiscard is None:
         return []
     exposedChows = [x for x in self._exposedMelds if x.isChow]
     if len(exposedChows) >= self.game.ruleset.maxChows:
         return []
     tile = self.game.lastDiscard
     within = TileList(self.concealedTiles[:])
     within.append(tile)
     return within.hasChows(tile)
예제 #7
0
파일: meld.py 프로젝트: zero804/kajongg
 def __new__(cls, newContent=None):
     """try to use cache"""
     if isinstance(newContent, str) and newContent in cls.cache:
         return cls.cache[newContent]
     if isinstance(newContent, Meld):
         return newContent
     tiles = TileList(newContent)
     cacheKey = tiles.key()
     if cacheKey in cls.cache:
         return cls.cache[cacheKey]
     return TileList.__new__(cls, tiles)
예제 #8
0
파일: hand.py 프로젝트: zero804/kajongg
    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
            self.debug('New Hand {} {}'.format(string, 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):
                self.debug('Fixing {} {} {}'.format(self, self.won, self.score))
            Hand.indent -= 1
예제 #9
0
 def callingTest(self, string, expected):
     """test a calling hand"""
     for idx, ruleset in enumerate(RULESETS):
         game = GAMES[idx]
         game.players[0].clearCache()
         hand = Hand(game.players[0], string)
         testSays = TileList(
             set(x.lastTile.exposed for x in hand.callingHands)).sorted()
         if isinstance(expected, list):
             if idx >= len(expected):
                 idx %= len(RULESETS) // 2
             expIdx = idx
             if expIdx >= len(expected):
                 expIdx %= len(RULESETS) // 2
             exp = expected[expIdx]
         else:
             exp = expected
         completingTiles = TileList(exp)
         self.assertTrue(testSays == completingTiles,
                         '%s: %s may be completed by %s but testresult is %s' % (
                             ruleset.name, string, completingTiles or 'None', testSays or 'None'))
예제 #10
0
 def endHand(self, dummyResults=None):
     """hand is over, show all concealed tiles to all players"""
     if not self.running:
         return
     if self.game.playOpen:
         self.saveHand()
     else:
         block = DeferredBlock(self)
         for player in self.game.players:
             # there might be no winner, winner.others() would be wrong
             if player != self.game.winner:
                 # the winner tiles are already shown in claimMahJongg
                 block.tellOthers(player,
                                  Message.ShowConcealedTiles,
                                  show=True,
                                  tiles=TileList(player.concealedTiles))
         block.callback(self.saveHand)
예제 #11
0
파일: hand.py 프로젝트: zero804/kajongg
 def __sub__(self, subtractTile):
     """returns a copy of self minus subtractTiles.
     Case of subtractTile (hidden or exposed) is ignored.
     subtractTile must either be undeclared or part of
     lastMeld. Exposed melds of length<3 will be hidden."""
     # pylint: disable=too-many-branches
     # If lastMeld is given, it must be first in the list.
     # Next try undeclared melds, then declared melds
     assert self.lenOffset == 1
     if self.lastTile:
         if self.lastTile is subtractTile and self.prevHand:
             return self.prevHand
     declaredMelds = self.declaredMelds
     tilesInHand = TileList(self.tilesInHand)
     boni = MeldList(self.bonusMelds)
     lastMeld = self.lastMeld
     if subtractTile.isBonus:
         for idx, meld in enumerate(boni):
             if subtractTile is meld[0]:
                 del boni[idx]
                 break
     else:
         if lastMeld and lastMeld.isDeclared and (
                 subtractTile.exposed in lastMeld.exposed):
             declaredMelds.remove(lastMeld)
             tilesInHand.extend(lastMeld.concealed)
         tilesInHand.remove(subtractTile.concealed)
     for meld in declaredMelds[:]:
         if len(meld) < 3:
             declaredMelds.remove(meld)
             tilesInHand.extend(meld.concealed)
     # if we robbed a kong, remove that announcement
     mjPart = ''
     announcements = self.announcements - set('k')
     if announcements:
         mjPart = 'm.' + ''.join(announcements)
     rest = 'R' + str(tilesInHand)
     newString = ' '.join(str(x) for x in (
         declaredMelds, rest, boni, mjPart))
     return Hand(self.player, newString, prevHand=self)
예제 #12
0
파일: meld.py 프로젝트: zero804/kajongg
    def __init__(self, newContent=None):
        """init the meld: content can be either
        - a single string with 2 chars for every tile
        - a list containing such strings
        - another meld. Its tiles are not passed.
        - a list of Tile objects"""
        if not hasattr(self, '_fixed'):  # already defined if I am from cache
            TileList.__init__(self, newContent)
            self.case = ''.join('a' if x.islower() else 'A' for x in self)
            self.key = TileList.key(self)
            if self.key not in self.cache:
                self.cache[self.key] = self
                self.cache[str(self)] = self
            self.isExposed = self.__isExposed()
            self.isConcealed = not self.isExposed
            self.isSingle = self.isPair = self.isChow = self.isPung = False
            self.isKong = self.isClaimedKong = self.isKnitted = False
            self.isDragonMeld = len(self) and self[0].isDragon
            self.isWindMeld = len(self) and self[0].isWind
            self.isHonorMeld = self.isDragonMeld or self.isWindMeld
            self.isBonus = len(self) == 1 and self[0].isBonus
            self.isKnown = len(self) and self[0].isKnown
            self.__setMeldType()
            self.isPungKong = self.isPung or self.isKong
            self.isDeclared = self.isExposed or self.isKong
            groups = set(x.group.lower() for x in self)
            if len(groups) == 1:
                self.group = self[0].group
                self.lowerGroup = self.group.lower()
            else:
                self.group = 'X'
                self.lowerGroup = 'x'
            self.isRest = False
            self.__staticRules = {}  # ruleset is key
            self.__dynamicRules = {}  # ruleset is key
            self.__staticDoublingRules = {}  # ruleset is key
            self.__dynamicDoublingRules = {}  # ruleset is key
            self.__hasRules = None  # unknown yet
            self.__hasDoublingRules = None  # unknown yet
            self.concealed = self.exposed = self.declared = self.exposedClaimed = None  # to satisfy pylint
            self._fixed = True

            if len(self) < 4:
                TileList.__setattr__(self, 'concealed',
                                     Meld(TileList(x.concealed for x in self)))
                TileList.__setattr__(self, 'declared', self.concealed)
                TileList.__setattr__(self, 'exposed',
                                     Meld(TileList(x.exposed for x in self)))
                TileList.__setattr__(self, 'exposedClaimed', self.exposed)
            else:
                TileList.__setattr__(self, 'concealed',
                                     Meld(TileList(x.concealed for x in self)))
                TileList.__setattr__(
                    self, 'declared',
                    Meld(
                        TileList([
                            self[0].exposed, self[1].concealed,
                            self[2].concealed, self[3].exposed
                        ])))
                TileList.__setattr__(self, 'exposed',
                                     Meld(TileList(x.exposed for x in self)))
                TileList.__setattr__(
                    self, 'exposedClaimed',
                    Meld(
                        TileList([
                            self[0].exposed, self[1].exposed, self[2].exposed,
                            self[3].concealed
                        ])))
예제 #13
0
파일: meld.py 프로젝트: zero804/kajongg
 def tiles(self):
     """flat view of all tiles in all melds"""
     return TileList(sum(self, []))
예제 #14
0
 def setUp(self):
     lv = LoadValues("test.txt", groups=True)
     self.tl = TileList()
     for tile in lv.raw_values:
         T = Tile(tile)
         self.tl.add_tile(T)