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 getHandTilesValue(cls, tiles_player_hand, tiles_left): """计算手牌价值 返回值: 1)每张牌的价值 2)手牌花色个数的数组 """ tiles_player_Arr = MTile.changeTilesToValueArr(tiles_player_hand[MHand.TYPE_HAND]) tiles_left_Arr = MTile.changeTilesToValueArr(tiles_left) # 权值初始化 tiles_value_Arr = [0 for _ in range(40)] for index in range(MTile.TILE_MAX_VALUE): if tiles_player_Arr[index] == 0: continue tiles_value_Arr[index] = tiles_player_Arr[index] * 4 + tiles_left_Arr[index] if index < 30: if index % 10 < 9: tiles_value_Arr[index] += tiles_player_Arr[index + 1] * 3 if index % 10 < 8: tiles_value_Arr[index] += tiles_player_Arr[index + 2] * 2 if index % 10 > 1: tiles_value_Arr[index] += tiles_player_Arr[index - 1] * 3 if index % 10 > 2: tiles_value_Arr[index] += tiles_player_Arr[index - 2] * 2 return tiles_value_Arr, tiles_player_Arr
def canTing(cls, tiles, leftTiles, winRule, cur_tile, magicTiles=list()): """ 判断所有的听牌情况 :param tiles 手牌 :param leftTiles 剩余未发的牌 :param winRule: :param cur_tile: :param magicTiles: :type tiles HandTiles :return """ ftlog.debug('MTile.changeTilesToValueArr', tiles[MHand.TYPE_HAND]) handTileArr = MTile.changeTilesToValueArr(tiles[MHand.TYPE_HAND]) leftTileArr = MTile.changeTilesToValueArr(leftTiles) leftTileCount = len(leftTileArr) ftlog.debug('MTing.canTing leftTileArr:', leftTileArr, ' leftTileCount:', leftTileCount) result = [] for tile, _ in handTileArr.tile_items(): # 打出一张牌后可以听牌 newTiles = HandTiles.clone(tiles) newTiles.dropHand(tile) resultNode = cls.canWinAddOneTile(leftTileArr, leftTileCount, newTiles, winRule, 0, magicTiles) if len(resultNode) > 0: winNode = {'dropTile': tile, 'winNodes': resultNode} result.append(winNode) return len(result) > 0, result
def getHandTilesValue(cls, tiles_player_hand, tiles_left): """计算手牌价值 返回值: 1)每张牌的价值 2)手牌花色个数的数组 """ tiles_player_Arr = MTile.changeTilesToValueArr( tiles_player_hand[MHand.TYPE_HAND]) tiles_left_Arr = MTile.changeTilesToValueArr(tiles_left) # 权值初始化 tiles_value_Arr = [0 for _ in range(40)] for index in range(MTile.TILE_MAX_VALUE): if tiles_player_Arr[index] == 0: continue tiles_value_Arr[ index] = tiles_player_Arr[index] * 4 + tiles_left_Arr[index] if index < 30: if index % 10 < 9: tiles_value_Arr[index] += tiles_player_Arr[index + 1] * 3 if index % 10 < 8: tiles_value_Arr[index] += tiles_player_Arr[index + 2] * 2 if index % 10 > 1: tiles_value_Arr[index] += tiles_player_Arr[index - 1] * 3 if index % 10 > 2: tiles_value_Arr[index] += tiles_player_Arr[index - 2] * 2 return tiles_value_Arr, tiles_player_Arr
def isHu(self, tiles, tile, isTing, getTileType, magicTiles=list(), tingNodes=list()): result, rePattern = MWin.isHu(tiles[MHand.TYPE_HAND]) if not result: return False, [] # 分析花色 tileArr = MTile.changeTilesToValueArr(MHand.copyAllTilesToList(tiles)) colors = MTile.getColorCount(tileArr) ftlog.debug('MWinRuleSichuan.isHu colors:', colors) if colors <= 2: # 花色缺门,可以和 return True, rePattern return False, []
def isHu(cls, hand_tiles, magicTiles=list()): """ 胡牌判断,只判断手牌,杠牌,吃牌,碰牌不在内 杠牌、吃牌、碰牌已成型,不用另外计算 * 肯定包含将牌 * 剩下的牌里不会有暗杠牌 * 杠牌/吃牌/碰牌是已经成型的牌,按成型的样式计算积分,不再重新计算 :param magicTiles 赖子牌 :return 是否胡了 """ tileArr = MTile.changeTilesToValueArr(hand_tiles) magicArr = [] for magicTile in magicTiles: magicArr.extend([magicTile for _ in range(tileArr[magicTile])]) tileArr[magicTile] = 0 resultArr = [] tileTypes = [MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG] hasJiang = False winResult = False for tileType in tileTypes: winResult, hasJiang, _tArr, _rArr, _mArr = cls.isHuWithMagic(tileArr, resultArr, magicArr, hasJiang, tileType) if not winResult: return False, [] else: tileArr = copy.deepcopy(_tArr) resultArr = copy.deepcopy(_rArr) magicArr = copy.deepcopy(_mArr) if winResult and not hasJiang and len(magicArr) >= 2: hasJiang = True return hasJiang and winResult, resultArr
def isHu(self, tiles, last_tile, isTing, getTileType, magicTiles=list(), tingNodes=list()): hu_tiles = HuTiles() handTileArr = MTile.changeTilesToValueArr(tiles[MHand.TYPE_HAND]) if not M14.find_first( handTileArr, hu_tiles, M14.is7Dui if self.dui7 else M14.justPass, M14.isPHu, ): # 基本的胡牌类型都挂了 return False, None dui_list = handTileArr.tiles_dui() if len(dui_list) == 0: # 没有将牌 return False, [] if len(hu_tiles) != 7 and not set( zip(*dui_list)[0]) & MWinRuleJiNan.JIANG: # 没有2,5,8将牌 return False, [] return True, hu_tiles
def isPairs(cls, tiles, magicTiles): if len(tiles[MHand.TYPE_CHI]) != 0: return False if len(tiles[MHand.TYPE_PENG]) != 0: return False if len(tiles[MHand.TYPE_GANG]) != 0: return False pairTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) haveMagicCount = 0 for magicTile in magicTiles: while magicTile in pairTiles: pairTiles.remove(magicTile) haveMagicCount += 1 ftlog.debug("win_rule_zhaotong::isPairs pairTiles = ", pairTiles, "haveMagicCount =", haveMagicCount) tileArr = MTile.changeTilesToValueArr(pairTiles) for count in tileArr: if count % 2 == 0: continue else: if haveMagicCount <= 0: return False else: haveMagicCount -= 1 continue return True
def isPairs(cls, tiles, magicTiles): if len(tiles[MHand.TYPE_CHI]) != 0: return False if len(tiles[MHand.TYPE_PENG]) != 0: return False if len(tiles[MHand.TYPE_GANG]) != 0: return False pairTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) haveMagicCount = 0 for magicTile in magicTiles: while magicTile in pairTiles: pairTiles.remove(magicTile) haveMagicCount += 1 ftlog.debug("win_rule_zhaotong::isPairs pairTiles = ", pairTiles, "haveMagicCount =", haveMagicCount) tileArr = MTile.changeTilesToValueArr(pairTiles) for count in tileArr: if count % 2 == 0: continue else: if haveMagicCount <= 0: return False else: haveMagicCount -= 1 continue return True
def hasChi(cls, tiles, tile): """是否可以吃 吃牌的判断中,tile已经在tiles中 参数: tiles - 手牌 tile - 待吃的牌 返回值:吃牌选择 最多三种解 例子: [[2, 3, 4], [3, 4, 5], [4, 5, 6 """ tileArr = MTile.changeTilesToValueArr(tiles) result = [] # 第一种情况 001 if (tile % 10) >= 3: if tileArr[tile - 2] > 0 and tileArr[tile - 1] > 0 and tileArr[tile] > 0: solution = [tile - 2, tile - 1, tile] result.append(solution) # 第二种情况 010 if (tile % 10) >= 2 and (tile % 10) < 9: if tileArr[tile - 1] > 0 and tileArr[tile] > 0 and tileArr[tile + 1] > 0: solution = [tile - 1, tile, tile + 1] result.append(solution) # 第三种情况 100 if (tile % 10) < 8: if tileArr[tile] > 0 and tileArr[tile + 1] > 0 and tileArr[tile + 2] > 0: solution = [tile, tile + 1, tile + 2] result.append(solution) return result
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 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 isLanPaiHu(cls, tiles, magicTiles): """先做简单的牌型检查,如果符合再进行细节判断""" if len(tiles[MHand.TYPE_CHI]) != 0: return False if len(tiles[MHand.TYPE_PENG]) != 0: return False if len(tiles[MHand.TYPE_GANG]) != 0: return False # 去除手牌赖子,并计数 haveMagicCount = 0 lanpaiTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in lanpaiTiles: lanpaiTiles.remove(magicTile) haveMagicCount += 1 tileArr = MTile.changeTilesToValueArr(lanpaiTiles) # 去除赖子后手牌数不能有超过2张的 for count in tileArr: if count <= 1: continue else: return False # 去除赖子后不重复字牌加赖子数要大于等于5,并且可用赖子数=字牌+赖子-5 # canUseMagicCount = haveMagicCount tempFengTiles = MTile.traverseTile(MTile.TILE_FENG) fengArr = tileArr[tempFengTiles[0]:tempFengTiles[len(tempFengTiles) - 1] + 1] # 检查字牌种类和每种的数量,之前因为已经判断过数量小于等于1,这里不再重复 fengCount = 0 for count in fengArr: if count == 1: fengCount += 1 # 如果字牌每种不超过1张且有五种,开始判断其它花色 if fengCount + haveMagicCount >= 5: # 分别判断三种花色 if cls.checkBukao(tileArr, MTile.TILE_WAN) and cls.checkBukao( tileArr, MTile.TILE_TONG) and cls.checkBukao( tileArr, MTile.TILE_TIAO): return True else: return False return False
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 isLanPaiHu(cls, tiles, magicTiles): """先做简单的牌型检查,如果符合再进行细节判断""" if len(tiles[MHand.TYPE_CHI]) != 0: return False if len(tiles[MHand.TYPE_PENG]) != 0: return False if len(tiles[MHand.TYPE_GANG]) != 0: return False # 去除手牌赖子,并计数 haveMagicCount = 0 lanpaiTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in lanpaiTiles: lanpaiTiles.remove(magicTile) haveMagicCount += 1 tileArr = MTile.changeTilesToValueArr(lanpaiTiles) # 去除赖子后手牌数不能有超过2张的 for count in tileArr: if count <= 1: continue else: return False # 去除赖子后不重复字牌加赖子数要大于等于5,并且可用赖子数=字牌+赖子-5 # canUseMagicCount = haveMagicCount tempFengTiles = MTile.traverseTile(MTile.TILE_FENG) fengArr = tileArr[tempFengTiles[0]:tempFengTiles[len(tempFengTiles) - 1] + 1] # 检查字牌种类和每种的数量,之前因为已经判断过数量小于等于1,这里不再重复 fengCount = 0 for count in fengArr: if count == 1: fengCount += 1 # 如果字牌每种不超过1张且有五种,开始判断其它花色 if fengCount + haveMagicCount >= 5: # 分别判断三种花色 if cls.checkBukao(tileArr, MTile.TILE_WAN) and cls.checkBukao(tileArr, MTile.TILE_TONG) and cls.checkBukao( tileArr, MTile.TILE_TIAO): return True else: return False return False
def isLanPaiCheck(self, tiles, magicTiles): """先做简单的牌型检查,如果符合再进行细节判断""" if len(tiles[MHand.TYPE_HAND]) != 14: return False, 0, 0 ftlog.debug("isLanPaiCheck handcard is ok") # 去除手牌赖子,并计数 haveMagicCount = 0 lanpaiTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in lanpaiTiles: lanpaiTiles.remove(magicTile) haveMagicCount += 1 ftlog.debug("isLanPaiCheck haveMagicCount =", haveMagicCount, "lanpaiTiles =", lanpaiTiles) tileArr = MTile.changeTilesToValueArr(lanpaiTiles) # 去除赖子后手牌数不能有超过2张的 for count in tileArr: if count <= 1: continue else: return False, 0, 0 # 去除赖子后不重复字牌加赖子数要大于等于5,并且可用赖子数=字牌+赖子-5 # canUseMagicCount = haveMagicCount tempFengTiles = MTile.traverseTile(MTile.TILE_FENG) fengArr = tileArr[tempFengTiles[0]:tempFengTiles[len(tempFengTiles) - 1] + 1] ftlog.debug("isLanPaiCheck fengArr =", fengArr) # 检查字牌种类和每种的数量,之前因为已经判断过数量小于等于1,这里不再重复 fengCount = 0 for count in fengArr: if count == 1: fengCount += 1 # 如果字牌每种不超过1张且有五种,开始判断其它花色 if fengCount + haveMagicCount >= 5: # 分别判断三种花色 ftlog.debug("isLanPaiCheck checkBukao begin tileArr = ", tileArr) if self.checkBukao(tileArr, MTile.TILE_WAN) and self.checkBukao(tileArr, MTile.TILE_TONG) and self.checkBukao( tileArr, MTile.TILE_TIAO): return True, fengCount, haveMagicCount else: return False, 0, 0 return False, 0, 0
def hasAnGang(cls, tiles, tile): """自摸是否可以暗杠 判断杠牌时,tile已经加入tiles中 tiles - 手牌 tile - 待杠的牌 """ tileArr = MTile.changeTilesToValueArr(tiles) if tileArr[tile] == 4: return True return False
def isHu(self, tiles, tile, isTing, getTileType, magicTiles=list(), tingNodes=list()): result, rePattern = MWin.isHu(tiles[MHand.TYPE_HAND]) if not result: return False, [] # 分析花色 tileArr = MTile.changeTilesToValueArr(MHand.copyAllTilesToList(tiles)) colors = MTile.getColorCount(tileArr) ftlog.debug('MWinRuleSichuan.isHu colors:', colors) if colors <= 2: # 花色缺门,可以和 return True, rePattern return False, []
def hasPeng(cls, tiles, tile): """ 是否可以碰 判断之前tile已经加到tiles中 tiles - 手牌 tile - 待碰的牌 """ tileArr = MTile.changeTilesToValueArr(tiles) if tileArr[tile] >= 3: return True return False
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 包含所有的牌 """ super(AllColorDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG] # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles(MTile.getTiles(self.__card_colors)) ftlog.debug(self.cardTiles)
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 四川玩法,只有三门,没有风 """ super(SanMenNoFengDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO] # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles(MTile.getTiles(self.__card_colors)) ftlog.debug(self.cardTiles)
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 四川玩法,只有三门,没有风 """ super(SanMenNoFengDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO] # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles(MTile.getTiles(self.__card_colors)) ftlog.debug(self.cardTiles)
def hasPeng(self, tiles, tile): """ 是否有碰牌解 参数说明; tiles - 玩家的所有牌,包括手牌,吃牌,碰牌,杠牌,胡牌 tile - 待碰的牌 """ pengSolutions = [] normalPeng = MPeng.hasPeng(tiles[MHand.TYPE_HAND], tile) if normalPeng: pengSolutions.append([tile, tile, tile]) magics = self.tableTileMgr.getMagicTiles(False) tileArr = MTile.changeTilesToValueArr(tiles[MHand.TYPE_HAND]) tileArr, magicTiles = self.tableTileMgr.exculeMagicTiles( tileArr, magics) magicCount = len(magicTiles) if magicCount == 0: return pengSolutions if not self.tableTileMgr.canUseMagicTile(MTableState.TABLE_STATE_PENG): return pengSolutions magicPengMaxCount = self.tableTileMgr.magicPengMaxCount if magicPengMaxCount > 3 or magicPengMaxCount < 0: magicPengMaxCount = 3 ftlog.debug('MPengRule.hasPeng tile:', tile, ' tileCount:', tileArr[tile], ' magicCount:', magicCount, 'magicPengMaxCount', magicPengMaxCount) if (magicCount == 0) or (tileArr[tile] == 0) or (magicPengMaxCount <= 0): return pengSolutions if magicCount >= 1 and tileArr[tile] >= 2 and magicPengMaxCount >= 1: # 使用一个癞子 pattern1 = [tile, tile, magicTiles[0]] pattern1.sort() pengSolutions.append(pattern1) if magicCount >= 2 and tileArr[tile] >= 1 and magicPengMaxCount >= 2: # 使用两个癞子 pattern2 = [tile, magicTiles[0], magicTiles[1]] pattern2.sort() pengSolutions.append(pattern2) return pengSolutions
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 包含所有的牌 """ super(AllColorDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [ MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG ] # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles(MTile.getTiles(self.__card_colors)) ftlog.debug(self.cardTiles)
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 多余红中麻将/哈尔滨麻将 包括万/筒/条三门+红中 """ super(SanMenWithZhonggDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG] # 风牌的描述 self.__feng_details = MTile.FENG_ZHONG # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles(MTile.getTiles(self.__card_colors, self.__feng_details))
def isWuDuiHu(self, allTiles, winTile): huSeatId = -1 for seatId, playerTiles in enumerate(allTiles): handTiles = playerTiles[MHand.TYPE_HAND] handTilesArr = MTile.changeTilesToValueArr(handTiles) huSeatId = seatId for handTile in handTiles: if handTilesArr[handTile] >= 2: huSeatId = -1 break if huSeatId >= 0: return True, huSeatId return False, -1
def isWuDuiHu(self, allTiles, winTile): huSeatId = -1 for seatId, playerTiles in enumerate(allTiles): handTiles = playerTiles[MHand.TYPE_HAND] handTilesArr = MTile.changeTilesToValueArr(handTiles) huSeatId = seatId for handTile in handTiles: if handTilesArr[handTile] >= 2: huSeatId = -1 break if huSeatId >= 0: return True, huSeatId return False, -1
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 卡五星 包括筒/条两门+中发白 """ super(TongTiaoWithZFBDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG] # 风牌的描述 self.__feng_details = MTile.FENG_ZHONG | MTile.FENG_FA | MTile.FENG_BAI # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles(MTile.getTiles(self.__card_colors, self.__feng_details))
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 鸡西麻将三人玩法 包括筒/条三门+红中 """ super(TongTiaoWithZhonggDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG] # 风牌的描述 self.__feng_details = MTile.FENG_ZHONG # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles(MTile.getTiles(self.__card_colors, self.__feng_details))
def hasPeng(self, tiles, tile): """ 是否有碰牌解 参数说明; tiles - 玩家的所有牌,包括手牌,吃牌,碰牌,杠牌,胡牌 tile - 待碰的牌 """ pengSolutions = [] normalPeng = MPeng.hasPeng(tiles[MHand.TYPE_HAND], tile) if normalPeng: pengSolutions.append([tile, tile, tile]) magics = self.tableTileMgr.getMagicTiles(False) tileArr = MTile.changeTilesToValueArr(tiles[MHand.TYPE_HAND]) tileArr, magicTiles = self.tableTileMgr.exculeMagicTiles(tileArr, magics) magicCount = len(magicTiles) if magicCount == 0: return pengSolutions if not self.tableTileMgr.canUseMagicTile(MTableState.TABLE_STATE_PENG): return pengSolutions magicPengMaxCount = self.tableTileMgr.magicPengMaxCount if magicPengMaxCount > 3 or magicPengMaxCount < 0: magicPengMaxCount = 3 ftlog.debug('MPengRule.hasPeng tile:', tile , ' tileCount:', tileArr[tile] , ' magicCount:', magicCount , 'magicPengMaxCount', magicPengMaxCount) if (magicCount == 0) or (tileArr[tile] == 0) or (magicPengMaxCount <= 0): return pengSolutions if magicCount >= 1 and tileArr[tile] >= 2 and magicPengMaxCount >= 1: # 使用一个癞子 pattern1 = [tile, tile, magicTiles[0]] pattern1.sort() pengSolutions.append(pattern1) if magicCount >= 2 and tileArr[tile] >= 1 and magicPengMaxCount >= 2: # 使用两个癞子 pattern2 = [tile, magicTiles[0], magicTiles[1]] pattern2.sort() pengSolutions.append(pattern2) return pengSolutions
def isPairsCheck(self, tiles, magicTiles): """判断七对型胡牌""" # 不能吃碰杠 if len(tiles[MHand.TYPE_CHI]) != 0: return False, 0, 0, 0, 0 if len(tiles[MHand.TYPE_PENG]) != 0: return False, 0, 0, 0, 0 if len(tiles[MHand.TYPE_GANG]) != 0: return False, 0, 0, 0, 0 # 用赖子给其他牌配对 pairTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) fourCount = 0 specialFourCount = 0 twoCount = 0 haveMagicCount = 0 for magicTile in magicTiles: while magicTile in pairTiles: pairTiles.remove(magicTile) haveMagicCount += 1 tileArr = MTile.changeTilesToValueArr(pairTiles) for count in tileArr: if count % 2 == 0: if count == 4: fourCount += 1 elif count == 2: twoCount += 1 continue else: if haveMagicCount <= 0: return False, 0, 0, 0, 0 else: haveMagicCount -= 1 if count == 3: specialFourCount += 1 fourCount += 1 elif count == 1: twoCount += 1 continue # 配对结束,赖子必须剩偶数个 if haveMagicCount % 2 == 0: # 尽量凑4个的 while haveMagicCount >= 2 and twoCount >= 1: twoCount -= 1 specialFourCount += 1 fourCount += 1 haveMagicCount -= 2 return True, haveMagicCount, fourCount, twoCount, specialFourCount return False, 0, 0, 0, 0
def getPaoqiaomobaBaCount(self): """ 跑恰摸八中的八:筒、条、风这三门牌里面,和牌时,有几门达到8张 每种花色,8张加1分,9张加2分,以此类推 """ baCount = 0 if self.tableConfig.get(MTDefine.PAOQIAMOBA, 0): colorCountArr = [0, 0, 0, 0] for tile in self.__player_all_tiles_arr[self.winSeatId]: color = MTile.getColor(tile) colorCountArr[color] += 1 for colorCount in colorCountArr: if colorCount >= 8: baCount += colorCount - 7 ftlog.debug('MKawuxingOneResult.getPaoqiaomobaBaCount baCount: ', baCount) return baCount
def isPairsCheck(self, tiles, magicTiles): """判断七对型胡牌""" # 不能吃碰杠 if len(tiles[MHand.TYPE_CHI]) != 0: return False, 0, 0, 0 if len(tiles[MHand.TYPE_PENG]) != 0: return False, 0, 0, 0 if len(tiles[MHand.TYPE_GANG]) != 0: return False, 0, 0, 0 # 用赖子给其他牌配对 pairTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) fourCount = 0 twoCount = 0 haveMagicCount = 0 for magicTile in magicTiles: while magicTile in pairTiles: pairTiles.remove(magicTile) haveMagicCount += 1 tileArr = MTile.changeTilesToValueArr(pairTiles) for count in tileArr: if count % 2 == 0: if count == 4: fourCount += 1 elif count == 2: twoCount += 1 continue else: if haveMagicCount <= 0: return False, 0, 0, 0 else: haveMagicCount -= 1 if count == 3: fourCount += 1 elif count == 1: twoCount += 1 continue # 配对结束,赖子必须剩偶数个 if haveMagicCount % 2 == 0: # 尽量凑4个的 while haveMagicCount >= 2 and twoCount >= 1: twoCount -= 1 fourCount += 1 haveMagicCount -= 2 return True, haveMagicCount, fourCount, twoCount return False, 0, 0, 0
def isQingyise(self): """ 清一色:由同一门花色(筒子或条子)组成的和牌牌型 """ colorArr = [0, 0, 0, 0] for tile in self.__player_all_tiles_arr[self.winSeatId]: color = MTile.getColor(tile) colorArr[color] = 1 colorCount = 0 for eachColor in colorArr: if eachColor: colorCount += 1 if colorCount > 1: ftlog.debug('MKawuxingOneResult.isQingyise result: False') return False ftlog.debug('MKawuxingOneResult.isQingyise result: True') return True
def getPaoqiaomobaBaCount(self): """ 跑恰摸八中的八:筒、条、风这三门牌里面,和牌时,有几门达到8张 每种花色,8张加1分,9张加2分,以此类推 """ baCount = 0 if self.tableConfig.get(MTDefine.PAOQIAMOBA, 0): colorCountArr = [0, 0, 0, 0] for tile in self.__player_all_tiles_arr[self.winSeatId]: color = MTile.getColor(tile) colorCountArr[color] += 1 for colorCount in colorCountArr: if colorCount >= 8: baCount += colorCount - 7 ftlog.debug('MKawuxingOneResult.getPaoqiaomobaBaCount baCount: ', baCount) return baCount
def isQidui(self, tiles): handTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) handTilesArr = MTile.changeTilesToValueArr(handTiles) if len(handTiles) != 14: return False, [] pattern = [] for tile in range(MTile.TILE_MAX_VALUE): if handTilesArr[tile] == 1 or handTilesArr[tile] == 3: # 只要出现单数,必然不是七对 return False, [] if handTilesArr[tile] == 2: pattern.append([tile, tile]) if handTilesArr[tile] == 4: # 和KawuxingOneResult配合 pattern.extend([[tile, tile], [tile, tile]]) return True, pattern
def isHu(self, tiles, last_tile, isTing, getTileType, magicTiles=list(), tingNodes=list()): hu_tiles = HuTiles() handTileArr = MTile.changeTilesToValueArr(tiles[MHand.TYPE_HAND]) if not M14.find_first(handTileArr, hu_tiles, M14.is7Dui if self.dui7 else M14.justPass, M14.isPHu, ): # 基本的胡牌类型都挂了 return False, None dui_list = handTileArr.tiles_dui() if len(dui_list) == 0: # 没有将牌 return False, [] if len(hu_tiles) != 7 and not set(zip(*dui_list)[0]) & MWinRuleJiNan.JIANG: # 没有2,5,8将牌 return False, [] return True, hu_tiles
def __init__(self): """初始化 子类在自己的初始化方法里,初始化麻将牌池范围,准备发牌 卡五星 包括筒/条两门+中发白 """ super(TongTiaoWithZFBDealer, self).__init__() # 本玩法包含的花色 self.__card_colors = [ MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG ] # 风牌的描述 self.__feng_details = MTile.FENG_ZHONG | MTile.FENG_FA | MTile.FENG_BAI # 花色数量 self.__card_count = len(self.__card_colors) # 初始化本玩法包含的牌 self.setCardTiles( MTile.getTiles(self.__card_colors, self.__feng_details))
def isQingyise(self): """ 清一色:由同一门花色(筒子或条子)组成的和牌牌型 """ colorArr = [0, 0, 0, 0] for tile in self.__player_all_tiles_arr[self.winSeatId]: color = MTile.getColor(tile) colorArr[color] = 1 colorCount = 0 for eachColor in colorArr: if eachColor: colorCount += 1 if colorCount > 1: ftlog.debug('MKawuxingOneResult.isQingyise result: False') return False ftlog.debug('MKawuxingOneResult.isQingyise result: True') return True
def checkBukao(cls, tileArr, tileType): """烂牌检查三种花色的不靠""" tempTiles = MTile.traverseTile(tileType) colorArr = tileArr[tempTiles[0]:tempTiles[len(tempTiles) - 1] + 1] colorTiles = [] for i in range(len(colorArr)): if colorArr[i] > 0: colorTiles.append(i) if len(colorTiles) > 3: return False # 然后只需要判断不靠即可 elif len(colorTiles) == 2: if (colorTiles[0] - colorTiles[1]) % 3 != 0: return False elif len(colorTiles) == 3: if (colorTiles[0] - colorTiles[1]) % 3 != 0 or (colorTiles[0] - colorTiles[2]) % 3 != 0 or ( colorTiles[1] - colorTiles[2]) % 3 != 0: return False return True
def checkBukao(cls, tileArr, tileType): """烂牌检查三种花色的不靠""" tempTiles = MTile.traverseTile(tileType) colorArr = tileArr[tempTiles[0]:tempTiles[len(tempTiles) - 1] + 1] colorTiles = [] for i in range(len(colorArr)): if colorArr[i] > 0: colorTiles.append(i) if len(colorTiles) > 3: return False # 然后只需要判断不靠即可 elif len(colorTiles) == 2: if (colorTiles[0] - colorTiles[1]) % 3 != 0: return False elif len(colorTiles) == 3: if (colorTiles[0] - colorTiles[1]) % 3 != 0 or ( colorTiles[0] - colorTiles[2]) % 3 != 0 or ( colorTiles[1] - colorTiles[2]) % 3 != 0: return False return True
def calcFanDaduizi(self, fanData, nowTiles, magicTiles, magicTileCount, winTile, seatId, lastSeatId): """计算大对子番型""" fan = fanData.get('fan', 0) patterns = fanData.get('patterns', []) isUnique = fanData.get('isUnique', False) isSpecial = fanData.get('isSpecial', False) isDaduizi = False # 大对子,门前不能有吃,手牌多加一个赖子,能保证都是3张 if len(nowTiles[MHand.TYPE_CHI]) == 0: duiziTiles = copy.deepcopy(nowTiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in duiziTiles: duiziTiles.remove(magicTile) # 如果点炮胡,需要给牌堆里加回去一张赖子,并当普通牌处理 if seatId != lastSeatId and winTile in magicTiles: duiziTiles.append(winTile) duiziArr = MTile.changeTilesToValueArr(duiziTiles) ftlog.debug("MYunnanOneResult duiziArr = ", duiziArr) cardTypeCount = 0 # 假设多一张赖子 duiziMagicCount = magicTileCount + 1 for index in range(len(duiziArr)): if duiziArr[index] != 0: cardTypeCount += 1 if duiziArr[index] < 3: duiziMagicCount = duiziMagicCount - (3 - duiziArr[index]) if cardTypeCount <= 5 and duiziMagicCount >= 0: if not isUnique: patterns.append(self.fanXing[self.DUIDUIHU]['name']) fan += self.fanXing[self.DUIDUIHU]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) isDaduizi = True isSpecial = True fanData['isUnique'] = isUnique fanData['fan'] = fan fanData['isSpecial'] = isSpecial return fan, patterns, isUnique, isDaduizi
def shuffle(self, goodPointCount, cardCountPerHand): """参数说明 goodPointCount : 好牌点的人数 cardCountPerHand : 每手牌的麻将牌张数 """ # 初始化一下cardTiles,因为每设置一次好牌点都会从里面弹出13张牌 self.setCardTiles(MTile.getTiles(self.__card_colors)) for color in self.__card_colors: random.shuffle(self.cardTiles[color]) for _ in range(goodPointCount): self.addTiles(self.getGoodCard(cardCountPerHand)) left_tiles = [] for color in self.__card_colors: left_tiles.extend(self.cardTiles[color]) # 对剩余的牌洗牌 random.shuffle(left_tiles) self.addTiles(left_tiles) return self.tiles
def shuffle(self, goodPointCount, cardCountPerHand): """参数说明 goodPointCount : 好牌点的人数 cardCountPerHand : 每手牌的麻将牌张数 """ # 初始化一下cardTiles,因为每设置一次好牌点都会从里面弹出13张牌 self.setCardTiles(MTile.getTiles(self.__card_colors)) for color in self.__card_colors: random.shuffle(self.cardTiles[color]) for _ in range(goodPointCount): self.addTiles(self.getGoodCard(cardCountPerHand)) left_tiles = [] for color in self.__card_colors: left_tiles.extend(self.cardTiles[color]) # 对剩余的牌洗牌 random.shuffle(left_tiles) self.addTiles(left_tiles) return self.tiles
def isHu(cls, hand_tiles, magicTiles=list()): """ 胡牌判断,只判断手牌,杠牌,吃牌,碰牌不在内 杠牌、吃牌、碰牌已成型,不用另外计算 * 肯定包含将牌 * 剩下的牌里不会有暗杠牌 * 杠牌/吃牌/碰牌是已经成型的牌,按成型的样式计算积分,不再重新计算 :param magicTiles 赖子牌 :return 是否胡了 """ tileArr = MTile.changeTilesToValueArr(hand_tiles) magicArr = [] for magicTile in magicTiles: magicArr.extend([magicTile for _ in range(tileArr[magicTile])]) tileArr[magicTile] = 0 resultArr = [] tileTypes = [ MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO, MTile.TILE_FENG ] hasJiang = False winResult = False for tileType in tileTypes: winResult, hasJiang, _tArr, _rArr, _mArr = cls.isHuWithMagic( tileArr, resultArr, magicArr, hasJiang, tileType) if not winResult: return False, [] else: tileArr = copy.deepcopy(_tArr) resultArr = copy.deepcopy(_rArr) magicArr = copy.deepcopy(_mArr) if winResult and not hasJiang and len(magicArr) >= 2: hasJiang = True return hasJiang and winResult, resultArr
def hasChi(cls, tiles, tile): """是否可以吃 吃牌的判断中,tile已经在tiles中 参数: tiles - 手牌 tile - 待吃的牌 返回值:吃牌选择 最多三种解 例子: [[2, 3, 4], [3, 4, 5], [4, 5, 6 """ tileArr = MTile.changeTilesToValueArr(tiles) result = [] # 第一种情况 001 if (tile % 10) >= 3: if tileArr[tile - 2] > 0 and tileArr[tile - 1] > 0 and tileArr[tile] > 0: solution = [tile - 2, tile - 1, tile] result.append(solution) # 第二种情况 010 if (tile % 10) >= 2 and (tile % 10) < 9: if tileArr[tile - 1] > 0 and tileArr[tile] > 0 and tileArr[tile + 1] > 0: solution = [tile - 1, tile, tile + 1] result.append(solution) # 第三种情况 100 if (tile % 10) < 8: if tileArr[tile] > 0 and tileArr[tile + 1] > 0 and tileArr[tile + 2] > 0: solution = [tile, tile + 1, tile + 2] result.append(solution) return result
def isBu(cls, tileArr, resultArr, magicArr, tileType, hasJiang): """ 判断某个花色是否是三朴,缺的牌从癞子中获取,如果没有癞子牌了,也形不成三朴,和牌失败 """ if 0 == cls.getCardNumByType(tileArr, tileType): # 这个花色没有牌 return True, hasJiang # ftlog.debug('check card:', MTile.traverseTile(tileType)) for tileIndex in MTile.traverseTile(tileType): if tileArr[tileIndex] == 0: continue if tileArr[tileIndex] >= 3: # 刻,没有占用癞子 tileArr[tileIndex] -= 3 resultTmp, hasJiang = cls.isBu(tileArr, resultArr, magicArr, tileType, hasJiang) if resultTmp: resultArr.append([tileIndex, tileIndex, tileIndex]) return True, hasJiang # 还原手牌,继续判断 tileArr[tileIndex] += 3 if (tileArr[tileIndex] == 2) and (len(magicArr) >= 1): # 对子,尝试加一张癞子组成刻 tileArr[tileIndex] -= 2 mTile = magicArr.pop(-1) resultTmp, hasJiang = cls.isBu(tileArr, resultArr, magicArr, tileType, hasJiang) if resultTmp: resultArr.append([tileIndex, tileIndex, mTile]) return True, hasJiang # 还原手牌,继续判断 tileArr[tileIndex] += 2 magicArr.append(mTile) if (tileArr[tileIndex] == 1) and (len(magicArr) >= 2): # 单张,尝试加两张癞子组成刻 tileArr[tileIndex] -= 1 mTile1 = magicArr.pop(-1) mTile2 = magicArr.pop(-1) resultTmp, hasJiang = cls.isBu(tileArr, resultArr, magicArr, tileType, hasJiang) if resultTmp: resultArr.append([tileIndex, mTile1, mTile2]) return True, hasJiang # 还原手牌,继续判断 tileArr[tileIndex] += 1 magicArr.append(mTile1) magicArr.append(mTile2) if not hasJiang and tileArr[tileIndex] > 0 and (tileArr[tileIndex] + len(magicArr) >= 2): # 凑对了 tileArr[tileIndex] -= 1 isMagicJiang = False jiangTile = tileIndex if tileArr[tileIndex] > 0: tileArr[tileIndex] -= 1 else: isMagicJiang = True jiangTile = magicArr.pop(-1) oldJiang = hasJiang # 当前的对子当将测测是否成胡 resultTmp, hasJiang = cls.isBu(tileArr, resultArr, magicArr, tileType, True) if resultTmp: resultArr.append([tileIndex, jiangTile]) hasJiang = True return True, hasJiang else: # 还原将牌标记 hasJiang = oldJiang # 还原手牌 tileArr[tileIndex] += 1 if isMagicJiang: magicArr.append(jiangTile) else: tileArr[tileIndex] += 1 if tileIndex >= MTile.TILE_DONG_FENG: # 风箭牌不能组成顺 return False, hasJiang # 提取顺牌组合 if tileArr[tileIndex] > 0: # 测试顺子 0 1 2 if MTile.getValue(tileIndex) <= 7: tile0 = tileIndex needMagic = 0 is1Magic = False is2Magic = False if tileArr[tileIndex + 1] == 0: needMagic += 1 is1Magic = True if tileArr[tileIndex + 2] == 0: needMagic += 1 is2Magic = True if needMagic <= len(magicArr): pattern = [tile0, None, None] tileArr[tileIndex] -= 1 if is1Magic: pattern[1] = (magicArr.pop(-1)) else: pattern[1] = (tileIndex + 1) tileArr[tileIndex + 1] -= 1 if is2Magic: pattern[2] = (magicArr.pop(-1)) else: pattern[2] = (tileIndex + 2) tileArr[tileIndex + 2] -= 1 resultTmp, hasJiang = cls.isBu(tileArr, resultArr, magicArr, tileType, hasJiang) if resultTmp: resultArr.append(pattern) return True, hasJiang # 还原手牌 tileArr[tileIndex] += 1 if is1Magic: magicArr.append(pattern[1]) else: tileArr[tileIndex + 1] += 1 if is2Magic: magicArr.append(pattern[2]) else: tileArr[tileIndex + 2] += 1 # 测试顺子 -1 0 1 if 8 >= MTile.getValue(tileIndex) >= 2: tile1 = tileIndex needMagic = 0 is0Magic = False is2Magic = False if tileArr[tileIndex - 1] == 0: needMagic += 1 is0Magic = True if tileArr[tileIndex + 1] == 0: needMagic += 1 is2Magic = True if needMagic <= len(magicArr): pattern = [None, tile1, None] tileArr[tileIndex] -= 1 if is0Magic: pattern[0] = (magicArr.pop(-1)) else: pattern[0] = (tileIndex - 1) tileArr[tileIndex - 1] -= 1 if is2Magic: pattern.append(magicArr.pop(-1)) else: pattern.append(tileIndex + 1) tileArr[tileIndex + 1] -= 1 resultTmp, hasJiang = cls.isBu(tileArr, resultArr, magicArr, tileType, hasJiang) if resultTmp: resultArr.append(pattern) return True, hasJiang # 还原手牌 tileArr[tileIndex] += 1 if is0Magic: magicArr.append(pattern[0]) else: tileArr[tileIndex - 1] += 1 if is2Magic: magicArr.append(pattern[2]) else: tileArr[tileIndex + 1] += 1 # 测试顺子 -2 -1 0 if MTile.getValue(tileIndex) >= 3: tile2 = tileIndex needMagic = 0 is0Magic = False is1Magic = False if tileArr[tileIndex - 2] == 0: needMagic += 1 is0Magic = True if tileArr[tileIndex - 1] == 0: needMagic += 1 is1Magic = True if needMagic <= len(magicArr): pattern = [None, None, tile2] tileArr[tileIndex] -= 1 if is0Magic: pattern[0] = (magicArr.pop(-1)) else: pattern[0] = (tileIndex - 2) tileArr[tileIndex - 2] -= 1 if is1Magic: pattern[1] = (magicArr.pop(-1)) else: pattern[1] = (tileIndex - 1) tileArr[tileIndex - 1] -= 1 resultTmp, hasJiang = cls.isBu(tileArr, resultArr, magicArr, tileType, hasJiang) if resultTmp: resultArr.append(pattern) return True, hasJiang # 还原手牌 tileArr[tileIndex] += 1 if is0Magic: magicArr.append(pattern[0]) else: tileArr[tileIndex - 2] += 1 if is1Magic: magicArr.append(pattern[1]) else: tileArr[tileIndex - 1] += 1 # 无和牌可能 return False, hasJiang
def getCardNumByType(cls, tileArr, tileType): num = 0 for tile in MTile.traverseTile(tileType): num += tileArr[tile] return num
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 calcScore(self): """算分""" # 序列化 self.serialize() # 牌型数据都在tabletilemgr里面可以取到 playerAllTiles = [[] for _ in range(self.playerCount)] playerAllTilesArr = [[] for _ in range(self.playerCount)] playerHandTiles = [[] for _ in range(self.playerCount)] for player in self.tableTileMgr.players: # 按手牌格式的数组 playerAllTiles[player.curSeatId] = player.copyTiles() # 合到一个数组中 playerAllTilesArr[player.curSeatId].extend(MHand.copyAllTilesToList(playerAllTiles[player.curSeatId])) # 只获取手牌 playerHandTiles[player.curSeatId] = player.copyHandTiles() ftlog.debug("playerHandTiles", playerHandTiles) ftlog.debug("playerAllTiles", playerAllTiles) ftlog.debug("playerAllTilesArr", playerAllTilesArr) ftlog.debug("self.winTile", self.winTile) self.results[self.KEY_TYPE] = '' self.results[self.KEY_NAME] = '' self.results[self.KEY_SCORE] = [0 for _ in range(self.playerCount)] self.results[self.KEY_WIN_TILE] = [0 for _ in range(self.playerCount)] self.results[self.KEY_WIN_MODE] = [MOneResult.WIN_MODE_LOSS for _ in range(self.playerCount)] # 在和牌时统计自摸,点炮,最大番数 self.results[self.KEY_STAT] = [[] for _ in range(self.playerCount)] self.results[self.KEY_FAN_PATTERN] = [[] for _ in range(self.playerCount)] fanArr = [0 for _ in range(self.playerCount)] baseScore = 1 # 流局不走后面的结算,确保没有设置的值不会被使用 if self.resultType == self.RESULT_FLOW: self.results[self.KEY_TYPE] = MOneResult.KEY_TYPE_NAME_FLOW ftlog.debug("MYunnanOneResult calcScore Type = RESULT_FLOW return") return self.results[self.KEY_TYPE] = MOneResult.KEY_TYPE_NAME_HU if len(self.winSeats) <= 0: ftlog.debug("MYunnanOneResult self.winSeats error no winner") return ftlog.debug("MYunnanOneResultCalcScore self.winSeats = ", self.winSeats) if self.lastSeatId not in self.winSeats: self.results[self.KEY_WIN_MODE][self.lastSeatId] = MOneResult.WIN_MODE_DIANPAO # 计算胡牌者的番型和分数 for seatId in self.winSeats: # 番型 patterns = [] fan = 0 ftlog.debug('MajiangTableLogic.gameWin.yipaoduoxiang dealwith seatId:' , seatId , 'lastSeatId:', self.lastSeatId , 'winSeatId:', self.winSeatId , 'self.winSeats:', self.winSeats , 'self.actionID:', self.actionID ) ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan, "seatId = ", seatId) if seatId == self.lastSeatId: self.results[self.KEY_WIN_MODE][seatId] = MOneResult.WIN_MODE_ZIMO else: self.results[self.KEY_WIN_MODE][seatId] = MOneResult.WIN_MODE_PINGHU magicTiles = self.tableTileMgr.getMagicTiles() tempArrColor = copy.deepcopy(playerAllTilesArr[seatId]) # colorState里面要去掉赖子包含的花色 magicTileCount = 0 for magicTile in magicTiles: while magicTile in tempArrColor: tempArrColor.remove(magicTile) magicTileCount += 1 # 重新处理一次花色,不算赖子 oldColorState = copy.deepcopy(self.colorState) ftlog.debug("MYunnanOneResultCalcScore tempArrColor = ", tempArrColor) ftlog.debug("MYunnanOneResultCalcScore self.colorState1 = ", self.colorState) self.colorState[seatId] = MTile.getColorCount(MTile.changeTilesToValueArr(tempArrColor)) ftlog.debug("MYunnanOneResultCalcScore self.colorState2 = ", self.colorState) isUnique = False # 七对和五六七星烂,十风,十三幺,四幺鸡 # 取出dropTiles来判断是否十风和十三幺 dropTiles = self.tableTileMgr.dropTiles[seatId] nowTiles = playerAllTiles[seatId] nowTiles[MHand.TYPE_HAND].append(self.winTile) # 杠上花和杠上炮 ftlog.debug("MYunnanOneResultCalcScorelatestGangState = ", self.latestGangState) ftlog.debug("MYunnanOneResultCalcScorelatestGangState self.winSeatId:= ", self.winSeatId) ftlog.debug("MYunnanOneResultCalcScorelatestGangState seatId:= ", seatId) ftlog.debug("MYunnanOneResultCalcScorelatestGangState self.lastSeatId:= ", self.lastSeatId) if self.latestGangState != -1: if self.latestGangState == seatId: # 杠牌的是自己 wumeihuaTiles = copy.deepcopy(nowTiles) if self.winTile in wumeihuaTiles[MHand.TYPE_HAND]: wumeihuaTiles[MHand.TYPE_HAND].remove(self.winTile) wumeihuaTiles[MHand.TYPE_HAND].append(MTile.TILE_FIVE_TONG) result, _ = MWinRuleYunnan.checkHuByMagicTiles(wumeihuaTiles, magicTiles) if result and (self.winTile == MTile.TILE_FIVE_TONG or self.winTile in magicTiles): # 五梅花,包括幺鸡当五筒 if not isUnique: patterns.append(self.fanXing[self.GANGSHANGHUAWUMEIHUA]['name']) fan += self.fanXing[self.GANGSHANGHUAWUMEIHUA]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: if not isUnique: patterns.append(self.fanXing[self.GANGSHANGHUA]['name']) fan += self.fanXing[self.GANGSHANGHUA]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) elif self.latestGangState == self.lastSeatId: # 杠牌的是别人 if not isUnique: patterns.append(self.fanXing[self.GANGSHANGPAO]['name']) fan += self.fanXing[self.GANGSHANGPAO]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 四幺鸡,必须是自摸,必须是手牌 if nowTiles[MHand.TYPE_HAND].count(MTile.TILE_ONE_TIAO) == 4 and (seatId == self.lastSeatId): if not isUnique: self.results[self.KEY_WIN_MODE][seatId] = MYunnanOneResult.WIN_MODE_SIYAOJI patterns = [] patterns.append(self.fanXing[self.SIYAOJI]['name']) isUnique = True fan = 0 fan += self.fanXing[self.SIYAOJI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) ftlog.debug("MYunnanOneResult dropTiles = ", dropTiles, "nowTiles = ", nowTiles) if self.isShifeng(dropTiles, nowTiles): if not isUnique: self.results[self.KEY_WIN_MODE][seatId] = MYunnanOneResult.WIN_MODE_SHIFENG patterns.append(self.fanXing[self.SHIFENG]['name']) fan = 0 fan += self.fanXing[self.SHIFENG]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) isUnique = True self.setDropHuFlag(1) if self.isShisanyao(dropTiles, nowTiles): if not isUnique: self.results[self.KEY_WIN_MODE][seatId] = MYunnanOneResult.WIN_MODE_SHISANYAO patterns.append(self.fanXing[self.SHISANYAO]['name']) fan = 0 fan += self.fanXing[self.SHISANYAO]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) isUnique = True self.setDropHuFlag(1) ftlog.debug("MYunnanOneResult check lanpai nowTiles =", nowTiles, "magicTiles =", magicTiles) result, fengCount, lanPanMagicCount = self.isLanPaiCheck(nowTiles, magicTiles) lanPaiPatternForWuji = False if result: lanPaiPatternForWuji = True if fengCount + lanPanMagicCount >= 7: # 七星烂 if not isUnique: patterns.append(self.fanXing[self.QIXINGLAN]['name']) fan += self.fanXing[self.QIXINGLAN]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) elif fengCount + lanPanMagicCount >= 6: # 六星烂 if not isUnique: patterns.append(self.fanXing[self.LIUXINGLAN]['name']) fan += self.fanXing[self.LIUXINGLAN]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) elif fengCount + lanPanMagicCount >= 5: # 五星烂 if not isUnique: patterns.append(self.fanXing[self.WUXINGLAN]['name']) fan += self.fanXing[self.WUXINGLAN]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 七对必须门清 isPairs = False if self.menState[seatId] == 1: if seatId == self.lastSeatId: # 自摸 pairResult, leftMagicCount, fourCount, _ = self.isPairsCheck(nowTiles, magicTiles) if pairResult: isPairs = True if fourCount >= 1: if not isUnique: patterns.append(self.fanXing[self.LONGZHUABEI]['name']) fan += self.fanXing[self.LONGZHUABEI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: # 小七对 if not isUnique: patterns.append(self.fanXing[self.XIAOQIDUI]['name']) fan += self.fanXing[self.XIAOQIDUI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: # 点炮 if self.winTile in magicTiles: transferTiles = copy.deepcopy(nowTiles) magicCount = 0 for magicTile in magicTiles: while magicTile in transferTiles[MHand.TYPE_HAND]: transferTiles[MHand.TYPE_HAND].remove(magicTile) transferTiles[MHand.TYPE_HAND].append(0) magicCount += 1 if magicCount >= 1: transferTiles[MHand.TYPE_HAND].remove(0) transferTiles[MHand.TYPE_HAND].append(magicTile) pairResult, leftMagicCount, fourCount, _ = self.isPairsCheck(transferTiles, [0]) if pairResult: isPairs = True if leftMagicCount >= 2: if not isUnique: patterns.append(self.fanXing[self.LONGZHUABEI]['name']) fan += self.fanXing[self.LONGZHUABEI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: # 小七对 if not isUnique: patterns.append(self.fanXing[self.XIAOQIDUI]['name']) fan += self.fanXing[self.XIAOQIDUI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: pairResult, leftMagicCount, fourCount, _ = self.isPairsCheck(nowTiles, magicTiles) if pairResult: isPairs = True if nowTiles[MHand.TYPE_HAND].count(self.winTile) + leftMagicCount >= 3: # 一定是龙爪背 if not isUnique: patterns.append(self.fanXing[self.LONGZHUABEI]['name']) fan += self.fanXing[self.LONGZHUABEI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: # 小七对 if not isUnique: patterns.append(self.fanXing[self.XIAOQIDUI]['name']) fan += self.fanXing[self.XIAOQIDUI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 杠数 # if len(self.playerGangTiles[seatId]) == 1: # if not isUnique: # self.results[self.KEY_NAME] = self.fanXing[self.YIGANG]['name'] # patterns.append(self.fanXing[self.YIGANG]['name']) # fan += self.fanXing[self.YIGANG]['index'] # ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # el if len(self.playerGangTiles[seatId]) == 2: if not isUnique: self.results[self.KEY_NAME] = self.fanXing[self.LIANGGANG]['name'] patterns.append(self.fanXing[self.LIANGGANG]['name']) fan += self.fanXing[self.LIANGGANG]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) elif len(self.playerGangTiles[seatId]) == 3: if not isUnique: self.results[self.KEY_NAME] = self.fanXing[self.SANGANG]['name'] patterns.append(self.fanXing[self.SANGANG]['name']) fan += self.fanXing[self.SANGANG]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) elif len(self.playerGangTiles[seatId]) == 4: if not isUnique: self.results[self.KEY_NAME] = self.fanXing[self.SIGANG]['name'] patterns.append(self.fanXing[self.SIGANG]['name']) fan += self.fanXing[self.SIGANG]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 字一色 ziyiseWuji = False if self.colorState[seatId] == 0: if self.getZiTypeCountBySeatId(seatId) > 0: ziyiseWuji = True if not isUnique: self.results[self.KEY_NAME] = self.fanXing[self.ZIYISE]['name'] patterns.append(self.fanXing[self.ZIYISE]['name']) fan += self.fanXing[self.ZIYISE]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 大对子,门前不能有吃,手牌多加一个赖子,能保证都是3张 if len(nowTiles[MHand.TYPE_CHI]) == 0: duiziTiles = copy.deepcopy(nowTiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in duiziTiles: duiziTiles.remove(magicTile) # 如果点炮胡,需要给牌堆里加回去一张赖子,并当普通牌处理 if seatId != self.lastSeatId and self.winTile in magicTiles: duiziTiles.append(self.winTile) duiziArr = MTile.changeTilesToValueArr(duiziTiles) ftlog.debug("MYunnanOneResult duiziArr = ", duiziArr) cardTypeCount = 0 # 假设多一张赖子 duiziMagicCount = magicTileCount + 1 for index in range(len(duiziArr)): if duiziArr[index] != 0: cardTypeCount += 1 if duiziArr[index] < 3: duiziMagicCount = duiziMagicCount - (3 - duiziArr[index]) if cardTypeCount <= 5 and duiziMagicCount >= 0: patterns.append(self.fanXing[self.DADUIZI]['name']) fan += self.fanXing[self.DADUIZI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 清一色和混一色 qingyiseForWuji = False if self.colorState[seatId] == 1: qingyiseForWuji = True if self.getZiTypeCountBySeatId(seatId) > 0: if not isUnique: self.results[self.KEY_NAME] = self.fanXing[self.HUNYISE]['name'] patterns.append(self.fanXing[self.HUNYISE]['name']) fan += self.fanXing[self.HUNYISE]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: if not isUnique: self.results[self.KEY_NAME] = self.fanXing[self.QINGYISE]['name'] patterns.append(self.fanXing[self.QINGYISE]['name']) fan += self.fanXing[self.QINGYISE]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 不求人 门清并自摸 # 暗杠也算门清,重新计算 # 烂牌和七对牌型时不计算不求人 if not lanPaiPatternForWuji and not isPairs: isMenQing = False gangInfo = playerAllTiles[seatId][MHand.TYPE_GANG] chiInfo = playerAllTiles[seatId][MHand.TYPE_CHI] pengInfo = playerAllTiles[seatId][MHand.TYPE_PENG] if len(chiInfo) == 0 and len(pengInfo) == 0: isMenQing = True for gang in gangInfo: if gang['style'] == 1: isMenQing = False if isMenQing and seatId == self.lastSeatId: if not isUnique: self.results[self.KEY_WIN_MODE][seatId] = MYunnanOneResult.WIN_MODE_BUQIUREN patterns.append(self.fanXing[self.BUQIUREN]['name']) fan += self.fanXing[self.BUQIUREN]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 全求人 最后手里只有一张牌 单钓 不能有暗杠 if len(playerHandTiles[seatId]) == 1 and seatId != self.lastSeatId: noAnGang = True for gangInfo in nowTiles[MHand.TYPE_GANG]: if gangInfo.has_key('style'): gangStyle = gangInfo.get('style', 1) if gangStyle == 0: noAnGang = False break; if noAnGang: if not isUnique: patterns.append(self.fanXing[self.QUANQIUREN]['name']) fan += self.fanXing[self.QUANQIUREN]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 三元和混三元 sanyuanForWuji = False baibanCount = self.getZiCountByTypeBySeatId(seatId, MTile.TILE_BAI_BAN) hongzhongCount = self.getZiCountByTypeBySeatId(seatId, MTile.TILE_HONG_ZHONG) facaiCount = self.getZiCountByTypeBySeatId(seatId, MTile.TILE_FA_CAI) sanyuanMagicCount = nowTiles[MHand.TYPE_HAND].count(MTile.TILE_ONE_TIAO) if baibanCount + sanyuanMagicCount >= 2 \ and hongzhongCount + sanyuanMagicCount >= 2 \ and facaiCount + sanyuanMagicCount >= 2: if baibanCount + hongzhongCount + sanyuanMagicCount >= 5 \ and baibanCount + facaiCount + sanyuanMagicCount >= 5 \ and hongzhongCount + facaiCount + sanyuanMagicCount >= 5: if baibanCount + hongzhongCount + facaiCount + sanyuanMagicCount >= 8: if self.colorState[seatId] == 1 and self.noFengPai(seatId): # 混三元 if not isUnique: sanyuanForWuji = True patterns.append(self.fanXing[self.HUNSANYUAN]['name']) fan += self.fanXing[self.HUNSANYUAN]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: # 三元 if not isUnique: patterns.append(self.fanXing[self.SANYUAN]['name']) fan += self.fanXing[self.SANYUAN]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) # 无鸡 isWuji = False wujiTiles = copy.deepcopy(nowTiles) # 手牌不要赖子能胡 result0, _ = MWinRuleYunnan.checkHuByMagicTiles(wujiTiles, []) for temp in nowTiles[MHand.TYPE_CHI]: wujiTiles[MHand.TYPE_HAND].extend(temp) for temp in nowTiles[MHand.TYPE_PENG]: wujiTiles[MHand.TYPE_HAND].extend(temp) ftlog.debug("MYunnanOneResult wujiTiles = ", wujiTiles) # 加上碰吃,不要赖子也能胡 result1, _ = MWinRuleYunnan.checkHuByMagicTiles(wujiTiles, []) wujiMagicCount = playerAllTilesArr[seatId].count(MTile.TILE_ONE_TIAO) ftlog.debug("MYunnanOneResult wujiTiles = ", wujiTiles, "result1=", result1) result2 = True # 算杠,不是4个幺鸡都是有赖子 for magicTile in magicTiles: for gangInfo in wujiTiles[MHand.TYPE_GANG]: wujiGangMagicCount = 0 if gangInfo.has_key('pattern'): tempGangInfo = copy.deepcopy(gangInfo['pattern']) while magicTile in tempGangInfo: tempGangInfo.remove(magicTile) wujiGangMagicCount += 1 if wujiGangMagicCount != 4 and wujiGangMagicCount != 0: result2 = False break ftlog.debug("MYunnanOneResult wujiTiles = ", wujiTiles , "result1=", result1 , "result2=", result2 , "result0=", result0) if result1 and result2 and result0: isWuji = True if isWuji: if wujiMagicCount > 0: canXiaojiguiwei = True # 小鸡归位,要排除赖子应用在其它番型导致小鸡归位和其它番型不同存的情况 ftlog.debug("MYunnanOneResult canXiaojiguiwei oldColorState", oldColorState , "lanPaiPatternForWuji", lanPaiPatternForWuji , "qingyiseForWuji", qingyiseForWuji , "ziyiseWuji", ziyiseWuji , "sanyuanForWuji", sanyuanForWuji) if lanPaiPatternForWuji: # 如果是烂牌的小鸡归位,重新检查在没有赖子的情况能不能胡 resultNoMagic, fengCountNoMagic, lanPanMagicCountNoMagic = self.isLanPaiCheck(nowTiles, []) if lanPanMagicCount > 0: # 带赖子的六星烂,如果无赖子判定能胡,那就可以胡五星烂+小鸡归位 if self.fanXing[self.LIUXINGLAN]['name'] in patterns and resultNoMagic: patterns.remove(self.fanXing[self.LIUXINGLAN]['name']) fan -= self.fanXing[self.LIUXINGLAN]['index'] patterns.append(self.fanXing[self.WUXINGLAN]['name']) fan += self.fanXing[self.WUXINGLAN]['index'] canXiaojiguiwei = True elif self.fanXing[self.QIXINGLAN][ 'name'] in patterns and resultNoMagic and fengCountNoMagic >= 7: canXiaojiguiwei = True else: canXiaojiguiwei = False else: canXiaojiguiwei = True if qingyiseForWuji: if oldColorState[seatId] > 1: canXiaojiguiwei = False if ziyiseWuji: if oldColorState[seatId] > 0: canXiaojiguiwei = False if sanyuanForWuji: if oldColorState[seatId] > 1: canXiaojiguiwei = False if canXiaojiguiwei: if not isUnique: patterns.append(self.fanXing[self.XIAOJIGUIWEI]['name']) fan += self.fanXing[self.XIAOJIGUIWEI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: if not isUnique: patterns.append(self.fanXing[self.WUJI]['name']) fan += self.fanXing[self.WUJI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) self.results[self.KEY_FAN_PATTERN][seatId] = patterns self.results[self.KEY_WIN_TILE][seatId] = self.winTile fanArr[seatId] = fan if self.lastSeatId in self.winSeats: self.results[self.KEY_STAT][self.lastSeatId].append({MOneResult.STAT_ZIMO: 1}) else: # 点炮,点炮者点炮+1 self.results[self.KEY_STAT][self.lastSeatId].append({MOneResult.STAT_DIANPAO: 1}) # 最大番,当前的赢家番数 self.results[self.KEY_STAT][seatId].append({MOneResult.STAT_ZUIDAFAN: fan}) # 计算积分 winScore = baseScore * (self.multiple) if self.qiangGang: if self.winRuleMgr.itemParams.get('QGHSanbei', 1) == 2: winScore = winScore else: winScore = winScore * 3 for player in self.tableTileMgr.players: if player.curSeatId == self.lastSeatId and self.lastSeatId not in self.winSeats: ftlog.debug("MYunnanOneResultQGH lose seatId:", player.curSeatId, "lastSeatId:", self.lastSeatId) if self.winTile in player.handTiles: ftlog.debug("MYunnanOneResultQGH lose seatId:", player.curSeatId, "lastSeatId:", self.lastSeatId, "remove tile:", self.winTile) player.handTiles.remove(self.winTile) else: if self.showTile in player.handTiles and self.showTile != 0: ftlog.debug("MYunnanOneResultQGH lose seatId:", player.curSeatId, "lastSeatId:", self.lastSeatId, "remove tile:", self.showTile) player.handTiles.remove(self.showTile) for seatId in self.winSeats: if self.winRuleMgr.itemParams.get('QGHJiafan', 1) == 2: fanArr[seatId] += 1 self.results[self.KEY_WIN_MODE][seatId] = MOneResult.WIN_MODE_QIANGGANGHU # 番数上限3 for win in self.winSeats: if fanArr[win] > 3: fanArr[win] = 3 # 计算分数增减 if self.lastSeatId in self.winSeats: for i in range(self.playerCount): if self.lastSeatId == i: self.results[self.KEY_SCORE][i] = winScore * (2 ** fanArr[i]) * (self.playerCount - 1) else: self.results[self.KEY_SCORE][i] = -winScore * (2 ** fanArr[self.lastSeatId]) else: dianPaoScore = 0 for i in range(self.playerCount): if i in self.winSeats: self.results[self.KEY_SCORE][i] = winScore * (2 ** fanArr[i]) dianPaoScore += winScore * (2 ** fanArr[i]) self.results[self.KEY_SCORE][self.lastSeatId] = -dianPaoScore ftlog.debug('MYunnanOneResult calcScore:KEY_SCORE:', self.results[self.KEY_SCORE]) ftlog.debug('MYunnanOneResult calcScore:KEY_NAME:', self.results[self.KEY_NAME]) ftlog.debug('MYunnanOneResult calcScore:KEY_TYPE:', self.results[self.KEY_TYPE]) ftlog.debug('MYunnanOneResult calcScore:KEY_WIN_MODE:', self.results[self.KEY_WIN_MODE]) ftlog.debug('MYunnanOneResult calcScore:KEY_FAN_PATTERN:', self.results[self.KEY_FAN_PATTERN]) ftlog.debug('MYunnanOneResult calcScore:KEY_STAT:', self.results[self.KEY_STAT])
def isHu(self, tiles, tile, isTing, getTileType, magicTiles=[], tingNodes=[]): """ tiles:玩家所有的牌,但是手牌是加入了要胡的那张牌的 """ # 昭通无听牌 ftlog.debug('MWinRuleZhaotong.isHu tiles:', tiles , ' tile:', tile , ' magicTils:', magicTiles , ' getTileType:', getTileType) if getTileType != MWinRule.WIN_BY_MYSELF and MTableTile.isMagicTile(tile, magicTiles): # 如果是听用,不能胡 return False, [] # 先查花色 playerAllTiles = [] playerAllTiles.extend(tiles[MHand.TYPE_HAND]) for chi in tiles[MHand.TYPE_CHI]: playerAllTiles.extend(chi) for peng in tiles[MHand.TYPE_PENG]: playerAllTiles.extend(peng) for gang in tiles[MHand.TYPE_GANG]: playerAllTiles.extend(gang['pattern']) colorStateWithMagic = MTile.getColorCount(MTile.changeTilesToValueArr(playerAllTiles)) magicCount, tempTiles = MTableTile.getMagicTileCountInTiles(playerAllTiles, magicTiles) colorState = MTile.getColorCount(MTile.changeTilesToValueArr(tempTiles)) ftlog.debug("MWinRuleZhaotong.isHu colorState = ", colorState , "playerAllTiles = ", playerAllTiles , "tempTiles = ", tempTiles , "colorStateWithMagic = ", colorStateWithMagic , "magicCount = ", magicCount) # 必须缺一门才能胡牌 if colorState >= 3: ftlog.debug("MWinRuleZhaotong.isHu men >= 3 can not hu") return False, [] result1, pattern1 = MWinRuleZhaotong.checkHuByMagicTiles(tiles, magicTiles) # result2, pattern2 = MWinRuleZhaotong.checkHuByMagicTiles(tiles, []) # if colorStateWithMagic >= 3: # if result1 and not result2: # return result1, pattern1 # else: # return False, [] # else: # if result1: # return result1, pattern1 # else: # return False, [] if result1: return result1, pattern1 # if getTileType != MWinRule.WIN_BY_MYSELF: # hasMagic = False # for magicTile in magicTiles: # if magicTile in tiles[MHand.TYPE_HAND]: # hasMagic = True # if hasMagic: # # 点炮和抢杠胡要检查是不是叫听用,如果叫听用,可以胡任意牌,采用抽3张牌测试的方式,如果通过就认为是叫听用 # testTiles = [] # if tile/10 == 0: # testTiles.append(2) # testTiles.append(6) # testTiles.append(9) # elif tile/10 == 1: # testTiles.append(12) # testTiles.append(14) # testTiles.append(17) # elif tile/10 == 2: # testTiles.append(22) # testTiles.append(24) # testTiles.append(28) # else: # return False, [] # dandiao = True # for testTile in testTiles: # tempDandiao = copy.deepcopy(tiles) # if tile in tempDandiao[MHand.TYPE_HAND]: # tempDandiao[MHand.TYPE_HAND].remove(tile) # tempDandiao[MHand.TYPE_HAND].append(testTile) # resultDandiao, _ = MWinRuleZhaotong.checkHuByMagicTiles(tempDandiao, magicTiles) # if not resultDandiao: # dandiao = False # if not dandiao: # return result1, pattern1 # else: # return result1, pattern1 # else: # return result1, pattern1 return False, []
def isHu(self, tiles, tile, isTing, getTileType, magicTiles=[], tingNodes=[]): """ tiles:玩家所有的牌,但是手牌是加入了要胡的那张牌的 """ # 昭通无听牌 ftlog.debug('MWinRuleZhaotong.isHu tiles:', tiles, ' tile:', tile, ' magicTils:', magicTiles, ' getTileType:', getTileType) if getTileType != MWinRule.WIN_BY_MYSELF and MTableTile.isMagicTile( tile, magicTiles): # 如果是听用,不能胡 return False, [] # 先查花色 playerAllTiles = [] playerAllTiles.extend(tiles[MHand.TYPE_HAND]) for chi in tiles[MHand.TYPE_CHI]: playerAllTiles.extend(chi) for peng in tiles[MHand.TYPE_PENG]: playerAllTiles.extend(peng) for gang in tiles[MHand.TYPE_GANG]: playerAllTiles.extend(gang['pattern']) colorStateWithMagic = MTile.getColorCount( MTile.changeTilesToValueArr(playerAllTiles)) magicCount, tempTiles = MTableTile.getMagicTileCountInTiles( playerAllTiles, magicTiles) colorState = MTile.getColorCount( MTile.changeTilesToValueArr(tempTiles)) ftlog.debug("MWinRuleZhaotong.isHu colorState = ", colorState, "playerAllTiles = ", playerAllTiles, "tempTiles = ", tempTiles, "colorStateWithMagic = ", colorStateWithMagic, "magicCount = ", magicCount) # 必须缺一门才能胡牌 if colorState >= 3: ftlog.debug("MWinRuleZhaotong.isHu men >= 3 can not hu") return False, [] result1, pattern1 = MWinRuleZhaotong.checkHuByMagicTiles( tiles, magicTiles) # result2, pattern2 = MWinRuleZhaotong.checkHuByMagicTiles(tiles, []) # if colorStateWithMagic >= 3: # if result1 and not result2: # return result1, pattern1 # else: # return False, [] # else: # if result1: # return result1, pattern1 # else: # return False, [] if result1: return result1, pattern1 # if getTileType != MWinRule.WIN_BY_MYSELF: # hasMagic = False # for magicTile in magicTiles: # if magicTile in tiles[MHand.TYPE_HAND]: # hasMagic = True # if hasMagic: # # 点炮和抢杠胡要检查是不是叫听用,如果叫听用,可以胡任意牌,采用抽3张牌测试的方式,如果通过就认为是叫听用 # testTiles = [] # if tile/10 == 0: # testTiles.append(2) # testTiles.append(6) # testTiles.append(9) # elif tile/10 == 1: # testTiles.append(12) # testTiles.append(14) # testTiles.append(17) # elif tile/10 == 2: # testTiles.append(22) # testTiles.append(24) # testTiles.append(28) # else: # return False, [] # dandiao = True # for testTile in testTiles: # tempDandiao = copy.deepcopy(tiles) # if tile in tempDandiao[MHand.TYPE_HAND]: # tempDandiao[MHand.TYPE_HAND].remove(tile) # tempDandiao[MHand.TYPE_HAND].append(testTile) # resultDandiao, _ = MWinRuleZhaotong.checkHuByMagicTiles(tempDandiao, magicTiles) # if not resultDandiao: # dandiao = False # if not dandiao: # return result1, pattern1 # else: # return result1, pattern1 # else: # return result1, pattern1 return False, []
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