def main(): arguements = docopt( data_io.set_up_doc(__doc__), version='0.1' ) record = Record(debug=arguements['--debug']) if arguements['<data>']: # translation from_lang, to_lang, data = _extract(arguements) # translate data translator = Translator(from_lang, to_lang, data, debug=arguements['--debug']) # result is a dictionary contains decoded infomation of the # trnaslation. result = translator.translate() translator.display_result(result) # add record record.add(from_lang, to_lang, data, result) elif arguements['--record']: # display record record.display() else: raise Exception('No Implemented Yet.')
def monitor(): """ The core method of the cronjob. Monitors each configured repository for their current branch. """ repositories = Configuration(file_name="repositories").read() if len(repositories) == 0: print("There are no repositories configured to be monitored.") return record = Record(file_name="records") for repository in repositories: branch = retrieve_branch(repository) timestamp = datetime.datetime.now().replace(microsecond=0).isoformat() record.add(repository, branch, timestamp)
def simulate(nw0, nw1, init='fixed'): board = rule.init_board() if init == 'fixed' else rule.random_init_board() player = 1 records = Record() while True: nw = nw0 if player == 1 else nw1 try: bd = board.copy() from_, action, vp, p = nw.policy(board, player) # print('>', from_, action) assert board[from_] == player to_ = tuple(np.add(from_, rule.actions_move[action])) command, eat = rule.move(board, from_, to_) reward = len(eat) records.add(bd, from_, action, reward, vp, win=command == rule.WIN) except NoActionException: return Record(), 0 except Exception as e: logging.info('board is:') logging.info(board) logging.info('player is: %s', player) valid = rule.valid_action(board, player) logging.info('predict is:') print(nw.p) logging.info('sum is: %s', nw.p.sum()) logging.info('valid action is:') logging.info(nw.valid) logging.info('p * valid is:') logging.info(nw.vp) logging.info('from:%s, action:%s', from_, action) logging.info('prob is: %s', valid[from_][action]) records.save('records/train/1st_') raise e # if eat: # print(player, from_, to_, eat, N) if command == rule.WIN: logging.info('%s WIN, step use: %s', str(player), records.length()) return records, player if records.length() > 10000: logging.info('走子数过多: %s', records.length()) return Record(), 0 player = -player board = rule.flip_board(board)
class Tags_recom(object): def __init__(self): self.char_data = Character() self.char_data.extract_all_char() self.all_tags = { '狙击', '术师', '特种', '重装', '辅助', '先锋', '医疗', '近卫', '减速', '输出', '生存', '群攻', '爆发', '召唤', '快速复活', '费用回复', '新手', '治疗', '防护', '位移', '削弱', '控场', '支援', '支援机械', "机械", '近战位', '远程位', '近战', '远程', '资深干员', '高级资深干员', '高级资深', '资深', '高资', #'女', '男', #'女性', '男性', '狙击干员', '术师干员', '特种干员', '重装干员', '辅助干员', '先锋干员', '医疗干员', '近卫干员', #'女性干员', '男性干员', # flags '全部' } self.ocr_tool = Ocr_tool() self.record = Record(path_prefix + "record_tags.txt", writecnt=50) def recom_tags(self, tags, flags={}): tags = self.strip_tags(tags) itertag = self.iter_all_combine(tags) if itertag is None: return [] cob_lis = list(itertag) cob_lis.remove([]) cob_lis = [(tags_lis, list(self.char_data.filter(tags_lis, flags))) for tags_lis in cob_lis] cob_lis = [x for x in cob_lis if x[1] != []] # print(cob_lis) # char_data[name] # print("") # for x in cob_lis: # print(x) # remove same result for i in range(0, len(cob_lis)): for j in range(0, len(cob_lis)): if i == j: continue if set(cob_lis[i][1]) == set(cob_lis[j][1]): if set(cob_lis[i][0]).issubset(set(cob_lis[j][0])): cob_lis[j] = (cob_lis[j][0], []) cob_lis = [x for x in cob_lis if x[1] != []] # print("") # for x in cob_lis: # print(x) # special remove if ('show_all' not in flags or flags['show_all'] == False): for i in range(len(cob_lis)): if self.is_special_rm(cob_lis[i]): cob_lis[i] = (cob_lis[i][0], []) cob_lis = [x for x in cob_lis if x[1] != []] # print("") # for x in cob_lis: # print(x) # sort cob_lis.sort(key=self.avg_rank, reverse=True) for tags_lis, lis in cob_lis: lis.sort(key=lambda x: self.char_data.char_data[x]["rank"], reverse=True) # print("") # for x in cob_lis: # print(x) # for x in cob_lis: # print(self.avg_rank(x)) # # build reverse index # char_dic=dict() # for i in range(len(cob_lis)): # for name in cob_lis[i][1]: # if name not in char_dic: # char_dic[name]=[i] # else: # char_dic[name].append(i) # # print("") # # print(char_dic) # # remove duplicate # min_size_id=dict() # for name, lis in char_dic.items(): # if len(lis)>1: # min_size_id[name]=lis[0] # for id in lis: # if len(cob_lis[id][1])<len(cob_lis[min_size_id[name]][1]): # min_size_id[name]=id # for name, lis in char_dic.items(): # if len(lis)>1: # for id in lis: # if id!=min_size_id[name]: # cob_lis[id][1].remove(name) # cob_lis=[x for x in cob_lis if x[1]!=[]] # # print("") # # for x in cob_lis: # # print(x) #merge less rank 3 if ('show_all' not in flags or flags['show_all'] == False): tag_cnt = 0 max_num_until_del = 15 for tags_lis, lis in cob_lis: cnt = 0 sp_lis = [] while len(lis) > 0 and self.char_data.char_data[ lis[-1]]["rank"] <= "3": res = lis.pop() if res in ["Castle-3", "Lancet-2", "THRM-EX"]: sp_lis.append(res) else: cnt += 1 if len(sp_lis) > 0: lis.extend(sp_lis) if cnt > 0 and len(lis) > 0: lis.append("...{0}".format(cnt)) # delete all contain <=3 if tag_cnt + len(lis) > max_num_until_del: lis.clear() max_num_until_del = -1 tag_cnt += len(lis) cob_lis = [x for x in cob_lis if x[1] != []] return cob_lis # print("") # for x in cob_lis: # print(x) def is_special_rm(self, cob_i): if set(cob_i[0]) == set(["女"]): return True # if set(cob_i[0])==set(["男"]): # return True return False def avg_rank(self, cob_i): rank_map = {1: 0.5, 2: 1, 3: 10, 4: 2, 5: 0.5, 6: 3} rank_list = list( map(lambda x: int(self.char_data.char_data[x]["rank"]), cob_i[1])) sum_score = 0 sum_cnt = 0 for i in range(1, 7): sum_score += rank_list.count(i) * rank_map[i] * i sum_cnt += rank_list.count(i) * rank_map[i] if sum_cnt == 0: return 0 else: return sum_score / sum_cnt def strip_tags(self, tags): restags = [] for tag in tags: if tag in ["高级资深干员", "高资", "高级资深"]: restags.append("高级资深干员") elif tag in ["资深干员", "资深"]: restags.append("资深干员") elif tag in ["近战", "远程"]: restags.append(tag + "位") elif tag in ["机械"]: restags.append(tag + "支援机械") # elif tag in ["男性","女性"]: # tag=tag.replace("性","") # restags.append(tag) # elif "性干员" in tag: # tag=tag.replace("性干员","") # restags.append(tag) elif "干员" in tag: tag = tag.replace("干员", "") restags.append(tag) else: restags.append(tag) return restags def iter_all_combine(self, tags): if len(tags) == 0: yield [] return tag = tags[0] new_tags = tags[:] new_tags.remove(tag) for x in self.iter_all_combine(new_tags): yield [tag] + x for x in self.iter_all_combine(new_tags): yield x def check_legal_tags(self, tags): if not tags: return False for tag in tags: if tag not in self.all_tags: return False return True def split_tags(self, t_tag): rest_tag = t_tag[:] flag = True tag_lis = [] for tag in self.all_tags: if rest_tag == tag: return [tag] for tag in self.all_tags: if tag in rest_tag: res = self.split_tags(rest_tag.replace(tag, "")) if res: return [tag] + res return [] def filter_legal_tags(self, tags): if not tags: return [] new_tags = [] for tag in tags: split_res = self.split_tags(tag) new_tags.append(tag) if len(split_res) > 1: new_tags.extend(split_res) tags = new_tags # print(new_tags) res = [] for tag in tags: if tag in self.all_tags: res.append(tag) return res def split_flags(self, tags): if not tags: return [], {} tags = list(set(tags)) flags = {} if '全部' in tags: flags['show_all'] = True tags.remove('全部') else: flags['show_all'] = False return tags, flags def record_tags(self, tags): for tag in tags: self.record.add(tag) def recom(self, tags=None, images=None): if not tags: if images: tags = self.get_tags_from_image(images) if not tags: print("MYDEBUG image checkfail {0}".format(images[0])) return None else: return None tags, flags = self.split_flags(tags) # print(tags, flags) if not self.check_legal_tags(tags): print("MYDEBUG no legal tags") return None self.record_tags(tags) cob_lis = self.recom_tags(tags, flags) if not cob_lis: return "没有或者太多" line_lis = [] for tags_lis, lis in cob_lis: new_lis = [] for x in lis: if x in self.char_data.char_data: new_lis.append(x + "★" + self.char_data.char_data[x]["rank"]) else: new_lis.append("★1~3" + x) lef = '【' + '+'.join(tags_lis) + "】:\n" rig = ', '.join(new_lis) line_lis.append(lef + rig) res = "\n\n".join(line_lis) return res def get_tags_from_image(self, images): tags = self.ocr_tool.get_tags_from_url(images[0]) tags = self.filter_legal_tags(tags) tags = list(set(tags)) print("ocr res=", tags) if len(tags) >= 2 and len(tags) <= 8: return tags else: return []
class Character(object): def __init__(self): self.char_data = dict() self.enemy_data = dict() self.head_data = [] self.head_key_map = { "职业": "job", "星级": "rank", "性别": "sex", "阵营": "affiliation", "标签": "tags", "获取途径": "obtain_method" } self.fuzzname = Fuzzname() self.record = Record(path_prefix + "record_peo.txt") def extract_all_char(self, text_file=None, enemy_file=None): if text_file is None: text_file = path_prefix + "chardata.json" if enemy_file is None: enemy_file = path_prefix + "enemylist.json" if not os.path.exists(text_file) or not os.path.exists(enemy_file): self.fetch_data() # deal char with open(text_file, encoding='UTF-8') as fp: self.char_data = json.load(fp) # deal enemy with open(enemy_file, encoding='UTF-8') as fp: self.enemy_data = json.load(fp) # fuzzy name+pinyin -> name self.fuzzname.fit( list(self.char_data.keys()) + list(self.enemy_data.keys())) def filter(self, tags, flags={}): tags = tags[:] ranks = self.gen_ranks(tags) for name, dic in self.char_data.items(): if set(tags).issubset(set(dic["tags"])): pass else: continue if dic["rank"] in ranks or ('show_all' in flags and flags['show_all'] == True): pass else: continue if "公开招募" in dic["obtain_method"] or ('show_all' in flags and flags['show_all'] == True): pass else: continue yield name def gen_ranks(self, tags): ranks = ["1", "2", "3", "4", "5", "6"] for i in range(1, 7): if ">={0}".format(i) in tags: ranks = [x for x in ranks if x >= str(i)] tags.remove(">={0}".format(i)) if "<={0}".format(i) in tags: ranks = [x for x in ranks if x <= str(i)] tags.remove("<={0}".format(i)) if "高级资深干员" not in tags: ranks.remove("6") if "资深干员" in tags: ranks = ["5"] if "高级资深干员" in tags: ranks = ["6"] if "资深干员" in tags and "高级资深干员" in tags: ranks = ["5", "6"] return ranks def get_peo_info(self, name=None): if not name: return None res = "None" if name in self.char_data: res = self.format_friend_info(name) self.record.add("friend/" + name) elif name in self.enemy_data: res = self.format_enemy_info(name) self.record.add("enemy/" + name) else: res = self.fuzzname.predict(name) res = "你可能想查 {0}".format(res) return res def format_friend_info(self, name): res = [] for tp, cont in self.char_data[name]['all'].items(): if tp: if tp == "干员代号": tp = "姓名" res.append("{0}: {1}".format(tp, cont)) url = self.char_data[name]["link"] res.append(url) res_text = "\n".join(res) # r=requests.get(self.char_data[name]["head_pic"],timeout=30) # buffer=r.content bytes_image = get_bytes_image_from_url( self.char_data[name]["head_pic"]) ret_msg = [ Image.fromBytes(bytes_image), # Image.fromRemote(self.char_data[name]["head_pic"]), # Image.fromFileSystem("./plugins/image.jpg"), Plain(text="\n"), Plain(text=res_text) ] return ret_msg def format_enemy_info(self, name): res = [name] url = self.enemy_data[name]["link"] res.append(url) res_text = "\n".join(res) # r=requests.get(self.enemy_data[name]["head_pic"],timeout=30) # buffer=r.content bytes_image = get_bytes_image_from_url( self.enemy_data[name]["head_pic"]) ret_msg = [ Image.fromBytes(bytes_image), Plain(text="\n"), Plain(text=res_text) ] return ret_msg def fetch_data(self): # self.fetch_character_from_wikijoyme() self.fetch_character_from_akmooncell() self.fetch_enemy_from_akmooncell() def fetch_character_from_wikijoyme(self, filename="chardata.json"): r = requests.get("http://wiki.joyme.com/arknights/干员数据表") if r.status_code != 200: raise IOError("Cannot fetch char from wikijoyme") tree = html.fromstring(r.text) # table head data tb_head = tree.xpath("//table[@id='CardSelectTr']//th/text()") tb_head = [x.strip() for x in tb_head] # deal with character char_res_lis = tree.xpath("//tr[@data-param1]") char_data = dict() for char_tr in char_res_lis: name = char_tr.xpath("./td[2]/a[1]/text()")[0] char_data[name] = dict() char_data[name]["job"] = char_tr.xpath("./@data-param1")[0] char_data[name]["rank"] = char_tr.xpath("./@data-param2")[0].split( ",")[0] char_data[name]["sex"] = char_tr.xpath("./@data-param3")[0] char_data[name]["affiliation"] = char_tr.xpath("./@data-param4")[0] tag_string=char_tr.xpath("./@data-param5")[0]+", " \ +char_data[name]["sex"]+", " \ +char_data[name]["job"]+", " \ +("资深干员" if char_data[name]["rank"]=="5" else "")+", " \ +("高级资深干员" if char_data[name]["rank"]=="6" else "")+", " taglist = [x.strip() for x in tag_string.split(",")] taglist = [x for x in taglist if x != ""] char_data[name]["tags"] = taglist #如果俩小车是支援机械的话加个tag if name in ["Castle-3", "Lancet-2"]: char_data[name]["tags"].append("支援机械") char_data[name]["obtain_method"] = list( map(lambda x: x.strip(), char_tr.xpath("./@data-param6")[0].split(","))) #deal head and data td_lis = char_tr.xpath(".//td") text_lis = [ "".join([xx.strip() for xx in x.xpath(".//text()")]) for x in td_lis ] all_lis = [x.strip() for x in text_lis] all_dict = dict(zip(tb_head, all_lis)) char_data[name]["all"] = all_dict # link char_link_root = "http://wiki.joyme.com/arknights/" url = char_link_root + urllib.parse.quote(name) char_data[name]["link"] = url char_data[name]["type"] = "friend" with open(path_prefix + filename, "w", encoding='utf-8') as fp: json.dump(char_data, fp) return char_data def fetch_character_from_akmooncell(self, filename="chardata.json"): def fetch_data_with_json_format(): r = requests.get( "http://prts.wiki/load.php?debug=false&lang=zh-cn&modules=ext.gadget.charFilter&skin=vector&version=0vmy0ui" ) if r.status_code != 200: raise IOError("Cannot fetch char from akmooncell") rtext = r.text.replace("\n", "") rtext = re.sub(r"<.*?>", "", rtext) result = re.search(r"(?<=datalist=)(.*?)(?=;console)", rtext).group(1) content = eval(result) # print(content) char_data = dict() for char_tr in content: name = char_tr["cn"] # if name=="杜宾": # print(char_tr) char_data[name] = dict() char_data[name]["job"] = char_tr["class"] char_data[name]["rank"] = str(int(char_tr["rarity"]) + 1) char_data[name]["sex"] = char_tr["sex"] char_data[name]["affiliation"] = char_tr["camp"] char_data[name]["tags"]=char_tr["tag"]\ +[char_data[name]["job"]]\ +[char_tr["position"]]\ +(["资深干员"] if char_data[name]["rank"]=="5" else [])\ +(["高级资深干员"] if char_data[name]["rank"]=="6" else []) char_data[name]["obtain_method"] = char_tr["approach"] #deal head and data char_data[name]["all"] = { "姓名": char_tr["cn"], "出身": char_tr["camp"], "种族": ','.join(char_tr["race"]), "初始生命": char_tr["oriHp"], "初始攻击": char_tr["oriAtk"], "初始防御": char_tr["oriDef"], "初始法术抗性": char_tr["oriRes"], "初始再部署时间": char_tr["oriDt"], "初始部署费用": char_tr["oriDc"], "初始阻挡数": char_tr["oriBlock"], "初始攻击间隔": char_tr["oriCd"], "标签": ','.join(char_tr["tag"]), "特性": char_tr["feature"], } # link char_link_root = "http://prts.wiki/w/" url = char_link_root + urllib.parse.quote(name) char_data[name]["link"] = url char_data[name]["type"] = "friend" return char_data def fetch_data_with_source(): r = requests.get("http://prts.wiki/w/干员一览") if r.status_code != 200: raise IOError("Cannot fetch char from akmooncell") rtext = r.text rtext = rtext.replace("\n", "") rtext = re.sub( r"<span style="display:none.*?>(.*?)</span>", r"(\1)", rtext) rtext = re.sub(r"<br/>", "\n", rtext) rtext = re.sub(r"<span.*?>", "", rtext) rtext = re.sub(r"</span>", "", rtext) tree = html.fromstring(rtext) char_res_lis = tree.xpath("//div[@class='smwdata']") char_data = dict() for char_a in char_res_lis: name = char_a.xpath("./@data-cn")[0] char_data[name] = dict() char_data[name]["job"] = char_a.xpath("./@data-class")[0] char_data[name]["rank"] = str( int(char_a.xpath("./@data-rarity")[0]) + 1) char_data[name]["sex"] = char_a.xpath("./@data-sex")[0] char_data[name]["affiliation"] = char_a.xpath( "./@data-camp")[0] char_data[name]["tags"]=char_a.xpath("./@data-tag")[0].split(" ")\ +[char_data[name]["job"]]\ +[char_a.xpath("./@data-position")[0]]\ +(["资深干员"] if char_data[name]["rank"]=="5" else [])\ +(["高级资深干员"] if char_data[name]["rank"]=="6" else []) char_data[name]["obtain_method"] = char_a.xpath( "./@data-approach")[0].split(", ") char_data[name]["head_pic"] = char_a.xpath("./@data-icon")[0] #deal head and data char_data[name]["all"] = { "姓名": name, "出身": char_a.xpath("./@data-camp")[0], "种族": char_a.xpath("./@data-race")[0], "初始生命": char_a.xpath("./@data-ori-hp")[0], "初始攻击": char_a.xpath("./@data-ori-atk")[0], "初始防御": char_a.xpath("./@data-ori-def")[0], "初始法术抗性": char_a.xpath("./@data-ori-res")[0], "初始再部署时间": char_a.xpath("./@data-ori-dt")[0], "初始部署费用": char_a.xpath("./@data-ori-dc")[0], "初始阻挡数": char_a.xpath("./@data-ori-block")[0], "初始攻击间隔": char_a.xpath("./@data-ori-cd")[0], "标签": char_a.xpath("./@data-tag")[0], "特性": char_a.xpath("./@data-feature")[0], } # link char_link_root = "http://prts.wiki/w/" url = char_link_root + urllib.parse.quote(name) char_data[name]["link"] = url char_data[name]["type"] = "friend" # if name=="杜宾": # print(char_data[name]) return char_data char_data = fetch_data_with_source() with open(path_prefix + filename, "w", encoding='utf-8') as fp: json.dump(char_data, fp) return char_data def fetch_enemy_from_akmooncell(self, filename="enemylist.json"): import threading, time def try_enemy_head_pic_path(name, enemy_data): def modify_data(url): enemy_data_rlock.acquire() enemy_data[name]["head_pic"] = url enemy_data_rlock.release() print("%s is trying %s" % (threading.current_thread().name, name)) try: print(name) session_requests = requests.session() for i in range(256): h = hex(i)[2:] if len(h) == 1: h = '0' + h url = "http://prts.wiki/images/{0}/{1}/头像_敌人_{2}.png".format( h[0], h, name) r = session_requests.get(url, allow_redirects=False) if r.status_code == 200: print('SUCCESS %s get %s' % (threading.current_thread().name, url)) modify_data(url) return print(name, "didnt find right url, return default") return modify_data( "http://prts.wiki/images/3/3e/头像_敌人_源石虫.png") except Exception as e: print(e) print('FAIL %s error %s' % (threading.current_thread().name, name)) return modify_data( "http://prts.wiki/images/3/3e/头像_敌人_源石虫.png") print("begin fetch enemy") # get enemy data r = requests.get("http://prts.wiki/index.php?title=敌人一览/数据&action=raw") if r.status_code != 200: raise IOError("Cannot fetch enemy from akmooncell") enemy_data_raw = r.json() enemy_data = dict() enemy_link_root = "http://prts.wiki/w/" for enemy_a in enemy_data_raw: name = enemy_a["name"] # print("===="+name) enemy_data[name] = dict() link = enemy_link_root + urllib.parse.quote(enemy_a["enemyLink"]) enemy_data[name]["link"] = link enemy_data[name]["type"] = "enemy" if name in self.enemy_data and "head_pic" in self.enemy_data[ name] and (name == "源石虫" or self.enemy_data[name]["head_pic"] != self.enemy_data["源石虫"]["head_pic"]): enemy_data[name]["head_pic"] = self.enemy_data[name][ "head_pic"] else: enemy_data[name]["head_pic"] = "" enemy_name_lis = list(enemy_data.keys()) threads = [] enemy_data_rlock = threading.RLock() for name in enemy_name_lis: if not enemy_data[name]["head_pic"]: t = threading.Thread(target=try_enemy_head_pic_path, args=(name, enemy_data)) threads.append(t) while sum(map(lambda x: 1 if x.is_alive() else 0, threads)) >= 50: time.sleep(1) t.start() for t in threads: if t.is_alive(): t.join() with open(path_prefix + filename, "w", encoding='utf-8') as fp: json.dump(enemy_data, fp) print("end fetch enemy") return enemy_data """ def fetch_enemy_from_akmooncell(self, filename="enemylist.json"): # get enemy data r=requests.get("http://prts.wiki/w/敌人一览") if r.status_code!=200: raise IOError("Cannot fetch enemy from akmooncell") tree=html.fromstring(r.text) enemy_res_lis=tree.xpath("//div[@class='smwdata']") enemy_data=dict() enemy_link_root="http://prts.wiki/w/" for enemy_a in enemy_res_lis: name=enemy_a.xpath("./@data-name")[0] # print("===="+name) enemy_data[name]=dict() link=enemy_link_root+urllib.parse.quote(name) enemy_data[name]["link"]=link enemy_data[name]["type"]="enemy" enemy_data[name]["head_pic"]=enemy_a.xpath("./@data-file")[0] with open(path_prefix+filename,"w",encoding='utf-8') as fp: json.dump(enemy_data, fp) return enemy_data """ def fetch_enemy_from_wikijoyme(self, filename="enemylist.json"): # get enemy data r = requests.get("http://wiki.joyme.com/arknights/敌方图鉴") if r.status_code != 200: raise IOError("Cannot fetch enemy from wikijoyme") tree = html.fromstring(r.text) enemy_res_lis = tree.xpath("//tr[@data-param1]") enemy_data = dict() enemy_link_root = "http://prts.wiki/w/" for enemy_a in enemy_res_lis: name = enemy_a.xpath("./td[2]/a[1]/text()")[0] print("====" + name) enemy_data[name] = dict() link = enemy_link_root + urllib.parse.quote(name) enemy_data[name]["link"] = link enemy_data[name]["type"] = "enemy" with open(path_prefix + filename, "w", encoding='utf-8') as fp: json.dump(enemy_data, fp) return enemy_data
class ChessBoard: def __init__(self): window = tk.Tk() window.title('五子棋') window.geometry('600x720') w = 100 # 棋格宽度 r = 35 # 棋子半径 row = 5 col = 5 canvas = tk.Canvas(window, bg='blue', width=w * 6, height=w * 6) canvas.pack() # 棋盘 for i in range(1, 6): canvas.create_line(w, i * w, 5 * w, i * w, width=2) canvas.create_line(i * w, w, i * w, 5 * w, width=2) # 棋子 self._board = [[None for _ in range(col)] for _ in range(row)] # Q值 self._qtext = [[[ canvas.create_text(*(np.array([w * (j + 1), w * (i + 1)]) + np.array(a)[::-1] * 25), text='', fill='green') for a in rule.actions_move ] for j in range(5)] for i in range(5)] # 棋手的名字 self.name_white = canvas.create_text(40, 30, text=WHITE, fill='#EEE', font=font.Font(size=20)) self.name_black = canvas.create_text(40, w * 6 - 30, text=BLACK, fill='#111', font=font.Font(size=20)) # 指示当前棋手的信号灯 sig_r = 5 self.sig_white = canvas.create_oval(82 - sig_r, 30 - sig_r, 82 + sig_r, 30 + sig_r, fill='#66FF66', outline='#66FF66', state=tk.HIDDEN) self.sig_black = canvas.create_oval(82 - sig_r, w * 6 - (30 - sig_r), 82 + sig_r, w * 6 - (30 + sig_r), fill='#66FF66', outline='#66FF66', state=tk.HIDDEN) # 显示胜利者 self.winner_white = canvas.create_text(125, 30, text='WINNER', fill='red', font=font.Font(size=20), state=tk.HIDDEN) self.winner_black = canvas.create_text(125, w * 6 - 30, text='WINNER', fill='red', font=font.Font(size=20), state=tk.HIDDEN) # 计时钟 self.clock_white = canvas.create_text(w * 6 - 40, 30, text='00:00', fill='#EEE', font=font.Font(family='Times', size=20)) self.clock_black = canvas.create_text(w * 6 - 40, w * 6 - 30, text='00:00', fill='#111', font=font.Font(family='Times', size=20)) # ----------------- 第一排按扭 ----------------------------------------- # 对手选择 tk.Label(window, text='对手:').place(x=10, y=620) player_var = tk.StringVar() player_classes = [ ('White(HummanPlayer)', HummanPlayer, ('White', WHITE_VALUE, self.sig_white, self.winner_white, self.clock_white), {}), # ('Paul(PolicyPlayer)', PolicyNetworkPlayer, ['Paul', WHITE_VALUE, self.sig_white, self.winner_white, self.clock_white], {'play_func':self._play, 'model_file':'model/policy_network/convolution_0130w.model'}), ('Quin(DQNPlayer)', DQNPlayer, [ 'Quin', WHITE_VALUE, self.sig_white, self.winner_white, self.clock_white ], { 'play_func': self._play, 'weights_file': 'model/qlearning_network/DQN_fixed_sigmoid_00029w.weights' }), ('Vance(ValuePlayer)', ValuePlayer, [ 'Vance', WHITE_VALUE, self.sig_white, self.winner_white, self.clock_white ], { 'play_func': self._play, 'weights_file': 'model/value_network/value_network_sigmoid_00074w.weights' }), ('Toms(MCTSPlayer)', MCTSPlayer, [ 'Toms', WHITE_VALUE, self.sig_white, self.winner_white, self.clock_white ], { 'play_func': self._play, 'policy_model': '', 'value_model': 'model/qlearning_network/DQN_fixed_sigmoid_00029w.weights' }), ] self.player_map = {n: (c, p, kp) for n, c, p, kp in player_classes} players = [n for n, *_ in player_classes] player_choosen = ttk.Combobox(window, width=16, textvariable=player_var, values=players, state='readonly') player_choosen.current(0) player_choosen.place(x=50, y=617) self.player_var = player_var self.player_choosen = player_choosen # 开局选择 tk.Label(window, text='开局:').place(x=225, y=620) board_var = tk.IntVar(0) boards = list(range(len(init_boards))) board_choosen = ttk.Combobox(window, width=2, textvariable=board_var, values=boards, state='readonly') board_choosen.current(0) board_choosen.place(x=267, y=617) self.board_var = board_var self.board_choosen = board_choosen board_choosen.bind('<<ComboboxSelected>>', self.board_selected) # 先手 first_player = tk.IntVar(value=WHITE_VALUE) tk.Radiobutton(window, text='黑先', variable=first_player, value=BLACK_VALUE).place(x=315, y=620) tk.Radiobutton(window, text='白先', variable=first_player, value=WHITE_VALUE).place(x=370, y=620) self.first_player = first_player # 开始按扭 start_btn_text = tk.StringVar(window, value='start') tk.Button(window, textvariable=start_btn_text, command=self.start, width=5).place(x=425, y=617) # 隐藏路径按扭 hide_q_str = tk.StringVar(value='hideQ') tk.Button(window, textvariable=hide_q_str, command=self.hide_q, width=5).place(x=483, y=617) self.hide_q_str = hide_q_str self.print_q_flag = True # 帮助按扭 tk.Button(window, text='help', command=self.help, width=4).place(x=548, y=617) # ---------------- 第二排按扭 ------------------------------------------ # 选择棋谱 tk.Label(window, text='棋谱:').place(x=10, y=658) record_path = tk.StringVar() record_entry = tk.Entry(window, textvariable=record_path, width=18) record_entry.place(x=45, y=655) tk.Button(text='select', command=self.select_record).place(x=222, y=655) # replay按扭 tk.Button(window, text='replay', command=self.replay).place(x=290, y=655) # 速度调节按扭 tk.Button(window, text='faster', command=lambda: self.change_period(0.5)).place(x=360, y=655) tk.Button(window, text='slower', command=lambda: self.change_period(2)).place(x=430, y=655) # 暂停按扭 pause_text = tk.StringVar(value='pause') tk.Button(window, textvariable=pause_text, command=self.pause, width=6).place(x=510, y=655) # ---------------- 第三排按扭 ------------------------------------------ # 消息显示 lb = tk.Label(window, width=40) lb.place(x=85, y=690) self.w = w self.r = r self.row = row self.col = col self.period = 1 self.window = window self.canvas = canvas self.pause_text = pause_text self.text = lb self.black_player = None self.white_player = None self.players = [None, None, None] self.current_player = None self.current_stone = None self.timer = None self.play_timer = None self.replay_timer = None self.winner = None self.started = False self.ended = False self.action_select_signal = None self.start_btn_text = start_btn_text self.record_path = record_path self.record_entry = record_entry self.event = threading.Event() self.record = Record() # 记录棋谱: board:from_:to_:del_num self.stones = [] init_board = init_boards[self.board_var.get()] self.init_stone(init_board) def start(self): if self.start_btn_text.get() == 'stop': if messagebox.askokcancel(title='请确认', message='确定停止当前棋局?'): self.stop() return init_board = np.array(init_boards[self.board_var.get()]) self.init_stone(init_board) first_player = self.first_player.get() player_name = self.player_var.get() player_class, p, kp = self.player_map[player_name] white_player = player_class(*p, init_board=init_board, first_player=first_player, **kp) black_player = HummanPlayer('Jhon', BLACK_VALUE, self.sig_black, self.winner_black, self.clock_black, init_board=init_board, first_player=first_player) self.players[WHITE_VALUE] = white_player self.players[BLACK_VALUE] = black_player for stone in self.stones: stone.player = white_player if stone.value == WHITE_VALUE else black_player self.black_player = black_player self.white_player = white_player self.canvas.itemconfigure(self.name_white, text=white_player.name) self.canvas.itemconfigure(self.name_black, text=black_player.name) self.current_player = self.players[first_player] self.show_signal() self.begin_timer() self.canvas.bind('<Button-1>', self.onclick) self.start_btn_text.set('stop') self.white_player.start(init_board=init_board, first_player=first_player) self.black_player.start(init_board=init_board, first_player=first_player) self.started = True self.play() def board_selected(self, _): self.board_choosen.selection_clear() if not self.started: init_board = init_boards[self.board_var.get()] self.init_stone(init_board) def play(self): logger.info('%s play...', self.current_player) # if self.current_player.is_humman(): # 对手预测走棋 # bd = self.board() # pl = self.current_player.stone_val # op = self.opponent().predict_opponent(bd) # if op is not None: # valid = rule.valid_action(bd, pl) # self.show_qtext(op, valid, hide=False) # return board = self.board() self.current_player.play(board) def _play(self, player, from_, to_, p, opp_q=None): logger.info('from:%s, to_:%s', from_, to_) logger.debug('p:\n%s', p) board = self.board() valid_action = rule.valid_action(board, player) logger.debug('valid_action:\n%s', valid_action) self.show_qtext(p, valid_action) self.show_select(from_, to_) stone = self.stone(from_) def play_later(): result = self.move_to(stone, to_) if opp_q is not None: opp_valid = rule.valid_action(self.board(), -player) self.show_qtext(opp_q, opp_valid, hide=False) if result == rule.ACCQUIRE: # 对手走棋 self.switch_player_and_play() elif result == rule.WIN: logger.info('GAME OVER, WINNER IS %s', stone.player.name) self.game_over(stone.player) self.play_timer = self.window.after(int(self.period * 1000), play_later) def init_stone(self, board=None): self.clear() if board is None: board = init_boards[0] board = np.array(board) n = 1 for i, j in np.argwhere(board == WHITE_VALUE): self.create_stone(i, j, WHITE_VALUE, text=str(n)) n += 1 n = 1 for i, j in np.argwhere(board == BLACK_VALUE): self.create_stone(i, j, BLACK_VALUE, text=str(n)) n += 1 def onmotion(self, event): # self.show_message('position is (%d,%d)' % (event.x, event.y)) self.move_to_pos(self.current_stone, event.x, event.y) def onclick(self, event): x, y = event.x, event.y if not (self.w - self.r < x < self.w * 5 + self.r and self.w - self.r < y < self.w * 5 + self.r): # self.show_message('click at (%d,%d)' % (event.x, event.y)) return if not self.current_player.is_humman(): return posx = x / self.w - 0.5 posy = y / self.w - 0.5 # 整数部分 posx_i = int(posx) posy_i = int(posy) # 小数部分 posx_d = posx - posx_i posy_d = posy - posy_i # self.show_message('click at (%d,%d) position is %d,%d' % (event.x, event.y, posx_i, posy_i)) if 0.25 < posx_d < 0.75 and 0.25 < posy_d < 0.75: loc = self.pos_to_loc(x, y) if self.current_stone is None: stone = self.stone(loc) if stone and stone.player == self.current_player: self.move_to_pos(stone, x, y) self.begin_moving(stone) else: self.end_moving(loc) def begin_moving(self, stone): self.current_stone = stone self.canvas.bind('<Motion>', self.onmotion) def end_moving(self, loc): stone = self.current_stone board = self.board() from_ = stone.loc result = self.move_to(stone, loc) if result == rule.INVALID_MOVE: return False self.canvas.unbind('<Motion>') self.current_stone = None if result == rule.NOT_MOVE: self.move_to_loc(stone, loc) if result == rule.ACCQUIRE: # 将走的子告知对手 self.opponent().opponent_play(board, from_, loc) self.switch_player_and_play() elif result == rule.WIN: logger.info('GAME OVER, WINNER IS %s', stone.player.name) # self.opponent().stop() self.game_over(stone.player) def move_to(self, stone, to_loc): """ 把棋子移动到to_loc处,同时判断是否吃子 :param stone: :param to_loc: :return: True:终止移动,False:继续移动 """ old_board = self.board() from_ = stone.loc result, del_stone_loc = rule.move(self.board(), stone.loc, to_loc) if result == rule.ACCQUIRE or result == rule.WIN: self.move_to_loc(stone, to_loc) for loc in del_stone_loc: self.del_stone(self.stone(loc)) logger.info('from %s to %s, result:%s, del:%s', from_, to_loc, result, del_stone_loc) action = rule.actions_move.index(tuple(np.subtract(to_loc, from_))) logger.debug('action is: %s', action) self.record.add(old_board, from_, action, len(del_stone_loc), None, win=(result == rule.WIN)) return result def replay(self): recordpath = self.record_path.get() if not recordpath: self.show_message(message='请点击"open"按扭选择棋谱位置') return self.stop() self.event.set() record = Record() record.read(recordpath) init_bd = record[0][0] self.init_stone(init_bd) record_iter = iter(record) length = len(record) record.n = 1 def play_next_step(): self.event.wait() try: board, from_, action, reward = next(record_iter) player = board[from_] to_ = tuple(np.add(from_, rule.actions_move[action])) assert (board == self.board()).all(), str(board) + '\n' + str( self.board()) result = self.move_to(self.stone(from_), to_) if result == rule.WIN: winner_text = self.winner_black if player == 1 else self.winner_white self.canvas.itemconfigure(winner_text, state=tk.NORMAL) self.show_message( str(length) + ':' + str(record.n) + ',reward: ' + str(reward)) record.n += 1 self.replay_timer = threading.Timer(self.period, play_next_step) self.replay_timer.start() except StopIteration: return self.replay_timer = threading.Timer(self.period, play_next_step) self.replay_timer.start() def select_record(self): f = filedialog.askopenfilename() if f: self.record_path.set(f) self.record_entry.index(len(f) - 10) def pause(self): if self.pause_text.get() == 'pause': self.event.clear() self.pause_text.set('resume') else: self.event.set() self.pause_text.set('pause') def del_stone(self, stone): self.canvas.delete(stone.oval) self.canvas.delete(stone.text) self.stone(stone.loc, None) def switch_player(self): self.hide_signal() self.cancel_timer() self.current_player = self.white_player if self.current_player is self.black_player else self.black_player self.show_signal() self.begin_timer() def switch_player_and_play(self): self.switch_player() self.play() def move_to_loc(self, stone, loc): self.stone(stone.loc, None) self.stone(loc, stone) i, j = loc self.move_to_pos(stone, (j + 1) * self.w, (i + 1) * self.w) def move_to_pos(self, stone, x, y): self.canvas.coords(stone.oval, x - self.r, y - self.r, x + self.r, y + self.r) self.canvas.coords(stone.text, x, y) def opponent(self, player=None): if player is None: player = self.current_player return self.players[-player.stone_val] def stone(self, loc, value=Stone.NONE): i, j = loc if value != Stone.NONE: self._board[i][j] = value if value is not None: value.loc = loc return self._board[i][j] def create_stone(self, i, j, value, text=''): w, r = self.w, self.r color = '#EEE' if value == WHITE_VALUE else '#111' text_color = '#111' if value == WHITE_VALUE else '#EEE' s = Stone((i, j), self.create_oval(w * (j + 1), w * (i + 1), r, fill=color, outline=color), value=value, text=self.canvas.create_text(w * (j + 1), w * (i + 1), text=text, fill=text_color, font=font.Font(size=24, weight='bold'))) self.stone((i, j), value=s) self.stones.append(s) def pos_to_loc(self, x, y): i = int(y / self.w - 0.5) j = int(x / self.w - 0.5) if -1 < i < 5 and -1 < j < 5: return i, j def clear_stone(self): for s in self.stones: self.del_stone(s) self.stones.clear() def stop(self): if self.timer: self.cancel_timer() if self.play_timer: self.window.after_cancel(self.play_timer) if self.replay_timer: self.replay_timer.cancel() self.start_btn_text.set('start') self.pause_text.set('pause') if self.black_player: self.black_player.stop() self.black_player = None if self.white_player: self.white_player.stop() self.white_player = None self.started = False self.ended = True def clear(self): self.clear_stone() self.clear_timer() self.hide_signal() self.hide_winner() self.hide_qtext() self.hide_select() self.show_message('') self.current_player = None self.current_stone = None self.timer = None self.winner = None self.record.clear() self.ended = False def game_over(self, winner): # self.lb.config(text='winner is: ' + str(winner)) self.winner = winner self.started = False self.ended = True self.canvas.unbind('<Button-1>') self.cancel_timer() self.hide_signal() self.show_winner() self.start_btn_text.set('start') failer = self.opponent(winner) self.record_path.set( self.record.save('records/app/' + winner.name + '_' + failer.name + '_')) self.record.clear() self.white_player.stop() self.black_player.stop() def board(self): return np.array([[0 if s is None else s.value for s in row] for row in self._board]) def begin_timer(self): self.canvas.itemconfigure(self.current_player.clock, text='00:00') self.current_player.begin_time = int(time.time()) def timer(player): use_time = int(time.time()) - player.begin_time player.total_time += use_time self.canvas.itemconfigure(player.clock, text='%02d:%02d' % (use_time // 60, use_time % 60)) self.timer = self.canvas.after(1000, timer, player) self.timer = self.canvas.after(1000, timer, self.current_player) def cancel_timer(self): self.canvas.after_cancel(self.timer) def clear_timer(self): self.canvas.itemconfigure(self.clock_white, text='00:00') self.canvas.itemconfigure(self.clock_black, text='00:00') def change_period(self, scale): self.period *= scale logger.debug(self.period) def show_select(self, from_, to_): """ 显示选择的动作 """ if not self.print_q_flag: return self.hide_select() a = np.subtract(to_, from_) logger.debug('select action is: %s', tuple(a)) i, j = from_ x, y = np.array([self.w * (j + 1), self.w * (i + 1)]) + np.array(a)[::-1] * 25 self.action_select_signal = self.create_oval(x, y, r=13, outline='#FFB90F', width=2) def hide_select(self): """ 隐藏选择的动作 """ self.canvas.delete(self.action_select_signal) def create_oval(self, x, y, r, **config): return self.canvas.create_oval(x - r, y - r, x + r, y + r, **config) def show_qtext(self, qtable, valid_action, hide=True): """ 显示动作的Q值 """ if not self.print_q_flag: return if hide: self.hide_qtext(valid_action) maxq = np.max(qtable) avgq = qtable.sum() / valid_action.sum() idx = np.argwhere(valid_action == 1) # logger.info(idx) for i, j, k in idx: q = qtable[i, j, k] qtext = self.qtext(i, j, k) stone = self.stone((i, j)) self.canvas.itemconfigure(qtext, text=str(round(q, 2)).replace('0.', '.'), fill='red' if q == maxq else ('#BF3EFF' if q > avgq else 'green'), state=tk.NORMAL) self.canvas.tag_raise(qtext, stone.oval) def hide_qtext(self, valid_action=None): """ 隐藏动作的Q值 """ if valid_action is None: valid_action = np.zeros((5, 5, 4)) idx = np.argwhere(valid_action == 0) for i, j, k in idx: self.canvas.itemconfigure(self.qtext(i, j, k), text='', state=tk.HIDDEN) def hide_q(self): if self.hide_q_str.get() == 'hideQ': self.hide_qtext() self.hide_select() self.print_q_flag = False self.hide_q_str.set('showQ') elif self.hide_q_str.get() == 'showQ': self.print_q_flag = True self.hide_q_str.set('hideQ') def qtext(self, i, j, k): return self._qtext[i][j][k] def show_message(self, message): self.text.config(text=message) def show_signal(self): self.canvas.itemconfigure(self.current_player.signal, state=tk.NORMAL) def hide_signal(self): self.canvas.itemconfigure(self.sig_white, state=tk.HIDDEN) self.canvas.itemconfigure(self.sig_black, state=tk.HIDDEN) def show_winner(self): self.canvas.itemconfigure(self.winner.winner_text, state=tk.NORMAL) def hide_winner(self): self.canvas.itemconfigure(self.winner_white, state=tk.HIDDEN) self.canvas.itemconfigure(self.winner_black, state=tk.HIDDEN) def help(self): window_help = tk.Toplevel(self.window) window_help.geometry('400x620') tk.Label(window_help, text='1.规则', font=font.Font(size=16, weight='bold')).grid(row=0, sticky='w', padx=5) tk.Label(window_help, text='1)走棋:一次只能上下左右移动一步', font=font.Font(size=14)).grid(row=1, sticky='w', padx=5) tk.Label(window_help, text='2)吃子:', font=font.Font(size=14)).grid(row=2, sticky='w', padx=5) canvas = tk.Canvas(window_help, width=200, height=100, bg='blue') w = 50 # 棋格宽度 r = 20 # 棋子半径 # 棋盘 canvas.create_line(0, 50, 200, 50, width=2) canvas.create_line(5, 0, 5, 100, width=2) for i in range(1, 5): canvas.create_line(i * w, 0, i * w, 100, width=2) canvas.create_oval(50 - r, 50 - r, 50 + r, 50 + r, fill='#111', outline='#111') canvas.create_oval(100 - r, 50 - r, 100 + r, 50 + r, fill='#111', outline='#111') canvas.create_oval(150 - r, 50 - r, 150 + r, 50 + r, fill='#EEE', outline='#EEE') d = 2**0.5 * r // 2 canvas.create_line(150 - d, 50 - d, 150 + d, 50 + d, fill='red', width=2) canvas.create_line(150 - d, 50 + d, 150 + d, 50 - d, fill='red', width=2) canvas.grid(row=3, sticky='w', padx=20) text = ' 如上所示:\n' \ ' a.任意一个黑子走至当前位置后\n' \ ' b.形成在一条直线上有两个黑子对一个白子(白子在边上)\n' \ ' c.且这三个棋子是连续的\n' \ ' d.且该直线上只有这三个棋子时\n' \ ' 白子被吃掉(直线横坚均可)。\n' \ ' 注意abcd四个条件缺一不可,白子走到当前位置不会被吃。' tk.Label(window_help, text=text, anchor='w', justify='left', font=font.Font(size=14)).grid(row=5, sticky='w', padx=5) tk.Label(window_help, text='3)赢棋:对方棋子少于两个或无路可走时赢棋', font=font.Font(size=14)).grid(row=6, sticky='w', padx=5) tk.Label(window_help, text='2.使用', font=font.Font(size=16, weight='bold')).grid(row=7, sticky='w', padx=5) tk.Label(window_help, text='1)安装:建议安装anaconda,keras', font=font.Font(size=14)).grid(row=8, sticky='w', padx=5) tk.Label(window_help, text='2)开始:选择对手,先手后点击start按扭开始', font=font.Font(size=14)).grid(row=9, sticky='w', padx=5) tk.Label(window_help, text='3)走棋:点击己方棋子,移动到目标位置后单击即可落子', font=font.Font(size=14)).grid(row=10, sticky='w', padx=5) tk.Label(window_help, text='4)结束:点击stop按扭可结束棋局', font=font.Font(size=14)).grid(row=11, sticky='w', padx=5) tk.Label(window_help, text='5)回放:点击replay按扭可以回放棋局,\n' ' 点击select按扭可选择棋谱,\n' ' 点击faster,slower按扭可调节回放速度,\n' ' 点击pause/resume按扭可暂停/继续回放', anchor='w', justify='left', font=font.Font(size=14)) \ .grid(row=12, sticky='w', padx=5) tk.Label(window_help, text='6)可以根据需要选择不同的开局局面,\n' ' 局面可在init_boards.py中添加。', anchor='w', justify='left', font=font.Font(size=14)) \ .grid(row=13, sticky='w', padx=5) tk.Label(window_help, text='7)点击hideQ/showQ按扭可隐藏/显示Q值', anchor='w', justify='left', font=font.Font(size=14)) \ .grid(row=14, sticky='w', padx=5) @staticmethod def launch(): tk.mainloop()
class Material(object): def __init__(self): self.material_data = dict() self.columns_name = [] self.name_lis = [] self.fuzzname = Fuzzname() self.load_data(o_path + "res-0810.csv") self.record = Record(o_path + "record_material.txt") def load_data(self, filename): self.material_data = dict() self.name_lis = [] with open(filename, encoding='UTF-8') as fp: csv_reader = csv.reader(fp) self.columns_name = next(csv_reader)[:5] for line in csv_reader: name = line[0] self.material_data[name] = dict( list(zip(self.columns_name[0:5], line[0:5]))) self.name_lis.append(name) self.fuzzname.fit(self.material_data.keys()) def format(self, name): # lines=[] # lines.append(["\t"]+self.columns_name[1:4]) # lines.append([name]+[self.material_data[name][colname] for colname in self.columns_name[1:4]]) # lines.append([self.columns_name[4]+":"+self.material_data[name][self.columns_name[4]]]) # res="\n".join(["\t".join(line) for line in lines]) reslis = [] reslis.append(name + " " + self.material_data[name]["材料等级"] + "色") for colname in self.columns_name[2:5]: if self.material_data[name][colname]: reslis.append("{0}: {1}".format( colname, self.material_data[name][colname])) res = "\n".join(reslis) return res def recom(self, name): if not name: return None if name not in self.material_data: name = self.fuzzname.predict(name) res = self.format(name) self.record.add(name) return res def export_table_md(self): self.fetch_wiki() item_lis = ["img_div"] + self.columns_name[:5] with open(o_path + "materials.md", "w", encoding='UTF-8') as fp: fp.write("# 刷材料推荐地点\n\n") fp.write("数据来源——丸丸\n\n") fp.write("<table>\n") fp.write("<tr>\n") for colname in [""] + self.columns_name[:5]: fp.write("<td>") fp.write(colname) fp.write("</td>\n") fp.write("</tr>\n") for name in self.name_lis: fp.write("<tr>\n") for item_name in item_lis: fp.write("<td>") fp.write(self.material_data[name][item_name]) fp.write("</td>\n") fp.write("</tr>\n") fp.write("</table>\n") def fetch_wiki(self): url_prefix = "http://wiki.joyme.com" r = requests.get(url_prefix + "/arknights/材料") tree = html.fromstring(r.text) mati_lis = tree.xpath("//span[@class='itemhover']/div[1]") for mati in mati_lis: name = mati.xpath("./a/@title")[0] if name and name in self.material_data: sub_link = mati.xpath("./a/@href")[0] self.material_data[name]["link"] = url_prefix + sub_link self.material_data[name]["img"] = mati.xpath("./a/img/@src")[0] self.material_data[name]["img_div"] = unescape( html.tostring(mati).decode('utf-8')).replace( sub_link, self.material_data[name]["link"])
class Character(object): def __init__(self): self.char_data = dict() self.enemy_data = dict() self.head_data = [] self.head_key_map = { "职业": "job", "星级": "rank", "性别": "sex", "阵营": "affiliation", "标签": "tags", "获取途径": "obtain_method" } self.fuzzname = Fuzzname() self.record = Record(path_prefix + "record_peo.txt") def extract_all_char(self, text_file=None, enemy_file=None): if text_file is None: text_file = path_prefix + "chardata.json" if enemy_file is None: enemy_file = path_prefix + "enemylist.json" if not os.path.exists(text_file) or not os.path.exists(enemy_file): self.fetch_data() # deal char with open(text_file, encoding='UTF-8') as fp: self.char_data = json.load(fp) # deal enemy with open(enemy_file, encoding='UTF-8') as fp: self.enemy_data = json.load(fp) # fuzzy name+pinyin -> name self.fuzzname.fit( list(self.char_data.keys()) + list(self.enemy_data.keys())) def filter(self, tags, flags={}): tags = tags[:] ranks = self.gen_ranks(tags) for name, dic in self.char_data.items(): if set(tags).issubset(set(dic["tags"])): pass else: continue if dic["rank"] in ranks or ('show_all' in flags and flags['show_all'] == True): pass else: continue if "公开招募" in dic["obtain_method"] or ('show_all' in flags and flags['show_all'] == True): pass else: continue yield name def gen_ranks(self, tags): ranks = ["1", "2", "3", "4", "5", "6"] for i in range(1, 7): if ">={0}".format(i) in tags: ranks = [x for x in ranks if x >= str(i)] tags.remove(">={0}".format(i)) if "<={0}".format(i) in tags: ranks = [x for x in ranks if x <= str(i)] tags.remove("<={0}".format(i)) if "高级资深干员" not in tags: ranks.remove("6") if "资深干员" in tags: ranks = ["5"] if "高级资深干员" in tags: ranks = ["6"] return ranks def get_peo_info(self, name=None): if not name: return None res = "None" if name in self.char_data: res = self.format_friend_info(name) self.record.add("friend/" + name) elif name in self.enemy_data: res = self.format_enemy_info(name) self.record.add("enemy/" + name) else: res = self.fuzzname.predict(name) res = "你可能想查 {0}".format(res) return res def format_friend_info(self, name): res = [] for tp, cont in self.char_data[name]['all'].items(): if tp: if tp == "干员代号": tp = "姓名" res.append("{0}: {1}".format(tp, cont)) url = self.char_data[name]["link"] res.append(url) return "\n".join(res) def format_enemy_info(self, name): res = [name] url = self.enemy_data[name]["link"] res.append(url) return "\n".join(res) def fetch_data(self): self.fetch_character_from_wikijoyme() try: self.fetch_enemy_from_akmooncell() except Exception as e: print(e) self.fetch_enemy_from_wikijoyme() def fetch_character_from_wikijoyme(self, filename="chardata.json"): r = requests.get("http://wiki.joyme.com/arknights/干员数据表") if r.status_code != 200: raise IOError("Cannot fetch char from wikijoyme") tree = html.fromstring(r.text) # table head data tb_head = tree.xpath("//table[@id='CardSelectTr']//th/text()") tb_head = [x.strip() for x in tb_head] # deal with character char_res_lis = tree.xpath("//tr[@data-param1]") char_data = dict() for char_tr in char_res_lis: name = char_tr.xpath("./td[2]/a[1]/text()")[0] char_data[name] = dict() char_data[name]["job"] = char_tr.xpath("./@data-param1")[0] char_data[name]["rank"] = char_tr.xpath("./@data-param2")[0].split( ",")[0] char_data[name]["sex"] = char_tr.xpath("./@data-param3")[0] char_data[name]["affiliation"] = char_tr.xpath("./@data-param4")[0] tag_string=char_tr.xpath("./@data-param5")[0]+", " \ +char_data[name]["sex"]+", " \ +char_data[name]["job"]+", " \ +("资深干员" if char_data[name]["rank"]=="5" else "")+", " \ +("高级资深干员" if char_data[name]["rank"]=="6" else "")+", " taglist = [x.strip() for x in tag_string.split(",")] taglist = [x for x in taglist if x != ""] char_data[name]["tags"] = taglist char_data[name]["obtain_method"] = list( map(lambda x: x.strip(), char_tr.xpath("./@data-param6")[0].split(","))) #deal head and data td_lis = char_tr.xpath(".//td") text_lis = [ "".join([xx.strip() for xx in x.xpath(".//text()")]) for x in td_lis ] all_lis = [x.strip() for x in text_lis] all_dict = dict(zip(tb_head, all_lis)) char_data[name]["all"] = all_dict # link char_link_root = "http://wiki.joyme.com/arknights/" url = char_link_root + urllib.parse.quote(name) char_data[name]["link"] = url char_data[name]["type"] = "friend" with open(path_prefix + filename, "w", encoding='utf-8') as fp: json.dump(char_data, fp) return char_data def fetch_enemy_from_akmooncell(self, filename="enemylist.json"): # get enemy data r = requests.get("http://ak.mooncell.wiki/w/敌人一览") if r.status_code != 200: raise IOError("Cannot fetch enemy from akmooncell") tree = html.fromstring(r.text) enemy_res_lis = tree.xpath("//div[@class='smwdata']") enemy_data = dict() enemy_link_root = "http://ak.mooncell.wiki/w/" for enemy_a in enemy_res_lis: name = enemy_a.xpath("./@data-name")[0] # print("===="+name) enemy_data[name] = dict() link = enemy_link_root + urllib.parse.quote(name) enemy_data[name]["link"] = link enemy_data[name]["type"] = "enemy" with open(path_prefix + filename, "w", encoding='utf-8') as fp: json.dump(enemy_data, fp) return enemy_data def fetch_enemy_from_wikijoyme(self, filename="enemylist.json"): # get enemy data r = requests.get("http://wiki.joyme.com/arknights/敌方图鉴") if r.status_code != 200: raise IOError("Cannot fetch enemy from wikijoyme") tree = html.fromstring(r.text) enemy_res_lis = tree.xpath("//tr[@data-param1]") enemy_data = dict() enemy_link_root = "http://ak.mooncell.wiki/w/" for enemy_a in enemy_res_lis: name = enemy_a.xpath("./td[2]/a[1]/text()")[0] print("====" + name) enemy_data[name] = dict() link = enemy_link_root + urllib.parse.quote(name) enemy_data[name]["link"] = link enemy_data[name]["type"] = "enemy" with open(path_prefix + filename, "w", encoding='utf-8') as fp: json.dump(enemy_data, fp) return enemy_data