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 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 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 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 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 hasPeng(cls, tiles, tile): """ 是否可以碰 判断之前tile已经加到tiles中 tiles - 手牌 tile - 待碰的牌 """ tileArr = MTile.changeTilesToValueArr(tiles) if tileArr[tile] >= 3: 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(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 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 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 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 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 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 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 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 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 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 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 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 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 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 hasGang(self, tiles, curTile, state): """判断杠牌""" handTiles = tiles[MHand.TYPE_HAND] tileArr = MTile.changeTilesToValueArr(handTiles) magics = self.tableTileMgr.getMagicTiles(False) tileArr, magicTiles = self.tableTileMgr.exculeMagicTiles( tileArr, magics) magicCount = len(magicTiles) magicGangMaxCount = self.tableTileMgr.magicGangMaxCount if magicGangMaxCount > 4 or magicGangMaxCount < 0: magicGangMaxCount = 4 gangs = [] # 带有癞子的杠 for tile in range(MTile.TILE_MAX_VALUE): if tileArr[tile] == 4: pattern = [tile, tile, tile, tile] if (curTile in pattern) and (state & MTableState.TABLE_STATE_DROP): gangs.append({ "pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile }) else: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile }) if tileArr[tile] >= 3 and magicCount >= 1: pattern = [tile, tile, tile, magicTiles[0]] pattern.sort() if (curTile in pattern) and (curTile not in magicTiles) and ( state & MTableState.TABLE_STATE_DROP ) and magicGangMaxCount >= 1: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile }) else: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile }) if tileArr[tile] >= 2 and magicCount >= 2: pattern = [tile, tile, magicTiles[0], magicTiles[1]] pattern.sort() if (curTile in pattern) and (curTile not in magicTiles) and ( state & MTableState.TABLE_STATE_DROP ) and magicGangMaxCount >= 2: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile }) else: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile }) if tileArr[tile] >= 1 and magicCount >= 3: pattern = [tile, magicTiles[0], magicTiles[1], magicTiles[2]] pattern.sort() if (curTile in pattern) and (curTile not in magicTiles) and ( state & MTableState.TABLE_STATE_DROP ) and magicGangMaxCount >= 3: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile }) else: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile }) # 赖子作为普通牌来杠,暂时不处理多类赖子的情况 if magicCount >= 4 and len(magics) == 1: pattern = [ magicTiles[0], magicTiles[1], magicTiles[2], magicTiles[3] ] pattern.sort() if (curTile in pattern) and (state & MTableState.TABLE_STATE_DROP): gangs.append({ "pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": curTile }) else: gangs.append({ "pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": magicTiles[0] }) # 补杠 if not (state & MTableState.TABLE_STATE_DROP): for pengPattern in tiles[MHand.TYPE_PENG]: for tile in pengPattern: if tile not in magicTiles and tile in handTiles: gangPattern = copy.deepcopy(pengPattern) gangPattern.append(tile) gangs.append({ "pattern": gangPattern, "style": MPlayerTileGang.MING_GANG, "tile": tile }) break # 用赖子补杠,目前只处理一个赖子补杠 for pengPattern in tiles[MHand.TYPE_PENG]: ftlog.debug('MGangRule.hasGang:pengPattern', tiles[MHand.TYPE_PENG]) if magicCount >= 1: # 有赖子的杠,注意三个赖子碰补杠也在这里处理 gangPattern2 = copy.deepcopy(pengPattern) tile2 = magicTiles[0] gangPattern2.append(tile2) gangs.append({ "pattern": gangPattern2, "style": MPlayerTileGang.MING_GANG, "tile": tile2 }) ftlog.debug('MGangRule.hasGang:', gangs) return gangs
def hasGang(self, tiles, curTile, state): """判断杠牌""" handTiles = tiles[MHand.TYPE_HAND] tileArr = MTile.changeTilesToValueArr(handTiles) magics = self.tableTileMgr.getMagicTiles(False) tileArr, magicTiles = self.tableTileMgr.exculeMagicTiles(tileArr, magics) magicCount = len(magicTiles) magicGangMaxCount = self.tableTileMgr.magicGangMaxCount if magicGangMaxCount > 4 or magicGangMaxCount < 0: magicGangMaxCount = 4 gangs = [] # 带有癞子的杠 for tile in range(MTile.TILE_MAX_VALUE): if tileArr[tile] == 4: pattern = [tile, tile, tile, tile] if (curTile in pattern) and (state & MTableState.TABLE_STATE_DROP): gangs.append({"pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile}) else: gangs.append({"pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile}) if tileArr[tile] >= 3 and magicCount >= 1: pattern = [tile, tile, tile, magicTiles[0]] pattern.sort() if (curTile in pattern) and (curTile not in magicTiles) and ( state & MTableState.TABLE_STATE_DROP) and magicGangMaxCount >= 1: gangs.append({"pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile}) else: gangs.append({"pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile}) if tileArr[tile] >= 2 and magicCount >= 2: pattern = [tile, tile, magicTiles[0], magicTiles[1]] pattern.sort() if (curTile in pattern) and (curTile not in magicTiles) and ( state & MTableState.TABLE_STATE_DROP) and magicGangMaxCount >= 2: gangs.append({"pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile}) else: gangs.append({"pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile}) if tileArr[tile] >= 1 and magicCount >= 3: pattern = [tile, magicTiles[0], magicTiles[1], magicTiles[2]] pattern.sort() if (curTile in pattern) and (curTile not in magicTiles) and ( state & MTableState.TABLE_STATE_DROP) and magicGangMaxCount >= 3: gangs.append({"pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": tile}) else: gangs.append({"pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": tile}) # 赖子作为普通牌来杠,暂时不处理多类赖子的情况 if magicCount >= 4 and len(magics) == 1: pattern = [magicTiles[0], magicTiles[1], magicTiles[2], magicTiles[3]] pattern.sort() if (curTile in pattern) and (state & MTableState.TABLE_STATE_DROP): gangs.append({"pattern": pattern, "style": MPlayerTileGang.MING_GANG, "tile": curTile}) else: gangs.append({"pattern": pattern, "style": MPlayerTileGang.AN_GANG, "tile": magicTiles[0]}) # 补杠 if not (state & MTableState.TABLE_STATE_DROP): for pengPattern in tiles[MHand.TYPE_PENG]: for tile in pengPattern: if tile not in magicTiles and tile in handTiles: gangPattern = copy.deepcopy(pengPattern) gangPattern.append(tile) gangs.append({"pattern": gangPattern, "style": MPlayerTileGang.MING_GANG, "tile": tile}) break # 用赖子补杠,目前只处理一个赖子补杠 for pengPattern in tiles[MHand.TYPE_PENG]: ftlog.debug('MGangRule.hasGang:pengPattern', tiles[MHand.TYPE_PENG]) if magicCount >= 1: # 有赖子的杠,注意三个赖子碰补杠也在这里处理 gangPattern2 = copy.deepcopy(pengPattern) tile2 = magicTiles[0] gangPattern2.append(tile2) gangs.append({"pattern": gangPattern2, "style": MPlayerTileGang.MING_GANG, "tile": tile2}) ftlog.debug('MGangRule.hasGang:', gangs) return gangs
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 checkSpecialHu(cls, tiles, magicTiles, magicTileCount, tile): # 判断七对系列 if cls.isPairs(tiles, magicTiles): return True # 判定五六七星烂,手牌数必须为14,所有花色最多一张牌,字牌不重复且大于等于5种,其它花色必须都存在且互相不靠 if cls.isLanPaiHu(tiles, magicTiles): return True # 判断其它特殊牌型 allTiles = MHand.copyAllTilesToList(tiles) tempTiles = copy.deepcopy(allTiles) for magicTile in magicTiles: while magicTile in tempTiles: tempTiles.remove(magicTile) tileArr = MTile.changeTilesToValueArr(tempTiles) colorState = MTile.getColorCount(tileArr) tempFengTiles = MTile.traverseTile(MTile.TILE_FENG) ziState = tileArr[tempFengTiles[0]:tempFengTiles[len(tempFengTiles) - 1] + 1] # menState = 0 # if len(allTiles) == 14: # menState = 1 playerGangCount = len(tiles[MHand.TYPE_GANG]) if playerGangCount >= 2 \ or colorState == 1 or colorState == 0 \ or len(tiles[MHand.TYPE_HAND]) == 2 or len(tiles[MHand.TYPE_HAND]) == 3: return True # 三元和混三元 baibanCount = cls.getZiCountByTypeBySeatId(MTile.TILE_BAI_BAN, ziState) hongzhongCount = cls.getZiCountByTypeBySeatId(MTile.TILE_HONG_ZHONG, ziState) facaiCount = cls.getZiCountByTypeBySeatId(MTile.TILE_FA_CAI, ziState) if baibanCount + magicTileCount >= 2 \ and hongzhongCount + magicTileCount >= 2 \ and facaiCount + magicTileCount >= 2: if baibanCount + hongzhongCount + magicTileCount >= 5 \ and baibanCount + facaiCount + magicTileCount >= 5 \ and hongzhongCount + facaiCount + magicTileCount >= 5: if baibanCount + hongzhongCount + facaiCount + magicTileCount >= 8: return True # 大对子,门前不能有吃,手牌多加一个赖子,能保证都是3张 if len(tiles[MHand.TYPE_CHI]) == 0: duiziTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in duiziTiles: duiziTiles.remove(magicTile) # 如果点炮胡,需要给牌堆里加回去一张赖子,并当普通牌处理 if tile in magicTiles: duiziTiles.append(tile) 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: return True return False
def getTileLeftCount(self, tile): """获取某个花色剩余数量""" tileArr = MTile.changeTilesToValueArr(self.__tiles) return tileArr[tile]
def getTileLeftCount(self, tile): """获取某个花色剩余数量""" tileArr = MTile.changeTilesToValueArr(self.__tiles) return tileArr[tile]
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
def calcGenCount(self, tiles, magicTile, mFactor): """算单癞子情况下一手牌里的根,墙上牌三张就算一根,三张+一个癞子还能多加一番""" genCount = 0 extraFan = 0 workTiles = copy.deepcopy(tiles) matchedPattern = {'gang': [], 'peng': []} if len(tiles[MHand.TYPE_GANG]) > 0: for gangInfo in tiles[MHand.TYPE_GANG]: if mFactor in gangInfo['pattern']: extraFan = 1 matchedPattern['gang'].append(gangInfo) ftlog.debug("gangAdd0") break genCount += len(tiles[MHand.TYPE_GANG]) if len(tiles[MHand.TYPE_PENG]) > 0: # 先找一遍因子,优先匹配因子 for peng in tiles[MHand.TYPE_PENG]: if mFactor in peng: genCount += 1 # extraFan = 1 matchedPattern['peng'].append(peng) ftlog.debug("pengAdd0") break # 再找其他的 跳过因子 for peng in tiles[MHand.TYPE_PENG]: matchedOk = False if mFactor in peng: continue for pengTile in peng: if pengTile != magicTile: # 优先匹配非癞子 for handTile in workTiles[MHand.TYPE_HAND]: if pengTile == handTile: # 碰的母牌 手里还有 一定算一根 genCount += 1 matchedOk = True ftlog.debug("pengAdd1") matchedPattern['peng'].append(peng) break if matchedOk: # 匹配成功直接找下一组碰 break else: for handTile in workTiles[MHand.TYPE_HAND]: if handTile == magicTile: # 手里有癞子, 替换成碰的母牌 看是否能胡牌,能胡的话算一根 workTiles[MHand.TYPE_HAND].remove(handTile) workTiles[MHand.TYPE_HAND].append(pengTile) result, _ = MWinRuleZhaotong.checkHuByMagicTiles( workTiles, [magicTile]) if result: genCount += 1 ftlog.debug("pengAdd2") matchedPattern['peng'].append(peng) else: # 还原手牌 workTiles[MHand.TYPE_HAND].remove( pengTile) workTiles[MHand.TYPE_HAND].append( handTile) break break tempGenArr = copy.deepcopy(workTiles[MHand.TYPE_HAND]) genMagicCount = 0 ftlog.debug("MYunnanOneResultCalcScore GENINFO tempGenArr", tempGenArr, "genMagicCount", genMagicCount, "magicTile", magicTile, "mFactor", mFactor, "genCount", genCount) while magicTile in tempGenArr: tempGenArr.remove(magicTile) genMagicCount += 1 factorCount = 0 while mFactor in tempGenArr: tempGenArr.remove(mFactor) factorCount += 1 if factorCount + genMagicCount >= 4: genCount += 1 extraFan = 1 ftlog.debug("handAdd0") genMagicCount -= 4 - factorCount elif factorCount + genMagicCount >= 3: genCount += 1 ftlog.debug("handAdd0.5") genMagicCount -= 3 - factorCount tileValueArr = MTile.changeTilesToValueArr(tempGenArr) tileIndex = 0 handTileCount = {3: [], 2: [], 1: []} # 4个癞子的情况单独考虑 for count in tileValueArr: if tileIndex <= 0 or tileIndex >= 30: tileIndex += 1 continue if count == 4: genCount += 1 ftlog.debug("handAdd1") elif count == 3: handTileCount[3].append(tileIndex) elif count == 2: handTileCount[2].append(tileIndex) elif count == 1: handTileCount[1].append(tileIndex) tileIndex += 1 addGenCount = {} for i in range(3): if genMagicCount > 0 and len(handTileCount[i + 1]) > 0: addGenCount[i + 1], genMagicCount = self.dealWithGenCount( workTiles, handTileCount[i + 1], i + 1, genMagicCount, magicTile) else: break for i in range(3): if addGenCount.has_key(i + 1): genCount += addGenCount.get(i + 1, 0) ftlog.debug("MYunnanOneResultCalcScore GENINFO tempGenArr", tempGenArr, "genMagicCount", genMagicCount, "magicTile", magicTile, "mFactor", mFactor, "genCount", genCount, "matchedPattern", matchedPattern) return genCount, extraFan
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 checkSpecialHu(cls, tiles, magicTiles, magicTileCount, tile): # 判断七对系列 if cls.isPairs(tiles, magicTiles): return True # 判定五六七星烂,手牌数必须为14,所有花色最多一张牌,字牌不重复且大于等于5种,其它花色必须都存在且互相不靠 if cls.isLanPaiHu(tiles, magicTiles): return True # 判断其它特殊牌型 allTiles = MHand.copyAllTilesToList(tiles) tempTiles = copy.deepcopy(allTiles) for magicTile in magicTiles: while magicTile in tempTiles: tempTiles.remove(magicTile) tileArr = MTile.changeTilesToValueArr(tempTiles) colorState = MTile.getColorCount(tileArr) tempFengTiles = MTile.traverseTile(MTile.TILE_FENG) ziState = tileArr[tempFengTiles[0]:tempFengTiles[len(tempFengTiles) - 1] + 1] # menState = 0 # if len(allTiles) == 14: # menState = 1 playerGangCount = len(tiles[MHand.TYPE_GANG]) if playerGangCount >= 2 \ or colorState == 1 or colorState == 0 \ or len(tiles[MHand.TYPE_HAND]) == 2 or len(tiles[MHand.TYPE_HAND]) == 3: return True # 三元和混三元 baibanCount = cls.getZiCountByTypeBySeatId(MTile.TILE_BAI_BAN, ziState) hongzhongCount = cls.getZiCountByTypeBySeatId(MTile.TILE_HONG_ZHONG, ziState) facaiCount = cls.getZiCountByTypeBySeatId(MTile.TILE_FA_CAI, ziState) if baibanCount + magicTileCount >= 2 \ and hongzhongCount + magicTileCount >= 2 \ and facaiCount + magicTileCount >= 2: if baibanCount + hongzhongCount + magicTileCount >= 5 \ and baibanCount + facaiCount + magicTileCount >= 5 \ and hongzhongCount + facaiCount + magicTileCount >= 5: if baibanCount + hongzhongCount + facaiCount + magicTileCount >= 8: return True # 大对子,门前不能有吃,手牌多加一个赖子,能保证都是3张 if len(tiles[MHand.TYPE_CHI]) == 0: duiziTiles = copy.deepcopy(tiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in duiziTiles: duiziTiles.remove(magicTile) # 如果点炮胡,需要给牌堆里加回去一张赖子,并当普通牌处理 if tile in magicTiles: duiziTiles.append(tile) 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: return True return False
def hasChi(self, tiles, tile): """是否有吃牌解 参数说明; tiles - 玩家的所有牌,包括手牌,吃牌,碰牌,杠牌,胡牌 tile - 待吃的牌 """ if tile >= MTile.TILE_DONG_FENG: return [] chiSolutions = MChi.hasChi(tiles[MHand.TYPE_HAND], tile) magicTiles = self.tableTileMgr.getMagicTiles(False) if len(magicTiles) == 0: return chiSolutions if not self.tableTileMgr.canUseMagicTile(MTableState.TABLE_STATE_CHI): return chiSolutions magicTile = magicTiles[0] tileArr = MTile.changeTilesToValueArr(tiles[MHand.TYPE_HAND]) magicCount = tileArr[magicTile] tileArr[magicTile] = 0 ftlog.debug('MChiRule.hasChi tile:', tile, ' magicCount:', magicCount) if magicCount == 0 or (tileArr[tile] == 0): return chiSolutions if MTile.getValue(tile) <= 7: # +1[-] +2[+] ==> [tile, magic, tile+2] if tileArr[tile + 1] == 0 and tileArr[tile + 2] > 0: chiSolutions.append([tile, magicTile, tile + 2]) # +1[+] +2[-] ==> [tile, tile + 1, magicTile] if tileArr[tile + 1] > 0 and tileArr[tile + 2] == 0: chiSolutions.append([tile, tile + 1, magicTile]) if (tileArr[tile + 1] + tileArr[tile + 2]) == 0 and magicCount >= 2: chiSolutions.append([tile, magicTile, magicTile]) if MTile.getValue(tile) >= 3: # -2[+] -1[-] ==> [tile - 2, magicTile, tile] if tileArr[tile - 2] > 0 and tileArr[tile - 1] == 0: chiSolutions.append([tile - 2, magicTile, tile]) # -2[0] -1[+] ==> [magicTile, tile - 1, tile] if tileArr[tile - 2] == 0 and tileArr[tile - 1] > 0: chiSolutions.append([magicTile, tile - 1, tile]) if (tileArr[tile - 2] + tileArr[tile - 1]) == 0 and magicCount >= 2: chiSolutions.append([magicTile, magicTile, tile]) if MTile.getValue(tile) >= 2 and MTile.getValue(tile) <= 8: # -1[-] 1[+] ==> magicTile, tile, tile + 1 if tileArr[tile - 1] == 0 and tileArr[tile + 1] > 0: chiSolutions.append([magicTile, tile, tile + 1]) # -1[+] 1[-] ==> [tile - 1, tile, magicTile] if tileArr[tile - 1] > 0 and tileArr[tile + 1] == 0: chiSolutions.append([tile - 1, tile, magicTile]) if (tileArr[tile + 1] + tileArr[tile - 1]) == 0 and magicCount >= 2: chiSolutions.append([magicTile, tile, magicTile]) return chiSolutions
输入参数: playMode - 玩法 返回值: 对应玩法手牌管理器 """ if playMode == MPlayMode.HAERBIN: return MTableTileHaerbin(playerCount, playMode, runMode) elif playMode == MPlayMode.YUNNAN: return MTableTileYunnan(playerCount, playMode, runMode) elif playMode == MPlayMode.ZHAOTONG: return MTableTileZhaotong(playerCount, playMode, runMode) elif playMode == MPlayMode.JIXI: return MTableTileJixi(playerCount, playMode, runMode) elif MPlayMode().isSubPlayMode(playMode, MPlayMode.KAWUXING): return MTableTileKawuxing(playerCount, playMode, runMode) return MTableTile(playerCount, playMode, runMode) if __name__ == "__main__": tableTileMgr = MTableTileFactory.getTableTileMgr(4, MPlayMode.HAERBIN, MRunMode.CONSOLE) tableTileMgr.tileTestMgr.setHandTiles([[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]]) tableTileMgr.tileTestMgr.setTiles([9, 9, 9, 9]) tableTileMgr.shuffle(0, 13) tiles = tableTileMgr.tiles print tiles tileArr = MTile.changeTilesToValueArr(tiles) print tileArr
def hasChi(self, tiles, tile): """是否有吃牌解 参数说明; tiles - 玩家的所有牌,包括手牌,吃牌,碰牌,杠牌,胡牌 tile - 待吃的牌 """ if tile >= MTile.TILE_DONG_FENG: return [] chiSolutions = MChi.hasChi(tiles[MHand.TYPE_HAND], tile) magicTiles = self.tableTileMgr.getMagicTiles(False) if len(magicTiles) == 0: return chiSolutions if not self.tableTileMgr.canUseMagicTile(MTableState.TABLE_STATE_CHI): return chiSolutions magicTile = magicTiles[0] tileArr = MTile.changeTilesToValueArr(tiles[MHand.TYPE_HAND]) magicCount = tileArr[magicTile] tileArr[magicTile] = 0 ftlog.debug('MChiRule.hasChi tile:', tile, ' magicCount:', magicCount) if magicCount == 0 or (tileArr[tile] == 0): return chiSolutions if MTile.getValue(tile) <= 7: # +1[-] +2[+] ==> [tile, magic, tile+2] if tileArr[tile + 1] == 0 and tileArr[tile + 2] > 0: chiSolutions.append([tile, magicTile, tile + 2]) # +1[+] +2[-] ==> [tile, tile + 1, magicTile] if tileArr[tile + 1] > 0 and tileArr[tile + 2] == 0: chiSolutions.append([tile, tile + 1, magicTile]) if (tileArr[tile + 1] + tileArr[tile + 2]) == 0 and magicCount >= 2: chiSolutions.append([tile, magicTile, magicTile]) if MTile.getValue(tile) >= 3: # -2[+] -1[-] ==> [tile - 2, magicTile, tile] if tileArr[tile - 2] > 0 and tileArr[tile - 1] == 0: chiSolutions.append([tile - 2, magicTile, tile]) # -2[0] -1[+] ==> [magicTile, tile - 1, tile] if tileArr[tile - 2] == 0 and tileArr[tile - 1] > 0: chiSolutions.append([magicTile, tile - 1, tile]) if (tileArr[tile - 2] + tileArr[tile - 1]) == 0 and magicCount >= 2: chiSolutions.append([magicTile, magicTile, tile]) if MTile.getValue(tile) >= 2 and MTile.getValue(tile) <= 8: # -1[-] 1[+] ==> magicTile, tile, tile + 1 if tileArr[tile - 1] == 0 and tileArr[tile + 1] > 0: chiSolutions.append([magicTile, tile, tile + 1]) # -1[+] 1[-] ==> [tile - 1, tile, magicTile] if tileArr[tile - 1] > 0 and tileArr[tile + 1] == 0: chiSolutions.append([tile - 1, tile, magicTile]) if (tileArr[tile + 1] + tileArr[tile - 1]) == 0 and magicCount >= 2: chiSolutions.append([magicTile, tile, magicTile]) return chiSolutions
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 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 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 # 获得癞子数据 magicTiles = self.tableTileMgr.getMagicTiles() colorStateNoMagic = [0 for _ in range(self.playerCount)] magicTileCountArr = [0 for _ in range(self.playerCount)] # 处理玩家手牌,得到一手不带癞子的花色 for seatId in range(self.playerCount): tempArrColor = copy.deepcopy(playerAllTilesArr[seatId]) # colorState里面要去掉赖子包含的花色 for magicTile in magicTiles: while magicTile in tempArrColor: tempArrColor.remove(magicTile) magicTileCountArr[seatId] += 1 # 重新处理一次花色,不算赖子 colorStateNoMagic[seatId] = MTile.getColorCount( MTile.changeTilesToValueArr(tempArrColor)) if self.resultType == self.RESULT_FLOW: # 昭通的流局需要查花猪和大叫 # 查花猪,赖子不算,赖子可以算作任何已有的花色,要先处理一下赖子s pigs = [] noTings = [] tings = [] huSeats = [] for player in self.tableTileMgr.players: if player.hasHu: huSeats.append(player.curSeatId) for seatId in range(self.playerCount): if colorStateNoMagic[seatId] >= 3: pigs.append(seatId) tempScore = [0 for _ in range(self.playerCount)] if len(pigs) > 0: pigInfo = { 'pigs': pigs, 'playerCount': self.playerCount, 'scoreBase': baseScore, 'fanMax': 4, 'huSeats': [] } # 会修改传入的score参数 self.calcPigsScore(pigInfo, tempScore) self.setPigs(pigs) ftlog.debug( "MYunnanOneResult calcScore Type = RESULT_FLOW calcPigsScore tempScore:", tempScore) # 开始查大叫 # 查大叫, # 多给一个赖子能胡牌就算有叫 for seatId in range(self.playerCount): if seatId in pigs or seatId in huSeats: continue zhaoTongRule = MWinRuleZhaotong() tempNoTingTiles = copy.deepcopy(playerAllTiles[seatId]) tempNoTingTiles[MHand.TYPE_HAND].append(magicTiles[0]) result, _ = zhaoTongRule.checkHuByMagicTiles( tempNoTingTiles, magicTiles) if result: tings.append(seatId) else: noTings.append(seatId) fanTings = [0 for _ in range(self.playerCount)] # 计算听牌人的番型 for ting in tings: # 番型 fanData = {'fan': 0, 'patterns': [], 'isUnique': False} fan = 1 patterns = [] isUnique = fanData.get('isUnique', False) tempTingTiles = copy.deepcopy(playerAllTiles[ting]) tempTingTiles[MHand.TYPE_HAND].append(magicTiles[0]) # 取出dropTiles和手牌 dropTiles = self.tableTileMgr.dropTiles[ting] # 计算根,修改传入的fanData参数 self.calcFanGen(fanData, tempTingTiles, magicTiles) # 七对必须门清,修改传入的fanData参数 self.calcFanPairsSeven(fanData, tempTingTiles, magicTiles) # 没听用,只要有听用就不算,不管用不用来当赖子 self.calcFanNoTingYong(fanData, playerAllTilesArr[ting], magicTiles) isDaduizi = False magicCount = 0 # 大对子,门前不能有吃,手牌多加一个赖子,能保证都是3张 if len(tempTingTiles[MHand.TYPE_CHI]) == 0: duiziTiles = copy.deepcopy(tempTingTiles[MHand.TYPE_HAND]) for magicTile in magicTiles: while magicTile in duiziTiles: duiziTiles.remove(magicTile) magicCount += 1 duiziArr = MTile.changeTilesToValueArr(duiziTiles) ftlog.debug("MYunnanOneResult duiziArr = ", duiziArr) cardTypeCount = 0 # 假设多一张赖子 duiziMagicCount = magicCount + 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.DUIDUIHU]['name']) fan += self.fanXing[self.DUIDUIHU]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) isDaduizi = True # 清一色 if colorStateNoMagic[ting] == 1: if isDaduizi: if not isUnique: if self.fanXing[self.DUIDUIHU]['name'] in patterns: patterns.remove( self.fanXing[self.DUIDUIHU]['name']) patterns.append( self.fanXing[self.QINGYISEDADUIZI]['name']) fan -= self.fanXing[self.DUIDUIHU]['index'] fan += self.fanXing[self.QINGYISEDADUIZI]['index'] ftlog.debug("MYunnanOneResult fanxing = ", patterns, "fan = ", fan) else: if not isUnique: patterns.append( self.fanXing[self.QINGYISE]['name']) fan += self.fanXing[self.QINGYISE]['index'] ftlog.debug("MYunnanOneResuFlt fanxing = ", patterns, "fan = ", fan) fanData['fan'] = fanData['fan'] + fan fanData['patterns'].extend(patterns) ftlog.debug("MYunnanOneResult gameFlow fanData = ", fanData) fanTings[ting] = fanData.get('fan', 0) # 打出过赖子最大只能胡一番 for magicTile in magicTiles: if magicTile in dropTiles: if fanTings[ting] > 1: fanTings[ting] = 1 if fanTings[ting] >= 5: fanTings[ting] = 5 if len(noTings) > 0: tingInfo = { 'noTings': noTings, 'tings': tings, 'scoreBase': baseScore, 'fanArr': fanTings } self.calcTingScore(tingInfo, tempScore) self.setNoTings(noTings) ftlog.debug( "MYunnanOneResult calcScore Type = RESULT_FLOW calcTingScore tempScore:", tempScore) self.results[self.KEY_TYPE] = MOneResult.KEY_TYPE_NAME_FLOW self.results[self.KEY_SCORE] = tempScore # 如果是最终结算,把数据取出来放在results里 for seatId in huSeats: result = self.winRuleMgr.getHasHuDataBySeatId(seatId) if result: self.results[self.KEY_WIN_MODE][seatId] = result.get( 'winMode', -1) self.results[self.KEY_FAN_PATTERN][seatId] = result.get( 'fan', []) self.results[self.KEY_WIN_TILE][seatId] = result.get( 'winTile', 0) # 清空保存的这些数据 self.winRuleMgr.clearHasHuData() 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 maxFan = 0 # 计算胡牌者的番型和分数 for seatId in self.winSeats: # 番型 fanData = { 'fan': 0, 'patterns': [], 'isUnique': False, 'isSpecial': False } ftlog.debug("MYunnanOneResultCalcScorelatestGangState = ", self.latestGangState) ftlog.debug( 'MajiangTableLogic.gameWin.yipaoduoxiang dealwith seatId:', seatId, 'lastSeatId:', self.lastSeatId, 'winSeatId:', self.winSeatId, 'self.winSeats:', self.winSeats, 'self.actionID:', self.actionID, 'self.bankerSeatId:', self.bankerSeatId) 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 # 取出dropTiles和手牌 dropTiles = self.tableTileMgr.dropTiles[seatId] nowTiles = playerAllTiles[seatId] nowTiles[MHand.TYPE_HAND].append(self.winTile) # 计算根 self.calcFanGen(fanData, nowTiles, magicTiles) # 杠上花和杠上炮 self.calcFanAfterGang(fanData, self.latestGangState, seatId, self.lastSeatId) # 天胡地胡,没有出过牌,没有吃碰杠 self.calcFanTianDiHu(fanData, seatId, self.bankerSeatId, self.lastSeatId, nowTiles, dropTiles) # 七对必须门清 self.calcFanPairsSeven(fanData, nowTiles, magicTiles) # 没听用,只要有听用就不算,不管用不用来当赖子 self.calcFanNoTingYong(fanData, playerAllTilesArr[seatId], magicTiles) # 大对子,门前不能有吃,手牌多加一个赖子,能保证都是3张 isDaduizi = False _, _, _, isDaduizi = self.calcFanDaduizi(fanData, nowTiles, magicTiles, magicTileCountArr[seatId], self.winTile, seatId, self.lastSeatId) # 清一色 self.calcFanQingyise(fanData, colorStateNoMagic[seatId], isDaduizi) # 自摸是否加番的处理 if self.winRuleMgr.zimoBonus == 2: if self.lastSeatId == seatId: fanData['fan'] += 1 # 如果对对胡,清一色,七对,龙七对,天胡,地胡,双龙对,清一色大对子,当不存在以上番型时 有平胡的1番 if not fanData.get('isSpecial', False): fanData['fan'] += 1 ftlog.debug("MYunnanOneResult fanData = ", fanData) self.results[self.KEY_WIN_TILE][seatId] = self.winTile self.results[self.KEY_FAN_PATTERN][seatId] = copy.deepcopy( fanData['patterns']) fanArr[seatId] = fanData.get('fan', 0) # 打出过赖子最大只能胡一番 for magicTile in magicTiles: if magicTile in dropTiles: if fanArr[seatId] > 1: fanArr[seatId] = 1 if fanArr[seatId] > maxFan: maxFan = fanArr[seatId] 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: maxFan}) # 番数上限5 for win in self.winSeats: if fanArr[win] > 5: fanArr[win] = 5 # 把血战里面已经胡牌的人的位置挑出来 hasHu = [] for player in self.tableTileMgr.players: if player.hasHu: hasHu.append(player.curSeatId) if len(hasHu) >= self.playerCount - 1: ftlog.error("MZhaotongOneReuslt hasHu Error hasHu:", hasHu) # 计算积分 # winScore = baseScore*(self.multiple) winScore = baseScore if self.qiangGang: # 如果是最后一个输的人被抢杠胡,需要把被抢的牌从他手中拿掉 if len(hasHu) + len(self.winSeats) >= self.playerCount - 1: for player in self.tableTileMgr.players: if player.curSeatId == self.lastSeatId and self.lastSeatId not in self.winSeats: if self.winTile in player.handTiles: player.handTiles.remove(self.winTile) else: player.handTiles.remove(magicTiles[0]) for seatId in self.winSeats: self.results[self.KEY_WIN_MODE][ seatId] = MOneResult.WIN_MODE_QIANGGANGHU # 计算分数增减 if self.lastSeatId in self.winSeats: for i in range(self.playerCount): if self.lastSeatId == i: looseCount = self.playerCount - 1 - len(hasHu) if looseCount <= 0: looseCount = 1 self.results[self.KEY_SCORE][i] = winScore * (2**( fanArr[i] - 1)) * looseCount elif i in hasHu: continue else: self.results[self.KEY_SCORE][i] = -winScore * (2**( fanArr[self.lastSeatId] - 1)) else: dianPaoScore = 0 for i in range(self.playerCount): if i in self.winSeats: if i not in hasHu: self.results[self.KEY_SCORE][i] = winScore * (2**( fanArr[i] - 1)) dianPaoScore += winScore * (2**(fanArr[i] - 1)) self.results[self.KEY_SCORE][self.lastSeatId] = -dianPaoScore if self.playerCount - len(hasHu) - len(self.winSeats) == 1: # 如果是最终结算,把数据取出来放在results里 for seatId in hasHu: result = self.winRuleMgr.getHasHuDataBySeatId(seatId) if result: self.results[self.KEY_WIN_MODE][seatId] = result.get( 'winMode', -1) self.results[self.KEY_FAN_PATTERN][seatId] = result.get( 'fan', []) self.results[self.KEY_WIN_TILE][seatId] = result.get( 'winTile', 0) # 清空保存的这些数据 self.winRuleMgr.clearHasHuData() else: # 如果不是最终结算,把胜者的一些信息存起来 for seatId in self.winSeats: result = { 'winMode': self.results[self.KEY_WIN_MODE][seatId], 'fan': self.results[self.KEY_FAN_PATTERN][seatId], 'winTile': self.results[self.KEY_WIN_TILE][seatId] } self.winRuleMgr.saveHasHuData(result, seatId) 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 getTableTileMgr(cls, playerCount, playMode, runMode): """牌桌手牌管理器获取工厂 输入参数: playMode - 玩法 返回值: 对应玩法手牌管理器 """ if playMode == MPlayMode.HAERBIN: return MTableTileHaerbin(playerCount, playMode, runMode) elif playMode == MPlayMode.YUNNAN: return MTableTileYunnan(playerCount, playMode, runMode) elif playMode == MPlayMode.ZHAOTONG: return MTableTileZhaotong(playerCount, playMode, runMode) elif playMode == MPlayMode.JIXI: return MTableTileJixi(playerCount, playMode, runMode) elif MPlayMode().isSubPlayMode(playMode, MPlayMode.KAWUXING): return MTableTileKawuxing(playerCount, playMode, runMode) return MTableTile(playerCount, playMode, runMode) if __name__ == "__main__": tableTileMgr = MTableTileFactory.getTableTileMgr(4, MPlayMode.HAERBIN, MRunMode.CONSOLE) tableTileMgr.tileTestMgr.setHandTiles([[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]]) tableTileMgr.tileTestMgr.setTiles([9, 9, 9, 9]) tableTileMgr.shuffle(0, 13) tiles = tableTileMgr.tiles print tiles tileArr = MTile.changeTilesToValueArr(tiles) print tileArr