def canTing(self, tiles, leftTiles, tile, magicTiles=[]): if len(leftTiles) < 12: # 小于12张不能亮牌/听牌 return False, [] isTing, tingResults = MTing.canTing(MTile.cloneTiles(tiles), leftTiles, self.winRuleMgr, tile, magicTiles) ftlog.debug('MTingKawuxingRule.canTing using MTing isTing:', isTing, ' tingResults:', tingResults) return isTing, tingResults
def isPiao(self): playerChiTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_CHI] if len(playerChiTiles) > 0: return False isHasKe = False playerPengTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_PENG] if len(playerPengTiles) > 0: isHasKe = True playerGangTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_GANG] if len(playerGangTiles) > 0: isHasKe = True playerHandTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_HAND] newPlayerHandTiles = MTile.cloneTiles(playerHandTiles) newPlayerHandTilesArr = MTile.changeTilesToValueArr(newPlayerHandTiles) for playerHandTileCount in newPlayerHandTilesArr: if playerHandTileCount == 3: isHasKe = True break if not isHasKe: return False for wn in self.winNodes: # if wn['winTile'] == self.winTile: patterns = wn['pattern'] ftlog.debug('MJixiOneResult.isPiao winTile:', self.winTile, ' winPatterns:', patterns) for p in patterns: if len(p) == 3 and p[0] != p[1]: return False return True
def isQiDui(self): playerChiTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_CHI] if len(playerChiTiles) > 0: return False playerPengTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_PENG] if len(playerPengTiles) > 0: return False playerGangTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_GANG] if len(playerGangTiles) > 0: return False for wn in self.winNodes: if wn['winTile'] == self.winTile: patterns = wn['pattern'] ftlog.debug('MJixiOneResult.isQiDui winTile:', self.winTile, ' winPatterns:', patterns) for p in patterns: if len(p) == 3: return False # 宝牌情况 if self.isMagicTile(): for wn in self.winNodes: winTile = wn['winTile'] patterns = wn['pattern'] for p in patterns: if (winTile in p) and len(p) == 3: return False handTiles = self.playerAllTiles[self.winSeatId][MHand.TYPE_HAND] newHandTiles = MTile.cloneTiles(handTiles) ftlog.debug('MTingJixiRule.MTing.canTing isQiDui handTiles:', handTiles, 'isMagic:', self.isMagicTile(), 'winTile:', self.winTile) newHandTiles.append(self.winTile) handTilesArr = MTile.changeTilesToValueArr(newHandTiles) duiCount = 0 for index in range(len(handTilesArr)): if handTilesArr[index] == 2: duiCount += 1 elif handTilesArr[index] == 4: duiCount += 2 if duiCount == 7 or (duiCount == 6 and self.isMagicTile()): # 宝牌情况 return True return False
def tingQiDui(self, tiles, cur_tile, leftTiles): """ 检查是否可以听七小对 二种牌型可听 * 别人打牌 五对(包括杠) 一刻 粘一张 * 自己上牌 六对(包括杠) 两个单张 :param tiles 手牌 :param cur_tile 刚刚摸的牌 :param leftTiles: 全局剩余的牌 :return [ { 'isQiDui' : 1 'dropTile' : 11, # 出牌`一筒` 'winNodes' : [{ # 听牌细节 'winTile' : 1, # 听`一万` 'winTileCount' : 3, # 剩`三张一万` 'pattern' : [ [6, 6], # 听牌的条件 ... ] }] } ] """ ftlog.debug('MTingHaerbinJixi.MTing.tingQiDui handTiles:', tiles[MHand.TYPE_HAND], ' tile:', cur_tile) handTiles = tiles[MHand.TYPE_HAND] newHandTiles = MTile.cloneTiles(handTiles) # 不考虑摸牌 newHandTiles.remove(cur_tile) if len(newHandTiles) < 13: # 手牌不够 return False, [] newHandTilesArr = MTile.changeTilesToValueArr(newHandTiles) duiCount = 0 singleTiles = [] duiPattern = [] for tile, number in newHandTilesArr.tile_items(): if number == 2: # 对 duiCount += 1 duiPattern.append([tile, tile]) elif number == 4: # 杠算两对 duiCount += 2 duiPattern.append([tile, tile]) duiPattern.append([tile, tile]) elif number == 3: # 碰 if tile != cur_tile: # 摸牌不能凑杠 有单张了 singleTiles.append(tile) duiPattern.append([tile, tile]) elif tile != cur_tile: # 摸牌不能凑对 有单张了 singleTiles.append(tile) else: duiPattern.append([cur_tile, cur_tile]) if len(singleTiles) != 2: # 单张过多不能听七对 # 单张过少则已经可以胡牌(不能听了) # ftlog.debug('MTingJixiRule.MTing.canTing tingQiDui the singleTiles count error: ', len(singleTiles)) return False, [] # 站牌处理 手里有五对 并且有一张或三张上的牌 那么可以听 方案就是剩下的两张 newLeftTilesArr = MTile.changeTilesToValueArr(leftTiles) tingResult = [ { # 听第2张单牌 'isQiDui': 1, 'dropTile': singleTiles[0], 'winNodes': [{ 'winTile': singleTiles[1], 'winTileCount': newLeftTilesArr[singleTiles[1]], 'pattern': duiPattern + [[singleTiles[1], singleTiles[1]]] }] }, { # 听第1张单牌 'isQiDui': 1, 'dropTile': singleTiles[1], 'winNodes': [{ 'winTile': singleTiles[0], 'winTileCount': newLeftTilesArr[singleTiles[0]], 'pattern': duiPattern + [[singleTiles[0], singleTiles[0]]] }] } ] return True, tingResult
def canTing(self, tiles, leftTiles, tile, magicTiles=[]): """子类必须实现 参数: 1)tiles 该玩家的手牌 2)leftTiles 剩余手牌 返回值: 是否可以听牌,听牌详情 """ handCount = len(tiles[MHand.TYPE_HAND]) if len(tiles[MHand.TYPE_CHI]) == 0 and len( tiles[MHand.TYPE_PENG]) == 0 and len( tiles[MHand.TYPE_GANG]) == 0: isTing, tingResults = self.tingQiDui(tiles, tile, leftTiles) if isTing: ftlog.debug( 'MTingJixiRule.MTing.canTing tingQiDui tingResults:', tingResults) return isTing, tingResults # ftlog.debug( 'MTingJixiRule.canTing 0 tiles:', tiles ) isTing, tingResults = MTing.canTing(MTile.cloneTiles(tiles), leftTiles, self.winRuleMgr, tile, magicTiles) # ftlog.debug( 'MTingJixiRule.canTing 1 tiles:', tiles ) ftlog.debug('MTingJixiRule.MTing.canTing isTing:', isTing, ' tingResults:', tingResults) if not isTing: return False, [] pengCount = len(tiles[MHand.TYPE_PENG]) gangCount = len(tiles[MHand.TYPE_GANG]) # 检查刻,刻的来源,碰牌/明杠牌/手牌 keCount = pengCount + gangCount newTingResults = [] for tingResult in tingResults: newWinNodes = [] winNodes = tingResult['winNodes'] for winNode in winNodes: newTiles = MTile.cloneTiles(tiles) newTiles[MHand.TYPE_HAND].remove(tingResult['dropTile']) newTiles[MHand.TYPE_HAND].append(winNode['winTile']) tileArr = MTile.changeTilesToValueArr( MHand.copyAllTilesToList(newTiles)) patterns = winNode['pattern'] isQiDui = False isPiaoHu = self.isPiaoHu(patterns, newTiles) # 飘和七对可以手把一 if (isPiaoHu or isQiDui): if handCount < 1: continue else: if handCount < 5: continue # 夹起步(顺牌只能和夹和3,7) 不能和两头 可以单吊 chunJiaConfig = self.getTableConfig(MTDefine.MIN_MULTI, 0) if chunJiaConfig: bianMulti = self.tableConfig.get(MTDefine.BIAN_MULTI, 0) hasJia = False for pattern in patterns: if winNode['winTile'] in pattern: if len(pattern) == 3 and pattern[0] != pattern[1]: if pattern.index(winNode['winTile']) == 2: if bianMulti: if MTile.getValue( winNode['winTile']) == 3: hasJia = True break if pattern.index(winNode['winTile']) == 0: if bianMulti: if MTile.getValue( winNode['winTile']) == 7: hasJia = True break if pattern.index(winNode['winTile']) == 1: hasJia = True break # 单吊 if len(pattern) == 2 and pattern[0] == pattern[1]: hasJia = True break if not hasJia: ftlog.debug( 'MTingHaerbinRule.canTing :, can not win tile:', winNode['winTile'], ', not has jia continue....') continue zhongCount = tileArr[MTile.TILE_HONG_ZHONG] # 检查牌中的幺/九 yaoCount = tileArr[MTile.TILE_ONE_WAN] + tileArr[ MTile.TILE_ONE_TONG] + tileArr[MTile.TILE_ONE_TIAO] jiuCount = tileArr[MTile.TILE_NINE_WAN] + tileArr[ MTile.TILE_NINE_TONG] + tileArr[MTile.TILE_NINE_TIAO] # 飘和七小对不需要1,9 if (yaoCount + jiuCount + zhongCount) == 0 and (not isPiaoHu) and (not isQiDui): continue patterns = winNode['pattern'] checkKeCount = keCount + self.getKeCount(patterns) ftlog.debug('MTingHaerbinRule.canTing keCount:', keCount) # 胡牌必须有刻牌 七小对除外 if checkKeCount or isQiDui: newWinNodes.append(winNode) if len(newWinNodes) > 0: newTingResult = {} newTingResult['dropTile'] = tingResult['dropTile'] newTingResult['winNodes'] = newWinNodes newTingResults.append(newTingResult) return len(newTingResults) > 0, newTingResults
def tingQiDui(self, tiles, cur_tile, leftTiles): """ 检查是否可以听七小对 二种牌型可听 * 别人打牌 五对(包括杠) 一刻 粘一张 * 自己上牌 六对(包括杠) 两个单张 :param tiles 手牌 :param cur_tile 刚刚摸的牌 :param leftTiles: 全局剩余的牌 :return [ { 'isQiDui' : 1 'dropTile' : 11, # 出牌`一筒` 'winNodes' : [{ # 听牌细节 'winTile' : 1, # 听`一万` 'winTileCount' : 3, # 剩`三张一万` 'pattern' : [ [6, 6], # 听牌的条件 ... ] }] } ] """ ftlog.debug('MTingHaerbinJixi.MTing.tingQiDui handTiles:', tiles[MHand.TYPE_HAND], ' tile:', cur_tile) handTiles = tiles[MHand.TYPE_HAND] newHandTiles = MTile.cloneTiles(handTiles) # 不考虑摸牌 newHandTiles.remove(cur_tile) if len(newHandTiles) < 13: # 手牌不够 return False, [] newHandTilesArr = MTile.changeTilesToValueArr(newHandTiles) duiCount = 0 singleTiles = [] duiPattern = [] for tile, number in newHandTilesArr.tile_items(): if number == 2: # 对 duiCount += 1 duiPattern.append([tile, tile]) elif number == 4: # 杠算两对 duiCount += 2 duiPattern.append([tile, tile]) duiPattern.append([tile, tile]) elif number == 3: # 碰 if tile != cur_tile: # 摸牌不能凑杠 有单张了 singleTiles.append(tile) duiPattern.append([tile, tile]) elif tile != cur_tile: # 摸牌不能凑对 有单张了 singleTiles.append(tile) else: duiPattern.append([cur_tile, cur_tile]) if len(singleTiles) != 2: # 单张过多不能听七对 # 单张过少则已经可以胡牌(不能听了) # ftlog.debug('MTingJixiRule.MTing.canTing tingQiDui the singleTiles count error: ', len(singleTiles)) return False, [] # 站牌处理 手里有五对 并且有一张或三张上的牌 那么可以听 方案就是剩下的两张 newLeftTilesArr = MTile.changeTilesToValueArr(leftTiles) tingResult = [{ # 听第2张单牌 'isQiDui': 1, 'dropTile': singleTiles[0], 'winNodes': [{ 'winTile': singleTiles[1], 'winTileCount': newLeftTilesArr[singleTiles[1]], 'pattern': duiPattern + [[singleTiles[1], singleTiles[1]]] }] }, { # 听第1张单牌 'isQiDui': 1, 'dropTile': singleTiles[1], 'winNodes': [{ 'winTile': singleTiles[0], 'winTileCount': newLeftTilesArr[singleTiles[0]], 'pattern': duiPattern + [[singleTiles[0], singleTiles[0]]] }] }] return True, tingResult
def canTing(self, tiles, leftTiles, tile, magicTiles=[]): """子类必须实现 参数: 1)tiles 该玩家的手牌 2)leftTiles 剩余手牌 返回值: 是否可以听牌,听牌详情 """ handCount = len(tiles[MHand.TYPE_HAND]) if len(tiles[MHand.TYPE_CHI]) == 0 and len(tiles[MHand.TYPE_PENG]) == 0 and len(tiles[MHand.TYPE_GANG]) == 0: isTing, tingResults = self.tingQiDui(tiles, tile, leftTiles) if isTing: ftlog.debug('MTingJixiRule.MTing.canTing tingQiDui tingResults:', tingResults) return isTing, tingResults # ftlog.debug( 'MTingJixiRule.canTing 0 tiles:', tiles ) isTing, tingResults = MTing.canTing(MTile.cloneTiles(tiles), leftTiles, self.winRuleMgr, tile, magicTiles) # ftlog.debug( 'MTingJixiRule.canTing 1 tiles:', tiles ) ftlog.debug('MTingJixiRule.MTing.canTing isTing:', isTing, ' tingResults:', tingResults) if not isTing: return False, [] pengCount = len(tiles[MHand.TYPE_PENG]) gangCount = len(tiles[MHand.TYPE_GANG]) # 检查刻,刻的来源,碰牌/明杠牌/手牌 keCount = pengCount + gangCount newTingResults = [] for tingResult in tingResults: newWinNodes = [] winNodes = tingResult['winNodes'] for winNode in winNodes: newTiles = MTile.cloneTiles(tiles) newTiles[MHand.TYPE_HAND].remove(tingResult['dropTile']) newTiles[MHand.TYPE_HAND].append(winNode['winTile']) tileArr = MTile.changeTilesToValueArr(MHand.copyAllTilesToList(newTiles)) patterns = winNode['pattern'] isQiDui = False isPiaoHu = self.isPiaoHu(patterns, newTiles) # 飘和七对可以手把一 if (isPiaoHu or isQiDui): if handCount < 1: continue else: if handCount < 5: continue # 夹起步(顺牌只能和夹和3,7) 不能和两头 可以单吊 chunJiaConfig = self.getTableConfig(MTDefine.MIN_MULTI, 0) if chunJiaConfig: bianMulti = self.tableConfig.get(MTDefine.BIAN_MULTI, 0) hasJia = False for pattern in patterns: if winNode['winTile'] in pattern: if len(pattern) == 3 and pattern[0] != pattern[1]: if pattern.index(winNode['winTile']) == 2: if bianMulti: if MTile.getValue(winNode['winTile']) == 3: hasJia = True break if pattern.index(winNode['winTile']) == 0: if bianMulti: if MTile.getValue(winNode['winTile']) == 7: hasJia = True break if pattern.index(winNode['winTile']) == 1: hasJia = True break # 单吊 if len(pattern) == 2 and pattern[0] == pattern[1]: hasJia = True break if not hasJia: ftlog.debug('MTingHaerbinRule.canTing :, can not win tile:', winNode['winTile'], ', not has jia continue....') continue zhongCount = tileArr[MTile.TILE_HONG_ZHONG] # 检查牌中的幺/九 yaoCount = tileArr[MTile.TILE_ONE_WAN] + tileArr[MTile.TILE_ONE_TONG] + tileArr[MTile.TILE_ONE_TIAO] jiuCount = tileArr[MTile.TILE_NINE_WAN] + tileArr[MTile.TILE_NINE_TONG] + tileArr[MTile.TILE_NINE_TIAO] # 飘和七小对不需要1,9 if (yaoCount + jiuCount + zhongCount) == 0 and (not isPiaoHu) and (not isQiDui): continue patterns = winNode['pattern'] checkKeCount = keCount + self.getKeCount(patterns) ftlog.debug('MTingHaerbinRule.canTing keCount:', keCount) # 胡牌必须有刻牌 七小对除外 if checkKeCount or isQiDui: newWinNodes.append(winNode) if len(newWinNodes) > 0: newTingResult = {} newTingResult['dropTile'] = tingResult['dropTile'] newTingResult['winNodes'] = newWinNodes newTingResults.append(newTingResult) return len(newTingResults) > 0, newTingResults
def canTing(self, tiles, leftTiles, tile, magicTiles=[]): """子类必须实现 参数: 1)tiles 该玩家的手牌 2)leftTiles 剩余手牌 返回值: 是否可以听牌,听牌详情 """ handCount = len(tiles[MHand.TYPE_HAND]) if handCount < 5: return False, [] # ftlog.debug( 'MTingHaerbinRule.canTing 0 tiles:', tiles ) isTing, tingResults = MTing.canTing(MTile.cloneTiles(tiles), leftTiles, self.winRuleMgr, tile, magicTiles) # ftlog.debug( 'MTingHaerbinRule.canTing 1 tiles:', tiles ) ftlog.debug('MTingHaerbinRule.MTing.canTing isTing:', isTing, ' tingResults:', tingResults) # [{'dropTile': 11, 'winNodes': [{'winTile': 1, 'winTileCount': 3, 'pattern': [[6, 6], [5, 6, 7], [4, 5, 6], [1, 2, 3]]}, {'winTile': 2, 'winTileCount': 2, 'pattern': [[6, 6, 6], [5, 6, 7], [3, 4, 5], [2, 2]]}, {'winTile': 4, 'winTileCount': 3, 'pattern': [[6, 6], [5, 6, 7], [4, 5, 6], [2, 3, 4]]}, {'winTile': 5, 'winTileCount': 2, 'pattern': [[6, 6, 6], [5, 6, 7], [5, 5], [2, 3, 4]]}, {'winTile': 7, 'winTileCount': 1, 'pattern': [[6, 6], [5, 6, 7], [5, 6, 7], [2, 3, 4]]}, {'winTile': 8, 'winTileCount': 1, 'pattern': [[6, 7, 8], [6, 6, 6], [5, 5], [2, 3, 4]]}]}] if not isTing: return False, [] chiCount = len(tiles[MHand.TYPE_CHI]) pengCount = len(tiles[MHand.TYPE_PENG]) gangCount = len(tiles[MHand.TYPE_GANG]) if (chiCount + pengCount + gangCount) == 0: return False, [] # 检查刻,刻的来源,碰牌/明杠牌/手牌 keCount = pengCount + gangCount # 必须有顺牌 shunCount = chiCount newTingResults = [] for tingResult in tingResults: newWinNodes = [] winNodes = tingResult['winNodes'] for winNode in winNodes: newTiles = MTile.cloneTiles(tiles) newTiles[MHand.TYPE_HAND].remove(tingResult['dropTile']) newTiles[MHand.TYPE_HAND].append(winNode['winTile']) tileArr = MTile.changeTilesToValueArr(MHand.copyAllTilesToList(newTiles)) # ftlog.debug( 'MTingHaerbinRule.canTing tileArr:', tileArr ) # 夹起步(顺牌只能和夹和3,7) 除单吊 chunJiaConfig = self.getTableConfig(MTDefine.MIN_MULTI, 0) if chunJiaConfig: chunJiaContinue = False patterns = winNode['pattern'] for pattern in patterns: if winNode['winTile'] in pattern: if len(pattern) == 3 and pattern[0] != pattern[1]: if (pattern.index(winNode['winTile'])) == 2 and MTile.getValue(winNode['winTile']) != 3: chunJiaContinue = True break if (pattern.index(winNode['winTile'])) == 0 and MTile.getValue(winNode['winTile']) != 7: chunJiaContinue = True break # 夹起步不能和对倒 if len(pattern) == 3 and pattern[0] == pattern[1]: chunJiaContinue = True break if chunJiaContinue: ftlog.debug('MTingHaerbinRule.canTing chunJiaConfig:', chunJiaConfig, ' can not win tile:', winNode['winTile'], ', continue....') continue if self.getTableConfig(MTDefine.YISE_CAN_TING, 0) != 1: # 清一色不可以听牌/和牌 colorCount = MTile.getColorCount(tileArr) if colorCount == 1: # 清一色不能和牌 ftlog.debug('MTingHaerbinRule.canTing colorCount:', colorCount, ' can not win, continue....') continue zhongCount = tileArr[MTile.TILE_HONG_ZHONG] # ftlog.debug( 'MTingHaerbinRule.canTing hongzhong count: ', zhongCount ) # 检查牌中的幺/九 yaoCount = tileArr[MTile.TILE_ONE_WAN] + tileArr[MTile.TILE_ONE_TONG] + tileArr[MTile.TILE_ONE_TIAO] jiuCount = tileArr[MTile.TILE_NINE_WAN] + tileArr[MTile.TILE_NINE_TONG] + tileArr[MTile.TILE_NINE_TIAO] # ftlog.debug( 'MTingHaerbinRule.canTing yaoCount:', yaoCount, ' jiuCount:', jiuCount ) if (yaoCount + jiuCount + zhongCount) == 0: continue patterns = winNode['pattern'] checkKeCount = keCount + self.getKeCount(patterns) checkShunCount = shunCount + self.getShunCount(patterns) ftlog.debug('MTingHaerbinRule.canTing keCount:', keCount, ' shunCount:', shunCount) if checkKeCount and checkShunCount: newWinNodes.append(winNode) if len(newWinNodes) > 0: newTingResult = {} newTingResult['dropTile'] = tingResult['dropTile'] newTingResult['winNodes'] = newWinNodes newTingResults.append(newTingResult) return len(newTingResults) > 0, newTingResults