def doQingYiSe(self, allTiles, leftTiles, seatId, abColors): ''' 是否做清一色 ''' isSanSha, bestColor = self.isSanShaQingYiSe(seatId, abColors) if isSanSha: ftlog.debug('SanSha, best situation!!! doSanShaQingYiSe') return True, bestColor length = 9 if len(leftTiles) >= 50: length = 8 elif len(leftTiles) >= 40: length = 9 elif len(leftTiles) >= 30: length = 10 elif len(leftTiles) >= 20: length = 11 allTilesArr = MHand.copyAllTilesToList(allTiles) cpgTiles = MHand.copyTiles( allTiles, [MHand.TYPE_CHI, MHand.TYPE_PENG, MHand.TYPE_GANG]) wans = MTile.filterTiles(allTilesArr, MTile.TILE_WAN) wanLength = len(wans) if wanLength >= length: for tile in cpgTiles: if MTile.getColor(tile) != MTile.TILE_WAN: return False, MTile.TILE_FENG return True, MTile.TILE_WAN tongs = MTile.filterTiles(allTilesArr, MTile.TILE_TONG) tongLength = len(tongs) if tongLength >= length: for tile in cpgTiles: if MTile.getColor(tile) != MTile.TILE_TONG: return False, MTile.TILE_FENG return True, MTile.TILE_TONG tiaos = MTile.filterTiles(allTilesArr, MTile.TILE_TIAO) tiaoLength = len(tiaos) if tiaoLength >= length: for tile in cpgTiles: if MTile.getColor(tile) != MTile.TILE_TIAO: return False, MTile.TILE_FENG return True, MTile.TILE_TIAO if wanLength >= tongLength and wanLength >= tiaoLength: return False, MTile.TILE_WAN elif tongLength >= wanLength and tongLength >= tiaoLength: return False, MTile.TILE_TONG else: return False, MTile.TILE_TIAO
def isTing(self, allTiles, dropTile, leftTiles, seatResponse=False, extend={}): ''' 是否听牌 ''' ftlog.debug('isTing allTiles:', allTiles, ' dropTile:', dropTile, ' leftTiles:', leftTiles, ' seatResponse:', seatResponse) if seatResponse: return True seatId = extend.get('seatId', None) abColors = extend.get('absenceColor', None) doQing, qingColor = self.doQingYiSe(allTiles, leftTiles, seatId, abColors) if doQing: handTiles = copy.deepcopy(allTiles[MHand.TYPE_HAND]) handColors = MTile.filterTiles(handTiles, qingColor) if (MTile.getColor(dropTile) == qingColor) and (len(handTiles) != len(handColors)): ftlog.debug('handTiles:', handTiles, ' handColors:', handColors, ' dropTile:', dropTile, ' doQingYiSe, do not drop...') return False return True
def sortHandTileColor(self, players, isAbsence=True): ''' 玩家手牌花色排序计算,保存到__hand_tile_sort,相应玩法各自实现 定缺的颜色不用判断,在最右边,只需要判断没有定缺的 定缺结束后,额外处理定缺的花色排序 初始化手牌 则不用 ''' TILE_COLORS = [MTile.TILE_WAN, MTile.TILE_TONG, MTile.TILE_TIAO] colorList = [[] for _ in range(self.playCount)] for cp in players: if not cp: continue handTiles = cp.copyHandTiles() colorLenList = [] for color in TILE_COLORS: if isAbsence and color == self.absenceColors[cp.curSeatId]: pass else: colorTiles = MTile.filterTiles(handTiles, color) colorLenList.append({ 'color': color, 'len': len(colorTiles) }) # 根据len来进行排序 colorLenList.sort(key=lambda colorLen: colorLen['len'], reverse=True) for cpColor in colorLenList: colorList[cp.curSeatId].append(cpColor['color']) # 加上定缺的花色 if isAbsence: colorList[cp.curSeatId].append( self.absenceColors[cp.curSeatId]) ftlog.debug('MTableTileSiChuan.sortHandTileColor cpColorList:', colorList) self.setHandTileColorSort(colorList)
def doQingYiSe(self, allTiles, leftTiles): ''' 是否做清一色 ''' length = 9 if len(leftTiles) >= 50: length = 8 elif len(leftTiles) >= 40: length = 9 elif len(leftTiles) >= 30: length = 10 elif len(leftTiles) >= 20: length = 11 allTilesArr = MHand.copyAllTilesToList(allTiles) cpgTiles = MHand.copyTiles( allTiles, [MHand.TYPE_CHI, MHand.TYPE_PENG, MHand.TYPE_GANG]) wans = MTile.filterTiles(allTilesArr, MTile.TILE_WAN) wanLength = len(wans) if wanLength >= length: for tile in cpgTiles: if MTile.getColor(tile) != MTile.TILE_WAN: return False, MTile.TILE_FENG return True, MTile.TILE_WAN tongs = MTile.filterTiles(allTilesArr, MTile.TILE_TONG) tongLength = len(tongs) if tongLength >= length: for tile in cpgTiles: if MTile.getColor(tile) != MTile.TILE_TONG: return False, MTile.TILE_FENG return True, MTile.TILE_TONG tiaos = MTile.filterTiles(allTilesArr, MTile.TILE_TIAO) tiaoLength = len(tiaos) if tiaoLength >= length: for tile in cpgTiles: if MTile.getColor(tile) != MTile.TILE_TIAO: return False, MTile.TILE_FENG return True, MTile.TILE_TIAO if wanLength >= tongLength and wanLength >= tiaoLength: return False, MTile.TILE_WAN elif tongLength >= wanLength and tongLength >= tiaoLength: return False, MTile.TILE_TONG else: return False, MTile.TILE_TIAO
def getBestDropTile(cls, tiles_player_hand, tiles_left, playMode, tile, isTing, magicTiles, absenceColor, tingRule=None, seatId=0): """ 手牌的价值,根据玩家自己的手牌和已经出的牌,计算手牌价值 参数: tiles_player_hand - 用户的手牌 tiles_droped - 牌桌上已经打出的牌和玩家手里已经成型的牌,这部分牌不再参与计算牌的可能性 计算方法: 1)没有的手牌,权值为0 2)有的手牌,初始权值为4 * count + 1 * left 3)左右相邻的手牌,增加权重 3 * count 4)左右隔一张的手牌,增加权重 2 * count """ ftlog.debug('MTileValue.getBestDropTile tiles_player_hand:', tiles_player_hand, ' tiles_left:', tiles_left, ' playMode:', playMode, ' tile:', tile, ' isTing:', isTing, ' magicTiles:', magicTiles, ' tingRule:', tingRule, ' seatId:', seatId) if isTing: # 听牌后,直接打出摸到的牌 return tile, 0 tiles_value_Arr, tiles_player_Arr = cls.getHandTilesValue( tiles_player_hand, tiles_left) # 放大癞子牌的作用 for mTile in magicTiles: tiles_value_Arr[mTile] = tiles_value_Arr[mTile] * 100 # 如果有一门花色大于9张牌,放大该门花色牌的价值,便于去做清一色番型 allTiles = MHand.copyAllTilesToList(tiles_player_hand) wans = MTile.filterTiles(allTiles, MTile.TILE_WAN) if len(wans) >= 9: for tile in MTile.traverseTile(MTile.TILE_WAN): tiles_value_Arr[tile] += 10 tongs = MTile.filterTiles(allTiles, MTile.TILE_TONG) if len(tongs) >= 9: for tile in MTile.traverseTile(MTile.TILE_TONG): tiles_value_Arr[tile] += 10 tiaos = MTile.filterTiles(allTiles, MTile.TILE_TIAO) if len(tiaos) >= 9: for tile in MTile.traverseTile(MTile.TILE_TIAO): tiles_value_Arr[tile] += 10 fengs = MTile.filterTiles(allTiles, MTile.TILE_FENG) if len(fengs) >= 9: for tile in MTile.traverseTile(MTile.TILE_FENG): tiles_value_Arr[tile] += 10 # 减小缺牌的作用 for tile in range(len(tiles_value_Arr)): if MTile.getColor(tile) == absenceColor: tiles_value_Arr[tile] -= 100 # [{'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 tingRule: canTing, tingResults = tingRule.canTing(tiles_player_hand, tiles_left, tile, magicTiles) ftlog.debug(canTing) ftlog.debug(tingResults) if canTing: for tingResult in tingResults: dropTile = tingResult['dropTile'] winNodes = tingResult['winNodes'] outs = 0 for winNode in winNodes: outs += winNode['winTileCount'] tiles_value_Arr[dropTile] = (0 - outs) minTile = 0 minValue = 0 for index in range(MTile.TILE_MAX_VALUE): if tiles_player_Arr[index] > 0: if minTile == 0: minTile = index minValue = tiles_value_Arr[index] continue if minValue > tiles_value_Arr[index]: minValue = tiles_value_Arr[index] minTile = index ftlog.debug('MTileValue.getBestDropTile minTile:', minTile, ' tileValue:', tiles_value_Arr[minTile]) return minTile, tiles_value_Arr[minTile]
def autoProcessAddCard(self, nPause): ''' 自动处理摸牌 ''' player = self.table.addCardProcessor.getPlayer() nowTile = self.table.addCardProcessor.getTile() extendStrategyInfo = self.getExtendStrategyInfo(player) # 海底且不出牌时,gameNext if self.table.tableTileMgr.isHaidilao() \ and (not self.table.tableTileMgr.canDropWhenHaidiLao()) \ and (not self.table.addCardProcessor.getState() & MTableState.TABLE_STATE_HU): self.table.addCardProcessor.reset() self.table.gameNext() return if (player.isRobot() and self.isRobotFoolish()) or \ ((not player.isRobot()) and player.autoDecide and self.isHumanAutoDecideFoolish(player)): ''' AI是傻瓜级别,抓什么打什么 如果有缺牌,则自动打出缺牌 如果nowTile是缺牌,则优先打出nowTile 如果没有缺牌并且nowTile也不是缺牌,则打出nowTile ''' if self.table.checkTableState(MTableState.TABLE_STATE_ABSENCE): abColor = self.table.getAbsenceColor(player.curSeatId) hands = player.copyHandTiles() abTiles = MTile.filterTiles(hands, abColor) if (len(abTiles) > 0) and (nowTile not in abTiles): nowTile = abTiles[0] # 剔除赖子 hands = player.copyHandTiles() mts = self.table.tableTileMgr.getMagicTiles() afterTiles = MTile.filterMagicTiles(hands, mts) ftlog.debug('autoProcessAddCard:', nowTile,hands,afterTiles) if nowTile not in afterTiles: if (len(afterTiles) > 0): nowTile = afterTiles[-1] self.table.dropTile(player.curSeatId, nowTile) return self.consumeSmartOperateCount(player) exInfo = self.table.addCardProcessor.extendInfo winScore = 0 if self.table.addCardProcessor.getState() & MTableState.TABLE_STATE_HU: winScore = player.getTingResultScore(MWinRule.WIN_BY_MYSELF) tingScore = 0 tingInfo = None # 添加判断条件玩家是否胡牌,胡牌后,不走听 if (self.table.addCardProcessor.getState() & MTableState.TABLE_STATE_TING) and not player.isWon(): tingInfo = exInfo.getChoosedInfo(MTableState.TABLE_STATE_TING) ftlog.debug('ActionHandler.autoProcessAddCard tingInfo:', tingInfo) tingScore = tingInfo.get('value', 0) if (self.table.addCardProcessor.getState() & MTableState.TABLE_STATE_HU) and (winScore >= tingScore): self.table.gameWin(player.curSeatId, nowTile) return if (self.table.addCardProcessor.getState() & MTableState.TABLE_STATE_TING) and (not player.isWon()): if self.table.addCardProcessor.getState() & MTableState.TABLE_STATE_GANG: gangs = exInfo.getChiPengGangResult(MTableState.TABLE_STATE_GANG) allDropTilesInTing = exInfo.getAllDropTilesInTing() for gangInfo in gangs: if gangInfo['pattern'][0] in allDropTilesInTing: style = gangInfo['style'] pattern = gangInfo['pattern'] special_tile = self.getPiguTile() self.table.gangTile(player.curSeatId, gangInfo['pattern'][0], pattern, style, MTableState.TABLE_STATE_GANG, special_tile) return # 选择打掉的牌,用剩下的牌听,自动选择可胡牌数最多的解,默认不扣任何牌 if tingInfo and self.table.dropCardStrategy.isTing(player.copyTiles() , tingInfo['dropTile'] , self.table.tableTileMgr.getTiles() , False , extendStrategyInfo ): self.table.tingAfterDropCard(player.curSeatId, tingInfo['dropTile'], True, [], self.table.addCardProcessor.extendInfo) return ftlog.debug('ActionHandler.autoProcessAddCard player.copyTiles:', player.copyTiles(), 'isStateFixeder:', player.isStateFixeder()) minTile, minValue = self.table.dropCardStrategy.getBestDropTile(player.copyTiles() , self.table.tableTileMgr.getTiles() , nowTile , player.isStateFixeder() , self.table.tableTileMgr.getMagicTiles(player.isTing()) , extendStrategyInfo) ftlog.debug('ActionHandler.getBestDropTile minTile:', minTile, ' minValue:', minValue) if self.table.addCardProcessor.getState() & MTableState.TABLE_STATE_GANG: gangInfo = exInfo.getChoosedInfo(MTableState.TABLE_STATE_GANG) # 第一种情况,当前策略允许杠 if self.table.dropCardStrategy.isGang(player.copyTiles() , nowTile , gangInfo , self.table.tableTileMgr.getTiles() , player.tingResult , False , extendStrategyInfo): exInfo.updateState(MTableState.TABLE_STATE_GANG, gangInfo) ftlog.debug('ActionHandler.autoProcessAddCard gangInfo:', gangInfo , ' strategy decide gang') style = gangInfo['style'] pattern = gangInfo['pattern'] special_tile = self.getPiguTile() self.table.gangTile(player.curSeatId, nowTile, pattern, style, MTableState.TABLE_STATE_GANG, special_tile) return # 第二种情况,当前的最佳出牌是杠牌 gangs = exInfo.getChiPengGangResult(MTableState.TABLE_STATE_GANG) for gangInfo in gangs: gangTile = gangInfo['pattern'][0] if gangTile != minTile: continue exInfo.updateState(MTableState.TABLE_STATE_GANG, gangInfo) ftlog.debug('ActionHandler.autoProcessAddCard gangInfo:', gangInfo , ' gangTile:', gangTile , ' minTile:', minTile , ' gangTile same with minTile, gang!!!') style = gangInfo['style'] pattern = gangInfo['pattern'] special_tile = self.getPiguTile() self.table.gangTile(player.curSeatId, nowTile, pattern, style, MTableState.TABLE_STATE_GANG, special_tile) return # 最后,出价值最小的牌 self.table.tingAfterDropCard(player.curSeatId, minTile, player.isTing(), [], exInfo)