def input_interface(game_str, role): """ 总调用接口:传入牌谱字符串及要学习的角色,返回训练用样本及标签 example: z = 'A4J5TT28TQDA9QJ44;5287KK8K5676K22T7;39J93937A8QQ6X356;4JA;0,58TTTJJJ;\ 0,2;2,X;0,D;0,QQ;1,22;1,T;0,4444;1,KKKK;1,55667788;1,7;0,9;1,2;' s, l = input_interface(z, 0) :param game_str : 牌谱, 默认顺序:地主;下家;上家;底牌;行牌过程 :param role : 要学习的角色 :return: sample : 机器学习输入 label : 机器学习输出 legal_ary : 合法标签one_hot形式 """ game_ary = game_str.rstrip(';').split(';') card_str = game_ary[role] + game_ary[3] if role == 0 else game_ary[role] card_ary = str2ary(card_str) rounds_ary = [] for i in range(4, len(game_ary)): cur_role, hand = game_ary[i].split(',') rounds_ary.append((int(cur_role), str2ary(hand))) full_rounds = complement(rounds_ary, role) before = get_before(full_rounds, role) if np.min(before) < 0: print('contain illegal hands!', game_str) return None, None, None rounds, hands = rounds_info(full_rounds, card_ary, role) sample = input_sample(rounds, hands, role) temp_label = full_rounds[role::3] label = [] for i in temp_label: label.append(hand_type.ary2label(i[1])) legal = legal_out_hands(before, rounds) legal_ary = legal_label(legal) return sample, label, legal_ary
def learning_sample(remain, recorder, hand, role): """ 获得训练用的样本(输入、输出) :param remain : 当前手牌 :param recorder : 记牌器 :param hand : 打出的一手 :param role : 角色 :return: input : 3 x 9 x 15 label : one hot """ hand = hand_parser.parse_hand(hand) main_hand = hand.to_dict()[:-1] cur_type = hand.to_dict()[-1] kicker_len, kicker_width = trans_utils.KICKER_PARAMS[cur_type] kicker_type = trans_utils.KICKER_TYPE[cur_type] cur_remain = remain - trans_utils.str2ary(main_hand) kickers = hand.kicker[::kicker_width] inputs = [] labels = [] used_labels = np.zeros(15, dtype=np.int32) for i in range(kicker_len): cur_main = main_hand[3 * i:3 * (i + 1)] if len(main_hand) % 3 == 0 else main_hand one_input = build_kicker_input(kicker_type, role, main_hand, cur_remain, kicker_width, kicker_len, cur_main, recorder, used_labels) label = kickers[i] used_labels[label] = 1 label_one_hot = np.zeros(15, dtype=np.int32) label_one_hot[label] = 1 inputs.append(one_input) labels.append(label_one_hot) return inputs, labels
def str2label(hand_str): """ hand转label,带非法hand检查 :param hand_str : hand字符串 :return : label """ return ary2label(str2ary(hand_str))
def append_kicker(cards, pot, process, role, hand, stub): main_hand = str2ary(hand[:-1]) cur_type = hand[-1] kicker_len, kicker_width = KICKER_PARAMS[cur_type] kicker_type = KICKER_TYPE[cur_type] ret_kicker = np.zeros(15, dtype=np.int32) remain = np.copy(cards) remain -= main_hand recorder = np.copy(pot) if role == 0 else np.zeros(15, dtype=np.int32) for p in process: cur_role, cur_hand = p hand_pot = np.copy(cur_hand) if cur_role == 0 and np.sum(pot) > 0: hand_pot -= pot num = np.where(hand_pot < 0)[0] pot = np.zeros(15, dtype=np.int32) for k in num: pot[k] = -hand_pot[k] hand_pot[k] += pot[k] if cur_role == role: remain -= cur_hand recorder = recorder + hand_pot if role == 0 else recorder + cur_hand cur_mains = [] cur_mains_index = np.where(main_hand == np.max(main_hand))[0] for i in cur_mains_index: cur_main = np.zeros(15, dtype=np.int32) cur_main[i] = 1 cur_mains.append(cur_main) while len(cur_mains) < kicker_len: cur_mains.append(cur_main) for cur_main in cur_mains: x_input_k = build_kicker_input(kicker_type, role, main_hand, remain, kicker_width, kicker_len, cur_main, recorder, ret_kicker) request = kicker_req(x_input_k) result_future = stub.Predict.future(request, 1) kicker = np.array(result_future.result().outputs['labels'].int_val)[0] for j in range(kicker_width): ret_kicker[kicker] += 1 kicker_str = ary2str(ret_kicker) check_legal = np.copy(cards) for p in process: if p[0] == role: check_legal -= p[1] check_legal -= main_hand check_legal -= ret_kicker check_mask = check_legal < 0 temp_out = hand[:-1] + kicker_str if True in check_mask or isinstance(str2label(temp_out), str): check_legal += ret_kicker out_hand = kicker_append(check_legal, HAND_CHAR2LABEL[hand]) else: out_hand = temp_out return out_hand
def get_kicker(cards, pot, process, role, dict_hand): main_hand = dict_hand[:-1] kicker_type = len(dict_hand) - 4 # kicker_type = 0 if '!' == dict_hand[-1] else 1 remain = cards + pot if role == 0 else cards remain -= tu.str2ary(main_hand) recorder = pot.copy() if role == 0 else np.zeros(15, dtype=np.int32) for p in process: cur_role = int(p.split(',')[0]) hand = tu.str2ary(p.split(',')[1]) hand_pot = hand.copy() if cur_role == 0 and np.sum(pot) > 0: hand_pot -= pot num = np.where(hand_pot < 0)[0] pot = np.zeros(15, dtype=np.int32) for k in num: pot[k] = -hand_pot[k] hand_pot[k] += pot[k] if cur_role == role: remain -= hand recorder = recorder + hand_pot if role == 0 else recorder + hand base_kickers = get_base_kickers(cards, kicker_type) return logic_filter(base_kickers, cards, recorder, role)
def get_game_result(game_ary, pot, turn=None, process=None, random_play=False, hostport='localhost:9000'): stub = get_stub(hostport) out_hands = [] if process is None else process.copy() role = 0 if turn is None else turn cur_cards = np.copy(game_ary) for p in out_hands: cur_cards[p[0]] -= p[1] while True: image, label = play_game_input(game_ary[role], out_hands, role) request = hand_req(image, label) result_future = stub.Predict.future(request, 1) top_n_labels = np.array( result_future.result().outputs['labels'].int_val) probs = np.array(result_future.result().outputs['scores'].float_val) out_hand_type, prob = get_hand(top_n_labels, probs, label, random_play) if 130 <= out_hand_type <= 223 or 269 <= out_hand_type <= 294: hand = HAND_LABEL2CHAR[out_hand_type] out_hand = append_kicker(game_ary[role], pot, out_hands, role, hand, stub) else: out_hand = HAND_LABEL2CHAR[out_hand_type] out_hand_ary = str2ary(out_hand) cur_cards[role] -= out_hand_ary out_hands.append((role, out_hand_ary)) if np.sum(cur_cards[role]) == 0: break elif np.sum(cur_cards[role]) < 0: print('-----error-------') print(cur_cards) temp = [] for i in game_ary: temp.append(ary2str(i)) print(';'.join(temp)) temp = [] for i in process: temp.append(','.join((str(i[0]), ary2str(i[1])))) print(';'.join(temp)) return else: role += 1 role = role % 3 return role, out_hands
def get_base_kickers(cards, kicker_type): """ 获取基本的带牌,原则:尽量不拆散手牌。方法:遍历所有合法带牌,如果带这张,计算剩下牌的所有合法打法,打法越多的说明越不重要,越应该被带。 :param cards:除去带牌主体的剩余手牌 :param kicker_type: 0单1双 :return: 候选带牌 """ # 如果不是只剩下2XD,不考虑 if sum(cards[:-3]) > 0: c = [] cards_index = [] for i in range(len(cards)): if cards[i] > kicker_type: cp = cards.copy() cp[i] -= (kicker_type + 1) c.append(cp) cards_index.append(i) all_hands = get_all_hands(c) l = [len(x) for x in all_hands] filter_1 = np.where(l == np.max(l))[0] if len(filter_1) > 1: score1 = [0] * len(filter_1) for i in range(len(filter_1)): cp = cards.copy() cp[cards_index[filter_1[i]]] -= (kicker_type + 1) c1 = [] for j in all_hands[filter_1[i]]: cp1 = cp.copy() cp1 -= tu.str2ary(j) c1.append(cp1) all_hands1 = get_all_hands(c1) l1 = [len(x) for x in all_hands1] score1[i] = sum(l1) filter_2 = np.where(score1 == np.max(score1))[0] out = [] for i in filter_2: out.append(cards_index[filter_1[i]]) else: out = [cards_index[filter_1[0]]] else: out = [] for i in range(12, 15): if cards[i] > 0: out.append(i) break return out
def solo_kicker(main, cards, length): ret = main good_kicker = np.zeros(15, dtype=np.int32) main_arr = str2ary(main) cardscp = cards.copy() for i in np.where(main_arr > 0)[0]: cardscp[i] = 0 all_hands = find_best_hand_group(cardscp) temp1 = [] temp2 = [] for i in all_hands: if sum(i) == 1: good_kicker += i else: temp1.append(i) for i in temp1: if sum(i) == len(np.where(i == 1)[0]) and len(i) > 5: t = np.where(i == 1)[0] for j in range(int(sum(i)) - 5): good_kicker[t[j]] = 1 else: temp2.append(i) l1 = int(sum(good_kicker)) if length <= l1: gk = np.where(good_kicker == 1)[0] for i in range(length): ret += CARDS_VALUE2CHAR[gk[i]] return ret else: pair_kicker = np.zeros(15, dtype=np.int32) temp1 = [] for i in temp2: if sum(i) == 2 and len(np.where(i == 2)[0]) == 1: pair_kicker += i else: temp1.append(i) l2 = len(np.where(pair_kicker > 0)[0]) if length - l1 <= l2: gk = np.where(good_kicker == 1)[0] pk = np.where(pair_kicker > 0)[0] for i in range(l1): ret += CARDS_VALUE2CHAR[gk[i]] for i in range(length - l1): ret += CARDS_VALUE2CHAR[pk[i]] return ret else: trio_kicker = np.zeros(15, dtype=np.int32) for i in temp1: if sum(i) == 3 and len(np.where(i == 3)[0]) == 1: trio_kicker += i l3 = len(np.where(trio_kicker > 0)[0]) if length - l1 - l2 <= l3: gk = np.where(good_kicker == 1)[0] pk = np.where(pair_kicker > 0)[0] tk = np.where(trio_kicker > 0)[0] for i in range(l1): ret += CARDS_VALUE2CHAR[gk[i]] for i in range(l2): ret += CARDS_VALUE2CHAR[pk[i]] for i in range(length - l1 - l2): ret += CARDS_VALUE2CHAR[tk[i]] return ret else: kicker = np.where(cardscp > 0)[0] for i in range(length): ret += CARDS_VALUE2CHAR[kicker[i]] return ret
return else: role += 1 role = role % 3 return role, out_hands if __name__ == '__main__': hostport = "192.168.31.196:9000" g = '333678899JQQKA22D;34445667TTTTJJQA2;4555677889JQKAA2X;9KK' pg = '0,3336;1,P' prc = pg.split(';') rounds_ary = [] for i in prc: cur_role, hand = i.split(',') rounds_ary.append((int(cur_role), str2ary(hand))) game_ary = str2ary(g, separator=';') t1 = time.time() hand = get_one_hand(game_ary[2], rounds_ary, 2, game_ary[3], hostport=hostport) t2 = time.time() print(hand) print(t2 - t1) game_ary[0] += game_ary[3] w, pc = get_game_result(game_ary, game_ary[3], hostport=hostport) temp = [] for i in pc: temp.append(','.join((str(i[0]), ary2str(i[1]))))
def samples_from_one_game(record, role=None): """ 从一副牌中挑出有带牌的情况(只适用于下面这种格式) :param record : 36J6JQ23QK23JQKAX;458QK23TK79TJA689;79TA478A4568457T2;59D;0,59JJJQQQ;0,KK;2,AA;0,22;0,33366;2,55444;0,XD;0,A; :param role : 默认为None,学三家(没写)。否则学习对应位置,0地主1下家2上家 :return : 一副牌中所有的带牌信息 remains : 当前手牌(打出这一手之前) recorders : 记牌器(打牌过程中出过的牌) hands : 打出的牌 roles : 角色 """ record_ary = record.rstrip(';').split(';') cards = np.zeros((4, 15), dtype=np.int32) process = np.zeros((len(record_ary) - 4, 15), dtype=np.int32) process_role = np.zeros((len(record_ary) - 4), dtype=np.int32) remains = [] recorders = [] hands = [] roles = [] process_cursor = 0 for i in range(len(record_ary)): if i < 4: # 手牌和底牌 cards[i] = str2ary(record_ary[i]) else: # 打牌过程 one_hand = record_ary[i].split(',') process_role[i - 4] = int(one_hand[0]) process[i - 4] = str2ary(one_hand[1]) # 判断是否为带牌 one_hand_type = str2label(one_hand[1]) if 130 <= one_hand_type <= 223 or 269 <= one_hand_type <= 294: if role is not None: if role == process_role[i - 4]: # hand hands.append(process[i - 4]) # role roles.append(role) # remain if len(remains) == 0: remain = np.copy(cards[role]) remain = remain + cards[3] if role == 0 else remain for j in range(process_cursor, i - 4): if process_role[j] == role: remain -= process[j] remains.append(np.copy(remain)) # recorder if len(recorders) == 0: recorder = np.copy(cards[3]) for j in range(process_cursor, i - 4): if process_role[j] == 0 and np.sum(cards[3]) > 0: # check pot hand_ary = np.copy(process[j]) hand_ary -= cards[3] num = np.where(hand_ary < 0)[0] cards[3] = np.zeros(15, dtype=np.int32) for k in num: cards[3][k] = -hand_ary[k] hand_ary[k] += cards[3][k] recorder += hand_ary else: recorder += process[j] recorders.append(np.copy(recorder)) process_cursor = i - 4 else: # 学三家,没写 pass ret = list() for i in range(len(roles)): ret.append((remains[i], recorders[i], hands[i], roles[i])) return ret
def label2ary(label): """ label转array(不含kicker) :param label : 标签 :return: ary : 数组 HandType : 牌型 """ label_str = HAND_LABEL2CHAR[label] if 1 <= label <= 15: return str2ary(label_str), HandType.SOLO.value elif 16 <= label <= 28: return str2ary(label_str), HandType.PAIR.value elif 29 <= label <= 41: return str2ary(label_str), HandType.AIRPLANE.value elif 42 <= label <= 77: return str2ary(label_str), HandType.SOLO_CHAIN.value elif 78 <= label <= 129: return str2ary(label_str), HandType.PAIR_SISTERS.value elif 130 <= label <= 142: return str2ary(label_str[:-1]), HandType.TRIO_SOLO.value elif 143 <= label <= 155: return str2ary(label_str[:-1]), HandType.TRIO_PAIR.value elif 156 <= label <= 193: return str2ary(label_str[:-1]), HandType.AIRPLANE_SOLO.value elif 194 <= label <= 223: return str2ary(label_str[:-1]), HandType.AIRPLANE_PAIR.value elif 224 <= label <= 268: return str2ary(label_str), HandType.AIRPLANE.value elif 269 <= label <= 281: return str2ary(label_str[:-1]), HandType.DUAL_SOLO.value elif 282 <= label <= 294: return str2ary(label_str[:-1]), HandType.DUAL_PAIR.value elif 295 <= label <= 307: return str2ary(label_str), HandType.BOMB.value elif label == 308: return str2ary(label_str), HandType.NUKE.value else: return np.zeros(15, dtype=np.int32), -1