def __init__(self, card_type_list=[CardType.WAN]): self.card_range = [] for t in card_type_list: self.card_range.append([ Card.cal_card_val(t, 1), Card.cal_card_val(t, CARD_SIZE[t] - 1) ])
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生暗杠操作 logger.debug(u"act_an_gang_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] # TODO 此处需要接受参数 用户选择暗杠牌值 used_card = params.get("used_card")[0] # card_val = self.game_data.last_chu_card_val if not used_card: logger.error("an_gang params error: %s", str([seat_id, params])) return hand_card = self.players[seat_id].hand_card if 4 != hand_card.hand_card_info[Card.cal_card_type(used_card)][ Card.cal_card_digit(used_card)]: logger.error("an_gang params error: %s", str([seat_id, params])) return self.seat_id = seat_id self.used_card = used_card return 1
def has_card(self, card_val): """ 是否有指定的手牌 :param card_val: :return: 返回张数 """ return self.hand_card_info[Card.cal_card_type(card_val)][ Card.cal_card_digit(card_val)]
def add_hand_card_by_vals(self, card_vals=[]): if not card_vals: return for v in card_vals: card_type = Card.cal_card_type(v) card_digit = Card.cal_card_digit(v) self.hand_card_info[card_type][card_digit] += 1 self.hand_card_info[card_type][0] += 1 self.last_card_val = card_vals[-1]
def get_can_peng_info_by_handcard(self, card, hand_card): """ 判断某张牌是否可以碰 :param card: 待判断的牌 :param cur_card_list: 当前手牌 :return: 返回是否可碰牌 """ card_type = Card.cal_card_type(card) card_digit = Card.cal_card_digit(card) return 2 <= hand_card.hand_card_info[card_type][card_digit]
def get_can_dian_gang_info_by_handcard(self, card, hand_card): """ 判断某张牌是否可以杠(点杠) :param card: 待判断的牌 :param cur_card_list: 当前手牌 :return: 返回是否可杠牌 """ card_type = Card.cal_card_type(card) card_digit = Card.cal_card_digit(card) return 4 == hand_card.hand_card_info[card_type][card_digit]
def can_bu_gang(self, hand_card): """是否可以补杠""" all_types = CardType.all_type() can_bu_gang_cards = [] for t in all_types: if 1 > hand_card.hand_card_info[t][0]: continue for i in range(1, CARD_SIZE[t]): if 1 == hand_card.hand_card_info[t][i]: card_val = Card.cal_card_val(t, i) for peng_group in hand_card.peng_card_vals: if card_val in peng_group: if self.players[self.seat_id].ting_info: # 玩家处于听牌状态, 判断补杠后会否破坏牌型 temp_cards = self.players[ self.seat_id].hand_card.hand_card_vals temp_cards.remove(card_val) temp_cards.append(LAI_ZI) ting_cards = self.card_analyse.get_can_ting_info_by_val( temp_cards) ret = [] for k in ting_cards.keys(): ret.extend(ting_cards[k]) if not set(self.players[self.seat_id].ting_info .keys()).issubset(set(ret)): # 如果新的听牌结果不包含原有听牌结果,则不能点杠 print( "seat=%s, card_val=%s, ting_cards=%s , can't ting!" % (self.seat_id, card_val, ting_cards)) else: can_bu_gang_cards.append(card_val) else: can_bu_gang_cards.append(card_val) return can_bu_gang_cards
def get_can_chi_info_by_val(self, card, cur_card_list): """ 判断某张牌是否可以吃 :param card: 待判断的牌 :param cur_card_list: 当前手牌 :return: 返回吃牌的组合[[], [], ...] """ if not Card.has_shun(card): return [] tmp = [] for i in range(card + 2, card - 3, -1): if i in tmp: continue if i == card: tmp.append(i) else: if i in cur_card_list: tmp.append(i) result = [] num = len(tmp) if 3 > num: return [] for j in range(num - 2): if self.hu_analyse.shun(tmp[j:j + 3]): result.append(tmp[j:j + 3]) return result
def bu_hua(self): """检查是否补花""" hua_card = [] for c in self.drew_cardvals: if CardType.HUA == Card.cal_card_type(c): hua_card.append(c) if not hua_card: return 0 logger.debug('补花:%d', len(hua_card)) # 将花牌从手牌中移除 self.players[self.seat_id].hand_card.del_hand_card_by_val(hua_card[0]) # 将补花数量添加进手牌中 self.players[self.seat_id].hand_card.hua_card_vals.extend(hua_card) # 通知所有人有玩家补花 notify_all_desk_player(self.desk_id, PUSH_GAME_BU_HUA, { "seat_id": self.seat_id, "hua_card_list": hua_card }) timer_manager_ins.add_timer(self.desk_id, self.seat_id, GlobalConfig().bu_hua_show_time, t_type=TimerType.KEEP, call_type=CallbackFuncType.FUNC_DRAW_CARD, call_params={ "seat_id": self.seat_id, "card_num": len(hua_card), "is_last": True }) return 1
def bu_hua(self, seat_id, card_list=[]): """检查是否补花""" hua_card = [] tmp_card_list = copy.deepcopy(card_list) for c in tmp_card_list: if CardType.HUA == Card.cal_card_type(c): hua_card.append(c) card_list.remove(c) if not hua_card: return 0 logger.debug('发牌补花:%d', len(hua_card)) new_cards = [] temp_hua = copy.deepcopy(hua_card) while temp_hua: cards = self.card_dealer.draw_cards(num=len(temp_hua), is_last=True) temp_hua = [] for c in cards: if CardType.HUA == Card.cal_card_type(c): temp_hua.append(c) hua_card.append(c) else: new_cards.append(c) card_list.extend(new_cards) # 将补花数量添加进手牌中 hua_card_vals 中 self.players[seat_id].hand_card.hua_card_vals.extend(hua_card) for p in self.players: if p.seat_id == seat_id: notify_single_user(self.desk_id, p.seat_id, message_ids.PUSH_GAME_DEAL_BU_HUA, data={ "seat_id": seat_id, "hua_card": hua_card, "bu_cards": new_cards }) else: notify_single_user(self.desk_id, p.seat_id, message_ids.PUSH_GAME_DEAL_BU_HUA, data={ "seat_id": seat_id, "hua_card": hua_card, "bu_cards": [BLACK] * len(new_cards) }) return 1
def trans_non_num_card_to_gap(self, card_list): """ 将非数字牌(风,箭,字,花)值转换成 间断的,避免误判为顺子 :param card_list: :return: """ result = [] for c in card_list: if c == LAI_ZI: result.append(c) continue t = Card.cal_card_type(c) if CardType.HUA == t: continue if t in [CardType.FENG, CardType.JIAN]: result.append(Card.cal_card_val(t, Card.cal_card_digit(c) * 3)) else: result.append(c) return result
def hand_card_vals(self): ret = [] for k, v in self.hand_card_info.items(): if v[0] == 0: continue for i in range(1, CARD_SIZE[k]): if v[i] == 0: continue for j in range(0, v[i]): ret.append(Card.cal_card_val(k, i)) return ret
def clear_data(self): self.card_count = 0 self.all_card_vals = [] for t in self.types: for d in range(1, CARD_SIZE[t]): for k in range(0, 4 if t != CardType.HUA else 1): self.all_card_vals.append(Card.cal_card_val(t, d)) self.card_count += 1 self.left_index = 0 self.right_index = self.card_count - 1
def is_this_type(self, hand_card, card_analyse): used_card_type = [CardType.WAN] # 此游戏中使用的花色 union_card = hand_card.union_card_info gang_lst = [] gang_lst.extend(hand_card.dian_gang_card_vals) gang_lst.extend(hand_card.bu_gang_card_vals) gang_lst.extend(hand_card.an_gang_card_vals) ret = [] # 手里有4张的牌集 for i, count in enumerate(union_card[CardType.WAN]): if i == 0 and count < 4: return False if count == 4 and Card.cal_card_val(CardType.WAN, i) not in gang_lst: ret.append(Card.cal_card_val(CardType.WAN, i)) if not ret: return False gang_lst = self.get_gang_lst(hand_card) for i in ret: if i in gang_lst: return False return True
def union_hand_card(self): """ 将现有手牌联合在一起 :return: """ all_types = CardType.all_type() for t in all_types: self.union_card_info[t] = [0 for _ in range(CARD_SIZE[t])] tmp_hand_card = copy.deepcopy(self.hand_card_for_settle_show) for card_group in tmp_hand_card: if 4 == len(card_group): card_group[1] = card_group[0] card_group[2] = card_group[0] card_group[3] = card_group[0] card_group.pop() for card_val in card_group: if card_val: card_type = Card.cal_card_type(card_val) card_digit = Card.cal_card_digit(card_val) self.union_card_info[card_type][card_digit] += 1 self.union_card_info[card_type][0] += 1
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生点杠操作 logger.debug(u"act_diangang_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] card_val = self.game_data.last_chu_card_val if not card_val or -1 == self.game_data.last_chu_card_seat_id: logger.error("dian_gang params error: %s", str([seat_id, params])) return hand_card = self.players[seat_id].hand_card if 3 != hand_card.hand_card_info[Card.cal_card_type(card_val)][Card.cal_card_digit(card_val)]: logger.error("dian_gang params error: %s", str([seat_id, params])) return self.seat_id = seat_id self.hand_card = self.game_data.players[seat_id].hand_card return 1
def can_an_gang(self, hand_card): """是否可以暗杠""" if self.players[self.seat_id].ting_info: # 玩家处于听牌状态 return [] all_types = CardType.all_type() can_an_gang_cards = [] for t in all_types: if 4 > hand_card.hand_card_info[t][0]: continue for i in range(1, CARD_SIZE[t]): if 4 == hand_card.hand_card_info[t][i]: can_an_gang_cards.append(Card.cal_card_val(t, i)) return can_an_gang_cards
def get_hu_detail(self, card_list): """ 胡牌判断 :param card_list: 牌值列表 :return: 返回所有胡牌详细信息[胡法1, 胡法2, ...] 胡法1 = [[将牌], [[顺子/刻子1], [顺子/刻子2], ...]]] """ temp_card_list = copy.deepcopy(card_list) rst = [] for c in temp_card_list: if CardType.HUA == Card.cal_card_type(c): # 如果牌中有花,则不能为屁胡 return rst num_len = len(card_list) if num_len % 3 == 2: card_list.sort(key=lambda x: -x) card_list = self.trans_non_num_card_to_gap(card_list) jiang = [] tmpset = set() # 首先求出所有的将牌组合 for i in range(num_len - 1): for j in range(i + 1, num_len): if card_list[i] == card_list[ j] or card_list[i] + card_list[j] > LAI_ZI: if card_list[i] * LAI_ZI + card_list[j] not in tmpset: jiang.append([card_list[i], card_list[j]]) tmpset.add(card_list[i] * LAI_ZI + card_list[j]) for it in jiang: tmp = self._delete(card_list, it) jp = [x for x in tmp if x >= LAI_ZI] lp = [x for x in tmp if x < LAI_ZI] # jp = filter(lambda x: x >= LAI_ZI, tmp) # lp = filter(lambda x: x < LAI_ZI, tmp) rst += list(map(lambda x: [it, x], self.hu(jp, lp))) rst = self.trans_non_num_card_from_gap_plus(rst) return rst
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生出牌操作 logger.debug(u"act_chu_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] card_val = params.get("card", None) if isinstance(card_val, list): card_val = card_val[0] if not card_val: logger.debug(u"chu_card error: card_val=%s", str(card_val)) return if 1 > self.players[seat_id].hand_card.hand_card_info[Card.cal_card_type(card_val)][Card.cal_card_digit(card_val)]: logger.debug(u"chu_card error: not hava card %s", str([seat_id, params])) return self.seat_id = seat_id self.chu_cardval = card_val return 1
def trans_non_num_card_from_gap(self, card_list): """ 将间断的非数字牌(风,箭,字,花)值转换成原始值 :param card_list: :return: """ ret = [[] for _ in range(len(card_list))] for f, cards in enumerate(card_list): jiang = copy.deepcopy(cards[0]) other_card = copy.deepcopy(cards[1]) jiang_vals = jiang[0] if jiang[0] == jiang[ 1] else jiang[0] + jiang[1] - LAI_ZI jiang_type = Card.cal_card_type(jiang_vals) jiang_lst = [] for index, j in enumerate(jiang): if jiang_type in [CardType.FENG, CardType.JIAN ] and jiang[index] != LAI_ZI: jiang_lst.append( Card.cal_card_val( jiang_type, Card.cal_card_digit(jiang[index]) // 3)) else: jiang_lst.append(j) ret[f].append(jiang_lst) shun_ke_lst = [] for shun_ke in other_card: tmp_shun_ke = copy.deepcopy(shun_ke) for index, i in enumerate(tmp_shun_ke): if i == LAI_ZI: continue t = Card.cal_card_type(i) if t in [CardType.FENG, CardType.JIAN]: tmp_shun_ke[index] = Card.cal_card_val( t, Card.cal_card_digit(i) // 3) shun_ke_lst.append(tmp_shun_ke) ret[f].append(shun_ke_lst) return ret
def trans_non_num_card_from_gap_plus(self, card_list): """ 将间断的非数字牌(风,箭,字,花)值转换成原始值 :param card_list: :return: """ ret = [[] for _ in range(len(card_list))] # 最终输出结果集 for f, cards in enumerate(card_list): jiang = cards[0] other_card = cards[1] ret_jiang = [] # 结果的将牌 ret_other_card = [] # 结果的顺和刻 for j in jiang: jiang_type = Card.cal_card_type(j) if jiang_type in [CardType.FENG, CardType.JIAN]: ret_jiang.append( Card.cal_card_val(jiang_type, Card.cal_card_digit(j) // 3)) else: ret_jiang.append(j) ret[f].append(ret_jiang) for shun_ke in other_card: sk_lst = [] for i in shun_ke: sk_type = Card.cal_card_type(i) if sk_type in [CardType.FENG, CardType.JIAN]: sk_lst.append( Card.cal_card_val(sk_type, Card.cal_card_digit(i) // 3)) else: sk_lst.append(i) ret_other_card.append(sk_lst) ret[f].append(ret_other_card) return ret
def del_hand_card_by_val(self, card_val): self.del_hand_card_by_type(Card.cal_card_type(card_val), Card.cal_card_digit(card_val))