本節作業:
熟練使用類和模塊,寫一個交互性強、有沖突的程序。
故本次寫了一個文字回合制的PK游戲,系統主程序為根目錄下的:game_menu.py
1. 系統功能模塊:
第六天的作業:文字游戲程序是在python3.4環境下開發,在python2.7環境下大同小異,主要功能模塊如下圖:

2. 系統目錄結構:
程序采用分層的方式編寫,包括系統配置conf、數據庫訪問層database、業務邏輯層modules,業務處理主程序game_menu.py,主要分類如下圖:

3.應用知識點:
a) 類的使用
b) 文件的讀寫操作
c) 系統模塊、自定義模塊的操作
d) 日志模塊的使用
4.程序流程圖如下:

5.程序代碼如下:
5.1 主程序game_menu.py:
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 游戲主程序文件 ''' import os,sys,random,time from datetime import date,datetime from conf import setting,menu from modules import common,role,skill,report from database import dbapi ###角色屬性和技能顯示函數### def role_skill_show(): ''' 當主菜單選擇1時,進行角色的屬性和技能查看 :return: 沒有返回值 ''' show_flag = False while not show_flag: ###輸出角色默認的菜單,有戰士,弓箭手,法師### print(menu.role_default_menu.format(today, common.numtochr(weekoftoday))) ###選擇角色的編號、分別調用戰士,弓箭手,法師三個角色類### role_choose = common.input_msg_choose("請選擇查看角色[1-3]: ", ["1", "2", "3","b"]).strip() if role_choose == '1': roleadj = role.zhanshi(role_choose) elif role_choose == '2': roleadj = role.gongjianshou(role_choose) elif role_choose == '3': roleadj = role.fashi(role_choose) else: show_flag = True continue ###輸出角色的說明介紹及初始技能### common.show_message('角色說明如下:', "NOTICE") roleadj.role_instruction() ###輸出角色的三個攻擊技能### common.show_message('【%s】技能如下:' % (roleadj.role), "NOTICE") skill.skill(role_choose).print_skill_list() ###角色選擇### def choose_role(vs_type,role_choose,role_list): """ 角色選擇函數 :param vs_type 指定是挑戰方,還是應戰方 :param role_choose: 角色選擇輸入的字符 :return:role_list 角色名字,角色,角色的血量,角色名字列表 """ role_info = {} ###判斷輸入值是否為b,如果是則退出### if role_choose == "b": sys.exit() else: ###角色名字列表賦值### name_list = role_list[role_choose] ###角色類的實例化### roleadj = role.role(role_choose) ###選擇角色各自的名字 vs_name = common.input_msg_choose("請選擇%s名字%s : " % (vs_type,name_list), name_list).strip() ###角色初始技能是否開啟### init_skill_info = (roleadj.init_skill,roleadj.init_chance_rate,roleadj.init_harm_rate) init_skill_flag = common.input_msg_choose("初始技能【%s : %s%% 機率減少傷害 %s%%】,是否開啟(y/n)" % init_skill_info, ['y','n']).strip() ###調用role類中的初始技能開關函數### init_skill_result = roleadj.init_skill_choose(init_skill_flag) if init_skill_result: common.show_message('已正常開啟初始技能【%s : %s%% 機率減少傷害 %s%%】' % init_skill_info, "INFORMATION") else: common.show_message('禁止啟用初始技能【%s】' % roleadj.init_skill, "NOTICE") ###挑戰和守擂雙方在選擇同一種角色時,強制選擇不同的二個名字### name_list.remove(vs_name) ###輸出角色的技能### common.show_message('%s【%s】技能如下:' % (vs_type,roleadj.role), "NOTICE") skill.skill(role_choose).print_skill_list() ###定義角色的信息字典,方便return### role_info = { "name" : vs_name, "role" : roleadj.role, "life" : roleadj.life, "init_skill_flag" : roleadj.init_skill_flag, "init_skill" : roleadj.init_skill, "init_chance_rate" : roleadj.init_chance_rate, "init_harm_rate" : roleadj.init_harm_rate } return(role_info,name_list) ###挑戰和守擂雙方PK函數### def role_vs(offensive_info,defensive_info): ''' 挑戰和守擂雙方PK函數 :param offensive_info: 挑戰方的信息字典 :param defensive_info: 防守方的信息字典 :return: 沒有返回值 ''' ###獲取challage的信息### offensive_choose = offensive_info['choose'] offensive_name = offensive_info['name'] offensive_role = offensive_info['role'] offensive_life = offensive_info['life'] offensive_init_skill_flag = offensive_info['init_skill_flag'] offensive_init_skill = offensive_info['init_skill'] offensive_init_chance_rate = offensive_info['init_chance_rate'] offensive_init_harm_rate = offensive_info['init_harm_rate'] ###獲取response的信息### defensive_choose = defensive_info['choose'] defensive_name = defensive_info['name'] defensive_role = defensive_info['role'] defensive_life = defensive_info['life'] defensive_init_skill_flag = defensive_info['init_skill_flag'] defensive_init_skill = defensive_info['init_skill'] defensive_init_chance_rate = defensive_info['init_chance_rate'] defensive_init_harm_rate = defensive_info['init_harm_rate'] ###PK雙方的技能實例化和獲取技能編號列表### offensive_skill_obj = skill.skill(offensive_choose) offensive_skill_list = offensive_skill_obj.skill_id_list() defensive_skill_obj = skill.skill(defensive_choose) defensive_skill_list = defensive_skill_obj.skill_id_list() i = 1 flag = False common.show_message('雙方准備,對戰開始',"INFO") ###自動對戰的開關### auto_flag = common.input_msg_choose("是否自動對戰(y/n):",['y','n']).strip() while not flag: ###VS對方菜單,顯示對戰雙方的角色,名字和血量### print(menu.vs_menu.format(offensive_name,offensive_role,offensive_life,defensive_name,defensive_role,defensive_life)) common.show_message('第{0}回合'.format(i),"NOTICE") ###如果挑戰方血量大於0,挑戰方開始選擇技能### if offensive_life > 0: if auto_flag == "y": ###自動對戰開啟,在技能列表中隨機生成一個數字### offensive_skill_id = str(random.randint(int(offensive_skill_list[0]),int(offensive_skill_list[-1]))) else: ###手工對戰時,輸入技能編號### offensive_skill_id = common.input_msg_choose("請挑戰方選擇技能編號【%s]: " % offensive_skill_list, offensive_skill_list).strip() ###調用技能傷害函數,並計算雙方的剩余血量### (offensive_life,defensive_life) = offensive_skill_obj.skill_harm(offensive_skill_id,offensive_info,defensive_info) offensive_info['life'] = offensive_life defensive_info['life'] = defensive_life else: common.show_message('挑戰方【%s】已經掛了,應戰方【%s】守擂成功' % (offensive_name,defensive_name),"ERROR") ###挑戰方掛了,進行PK記錄回寫報表文件### report.record_input_file(offensive_role,offensive_name,defensive_role,defensive_name,True) ###挑戰方掛了,進行PK記錄回寫日志文件### common.log_input_file(offensive_name,defensive_name,True) ###PK結束,退出本次循環### flag = True continue ###守擂方血量大於0,開始選擇技能### if defensive_life > 0: if auto_flag == "y": ###自動對戰開啟,在技能列表中隨機生成一個數字### defensive_skill_id = str(random.randint(int(defensive_skill_list[0]),int(defensive_skill_list[-1]))) else: ###手工對戰時,輸入技能編號### defensive_skill_id = common.input_msg_choose("請應戰方選擇技能編號【%s]: " % defensive_skill_list, defensive_skill_list).strip() ###調用技能傷害函數,並計算雙方的剩余血量### (defensive_life,offensive_life) = defensive_skill_obj.skill_harm(defensive_skill_id,defensive_info,offensive_info) defensive_info['life'] = defensive_life offensive_info['life'] = offensive_life else: common.show_message('挑戰方【%s】成功獲勝,應戰方【%s】已經升天了' % (offensive_name,defensive_name),"ERROR") ###守擂方掛了,進行PK記錄回寫報表文件### report.record_input_file(offensive_role,offensive_name,defensive_role,defensive_name,False) ###挑戰方掛了,進行PK記錄回寫日志文件### common.log_input_file(offensive_name,defensive_name,False) ###PK結束,退出本次循環### flag = True continue time.sleep(2) i += 1 ###PK場菜單函數### def battlefield(role_name_list): ''' 在進入PK場后,選擇雙方的角色### :param role_name_list: 角色名字列表 :return: 沒有返回值 ''' ###進入PK場,輸出角色選擇菜單### print(menu.role_default_menu.format(today, common.numtochr(weekoftoday))) ###初始化PK雙方的角色信息字典### challenge_role_info = {} response_role_info = {} ###選擇挑戰方角色、名稱及初始技能### challenge_choose = common.input_msg_choose("請選擇挑戰方角色[1-3]: ", ["1", "2", "3","b"]).strip() (challenge_role_info,role_name_list[challenge_choose]) = choose_role('挑戰方',challenge_choose,role_name_list) challenge_role_info['choose'] = challenge_choose ###選擇應戰方角色、名稱及初始技能### response_choose = common.input_msg_choose("請選擇應戰方角色[1-3]: ", ["1", "2", "3","b"]).strip() (response_role_info,role_name_list[response_choose]) = choose_role('應戰方',response_choose,role_name_list) response_role_info['choose'] = response_choose response_role_info['life'] += 100 ###調用role_vs,進行對戰環節### role_vs(challenge_role_info,response_role_info) ###PK戰績排序函數### def pk_result_sorted(sort_list,dates,value=0): ''' 對PK戰績進行不同的排序 :param sort_list 角色名字列表 :param dates 起始和結束日期 :param value 指定排序的值 :return 無返回值 ''' ###調用PK記錄報表,獲取所有角色名字的信息### all_user_pk_result = {} user_pk_list = report.print_vs_all_report(sort_list,dates,value) all_user_pk_result = {'startdate':dates['start'], 'enddate':dates['end'], 'vs_record':"\n".join(user_pk_list) } ###輸出所有角色名字的PK記錄並進行排序### common.show_message(menu.all_vs_history.format(**all_user_pk_result),"NOTICE") ###主程序開始,顯示主菜單### if __name__ == "__main__": ###定義並賦值當前的日期和星期幾的顯示### today = datetime.now().strftime("%Y-%m-%d") weekoftoday = date.weekday(datetime.now()) ### -------- 開始主程序 ---------### flag = False while not flag: ###定義三類角色的名字列表,戰士,弓箭手,法師各有二個用戶### _role_list = { "1" : ['za','zb'], "2" : ['ga','gb'], "3" : ['fa','fb'] } ###顯示游戲的主菜單界面,分別有角色,PK場,戰績榜### print(menu.main_menu.format(today, common.numtochr(weekoftoday))) choose = common.input_msg_choose("選擇功能編號[0-3]: ", ["0", "1", "2", "3"]).strip() ###0、退出游戲### if choose == "0": flag = True continue ###1、角色及技能介紹### if choose == "1": role_skill_show() ###調用角色信息顯示函數### ###2、PK場### if choose == "2": battlefield(_role_list) ###調用PK場函數### ###3、戰績榜### if choose == "3": ###定義初始的用戶列表和用戶選擇菜單### _name_list = ['za','zb','ga','gb','fa','fb'] _name_add_list = ['za','zb','ga','gb','fa','fb','b'] ###調用report函數的起始和結束日期輸入函數### date_dict = report.get_date() ###調用PK記錄的排序函數,默認是按用戶排序的### pk_result_sorted(_name_list,date_dict) pk_flag = False while not pk_flag: ###輸入指定排序的方式編號### sort_input = common.input_msg_choose("輸入戰績排序編號[0-3]:", ["0","1","2","3"]).strip() ###選擇0時,結束排序,進行用戶查詢環節### if sort_input != "0": ###根據輸入的排序編號進行具體排序### pk_result_sorted(_name_list,date_dict,int(sort_input)) continue query_flag = False while not query_flag: ###輸入具體的角色名字,來查詢具體的PK記錄### user_name = common.input_msg_choose("輸入用戶【%s】,返回(b): " % _name_list,_name_add_list).strip() ###當輸入b時,返回到主菜單### if user_name == 'b': pk_flag = True query_flag = True continue else: ###當選擇具體角色名字時,生成並輸出自己的PKu結果和具體記錄### user_pk_result = dict() user_pk_result = report.print_vs_report(user_name,date_dict) common.show_message(menu.role_vs_history.format(**user_pk_result),"NOTICE")
5.2 配置文件包conf:
5.2.1 參數配置文件setting.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 定義基本的變量 ''' import os,sys ###程序文件主目錄### BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ###添加主目錄到環境變量### sys.path.append(BASE_DIR) ###定義角色和技能數據庫信息### DATABASE = dict(engineer="file", dbpath=os.path.join(BASE_DIR, "database"), tables={"role" : "role","skill" : "skill"}) ###日志文件存放路徑### LOG_PATH = os.path.join(BASE_DIR, "log") ###角色初始生命值### init_hp = 1000
5.2.2 界面顯示模板文件menu.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 該模塊用來定義系統的菜單模板 ''' # 主程序中的菜單輸出信息### main_menu = ''' ------------------------------------------------------------------------- kevin在線游戲 今天 {0} 星期{1} ------------------------------------------------------------------------- 【1】角色介紹 【2】PK場 【3】戰績榜 【0】退出 ------------------------------------------------------------------------- ''' ###角色菜單輸出信息### role_default_menu = ''' ------------------------------------------------------------------------- 角色 今天 {0} 星期{1} ------------------------------------------------------------------------- 【1】戰士 【2】弓箭手 【3】法師 返回(b) ------------------------------------------------------------------------- ''' ###對戰菜單### vs_menu = ''' ------------------------------------------------------------------------- 挑戰方:{0}({1}) 應戰方:{3}({4}) VS 血量:{2} 血量:{5} ------------------------------------------------------------------------- ''' ###所有用戶戰榜菜單### all_vs_history = ''' ------------------------------------------------------------------------------ 戰績榜 VS時間:{startdate} 至 {enddate} ------------------------------------------------------------------------------ 戰績: 用戶 挑戰次數 挑戰成功次數 守擂次數 守擂成功次數 PK次數 PK成功次數 {vs_record} ------------------------------------------------------------------------------ 【1】挑戰成功次數 【2】守擂成功次數 【3】PK成功次數 【0】用戶查詢 ------------------------------------------------------------------------------ ''' ###具體用戶的戰榜和PK記錄信息### role_vs_history = ''' ------------------------------------------------------------------------------ 戰績榜 用戶:{user} VS時間:{startdate} 至 {enddate} ------------------------------------------------------------------------------ 戰績: 挑戰【{attack_sum}】次,成功【{attack_ok}】次 | 守擂【{defence_sum}】次,成功【{defence_ok}】次 | PK【{all_sum}】次,成功【{ok_sum}】次 PK戰況: ------------------------------------------------------------------------------ 對戰時間 結果 {vs_record} '''
5.3 數據庫包database:
5.3.1 初始化數據模塊db_init.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 定義角色和技能的信息,並初始化輸出到數據庫db文件 ''' import json,os,sys ###程序文件主目錄######程序文件主目錄### BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ###添加主目錄到環境變量### sys.path.append(BASE_DIR) ###導入如下三個模塊### from conf import setting from modules import common from database import dbapi ###角色列表### role_list = { "1": {"role": "戰士", "init_skill":"守護","init_skill_flag":1,"chance_rate" : 50 , "harm_rate" : 20}, "2": {"role": "弓箭手", "init_skill":"閃避","init_skill_flag":1,"chance_rate" : 40 , "harm_rate" : 25}, "3": {"role": "法師", "init_skill":"法盾","init_skill_flag":1,"chance_rate" : 30 , "harm_rate" : 40}, } ###角色的技能列表### role_skill_list = { "1": {"role": "戰士", "skill": ( {"id": "11", "level": "初級技能", "name": "野蠻沖鋒","init_harm": 100, "chance_rate" : 40 , "harm_rate" : 20}, {"id": "12", "level": "中級技能", "name": "旋風斬", "init_harm": 150, "chance_rate" : 30 , "harm_rate" : 20}, {"id": "13", "level": "高級技能", "name": "百刃斬" ,"init_harm": 200, "chance_rate" : 20 , "harm_rate" : 20}, )}, "2": {"role": "弓箭手", "skill": ( {"id": "21", "level": "初級技能", "name": "點射","init_harm": 100, "chance_rate" : 40 , "harm_rate" : 20}, {"id": "22", "level": "中級技能", "name": "連射", "init_harm": 150, "chance_rate" : 30 , "harm_rate" : 20}, {"id": "23", "level": "高級技能", "name": "爆裂箭" ,"init_harm": 200, "chance_rate" : 20 , "harm_rate" : 10}, )}, "3": {"role": "法師", "skill": ( {"id": "31", "level": "初級技能", "name": "火球術","init_harm": 100, "chance_rate" : 40 , "harm_rate" : 20}, {"id": "32", "level": "中級技能", "name": "冰咆哮", "init_harm": 150, "chance_rate" : 30 , "harm_rate" : 20}, {"id": "33", "level": "高級技能", "name": "地獄雷光" ,"init_harm": 200, "chance_rate" : 20 , "harm_rate" : 20}, )} } ''' ###初始化角色數據庫文件 role.db### def init_db_role(): _db_file = os.path.join(setting.DATABASE['dbpath'], "role.db") with open(_db_file, "w+") as f: f.write(json.dumps(role_list)) ###初始化角色技能數據庫文件 skill.db### def init_db_skill(): _db_file = os.path.join(setting.DATABASE['dbpath'], "skill.db") with open(_db_file, "w+") as f: f.write(json.dumps(role_skill_list)) ''' ###初始化角色數據庫文件 role.db### def init_db_role(): _db_file = os.path.join(setting.DATABASE['dbpath'], "role.db") ###調用函數,將角色列表以json的格式寫入文件### dbapi.write_db_json(role_list,_db_file) ###初始化角色技能數據庫文件 skill.db### def init_db_skill(): _db_file = os.path.join(setting.DATABASE['dbpath'], "skill.db") ###調用函數,將角色技能列表以json的格式寫入文件### dbapi.write_db_json(role_skill_list,_db_file) ###初始化技能數據表### def init_database(): tables = list(setting.DATABASE['tables'].values()) ###數據表名稱列表### database = setting.DATABASE['dbpath'] ###數據表存放路徑### for _table in tables: ###數據庫文件存在判斷### if not os.path.exists(os.path.join(database, "{0}.db".format(_table))): print("Table {0}.db create successfull".format(_table)) ###通過反射初始化數據表### if hasattr(sys.modules[__name__], "init_db_{0}".format(_table)): init_func = getattr(sys.modules[__name__], "init_db_{0}".format(_table)) init_func() else: ###如果不存在,則輸出錯誤日志### common.write_log("init table {0} failed,no function init_db_{0} found".format(_table),"error") ###主程序開始,調用初始化函數,生成數據庫文件### if __name__ == "__main__": init_database()
5.3.2 數據訪問層模塊dbapi.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 數據庫訪問層: 1 提供從數據文件、報表文件中讀取數據的接口 2 將數據寫入到數據文件的接口 ''' import os,sys,json from conf import setting from modules.common import write_log ###追加信息到指定文件### def append_db_json(contant, filename): """ 將信息以 json 格式寫入數據表文件(追加) :param contant: 要寫入的 json 格式內容 :param filename: 要寫入的數據表文件名 :return: 無返回 """ try: with open(filename, 'a+') as fa: fa.write(json.dumps(contant)) fa.write("\n") except Exception as e: write_log(e,'critical') ###覆蓋重寫信息到指定文件### def write_db_json(contant, filename): """ 將信息以 json 格式寫入數據表文件(覆蓋) :param contant: 寫入的json數據內容 :param filename: 要寫入的文件名 :return: 無返回結果 """ try: with open(filename, 'w+') as fw: fw.write(json.dumps(contant)) except Exception as e: write_log(e,'critical') ###從指定數據庫文件中讀取數據### def load_data_from_db(tabename): """ 從指定的數據表中獲取所有數據,通過 json 方式將數據返回 :param tabename: 數據文件名 :return: 返回數據庫文件信息 """ try: with open(tabename, 'r+') as f: return json.load(f) except Exception as e: write_log(e,'critical') ###從VS報表中讀取指定用戶的PK記錄### def load_vs_report(startdate, enddate,user=''): """ 查找報表記錄中的指定用戶的PK記錄,將結果存入到列表中 :param user: 角色用戶名 :param startdate: 開始日期 :param enddate: 結束日期 :return: 返回用戶的PK記錄 """ ###指定報表的文件名### _file = os.path.join(setting.LOG_PATH, "vs_report") result = list() try: with open(_file, "r") as f: for line in f: _record = json.loads(line) ###指定輸入用戶信息是否為空### if user: ###判斷用戶是否存在### if _record['attack_name'] == user or _record['defence_name'] == user: ###通過輸入的起始和結束日期對報表記錄進行匹配,是則追加到返回列表中### if _record["time"] >= startdate and _record["time"] <= enddate: result.append(_record) ###輸入用戶為空,則追加所有用戶記錄到返回列表中### else: if _record["time"] >= startdate and _record["time"] <= enddate: result.append(_record) return result ###執行異常,則輸出到錯誤日志文件### except Exception as e: write_log("dbapi > load_vs_report > {0}".format(e),"critical")
5.3.3 數據文件role.db
{"3": {"init_skill": "\u6cd5\u76fe", "harm_rate": 40, "chance_rate": 30, "init_skill_flag": 1, "role": "\u6cd5\u5e08"}, "1": {"init_skill": "\u5b88\u62a4", "harm_rate": 20, "chance_rate": 50, "init_skill_flag": 1, "role": "\u6218\u58eb"}, "2": {"init_skill": "\u95ea\u907f", "harm_rate": 25, "chance_rate": 40, "init_skill_flag": 1, "role": "\u5f13\u7bad\u624b"}}
5.3.4 數據文件skill.db
{"3": {"skill": [{"level": "\u521d\u7ea7\u6280\u80fd", "chance_rate": 40, "id": "31", "name": "\u706b\u7403\u672f", "init_harm": 100, "harm_rate": 20}, {"level": "\u4e2d\u7ea7\u6280\u80fd", "chance_rate": 30, "id": "32", "name": "\u51b0\u5486\u54ee", "init_harm": 150, "harm_rate": 20}, {"level": "\u9ad8\u7ea7\u6280\u80fd", "chance_rate": 20, "id": "33", "name": "\u5730\u72f1\u96f7\u5149", "init_harm": 200, "harm_rate": 20}], "role": "\u6cd5\u5e08"}, "1": {"skill": [{"level": "\u521d\u7ea7\u6280\u80fd", "chance_rate": 40, "id": "11", "name": "\u91ce\u86ee\u51b2\u950b", "init_harm": 100, "harm_rate": 20}, {"level": "\u4e2d\u7ea7\u6280\u80fd", "chance_rate": 30, "id": "12", "name": "\u65cb\u98ce\u65a9", "init_harm": 150, "harm_rate": 20}, {"level": "\u9ad8\u7ea7\u6280\u80fd", "chance_rate": 20, "id": "13", "name": "\u767e\u5203\u65a9", "init_harm": 200, "harm_rate": 20}], "role": "\u6218\u58eb"}, "2": {"skill": [{"level": "\u521d\u7ea7\u6280\u80fd", "chance_rate": 40, "id": "21", "name": "\u70b9\u5c04", "init_harm": 100, "harm_rate": 20}, {"level": "\u4e2d\u7ea7\u6280\u80fd", "chance_rate": 30, "id": "22", "name": "\u8fde\u5c04", "init_harm": 150, "harm_rate": 20}, {"level": "\u9ad8\u7ea7\u6280\u80fd", "chance_rate": 20, "id": "23", "name": "\u7206\u88c2\u7bad", "init_harm": 200, "harm_rate": 10}], "role": "\u5f13\u7bad\u624b"}}
5.4 業務處理包modules:
5.4.1 公共函數模塊common.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 ''' import os,sys,logging,random,re from datetime import datetime,date from conf import setting ###生成隨機數,用於機率判斷來是否觸發技能### def random_decide(random_num,cmp_value,cmp_mode='eq'): """ 生成一個指定范圍值之內隨機數,並對隨機數進行判斷 :param random_num:用來定義隨機數的范圍值 :param cmp_value:定義需要比對的值 :param cmp_flag:如果是gt或lt,則進行大於或小於判斷,如果是eq,則為等於判斷,默認為eq :return: 返回True或False """ ###生成指定范圍的隨機數 ra = random.randrange(1,random_num) ###根據比較符,輸出判斷的字符串### if cmp_mode == 'eq': express = "{0} == {1}" elif cmp_mode == 'gt': express = "{0} > {1}" elif cmp_mode == 'lt': express = "{0} < {1}" else: show_message('比較模式錯誤','ERROR') return False flag = eval(express.format(ra,cmp_value)) ###根據結果,返回正確與否### if flag: return True return False ###根據等級分顏色顯示### def show_message(msg, msgtype): """ 對print函數進行封裝,根據不同類型顯示不同顏色 :param msg: 顯示的消息體 :param msgtype: 消息類型 :return: 返回格式化過的內容 """ if msgtype == "INFO": show_msg = "\033[1;34m{0}\033[0m\n".format(msg) elif msgtype == "INFORMATION": show_msg = "\033[1;32m{0}\033[0m\n".format(msg) elif msgtype == "NOTICE": show_msg = "\033[1;33m{0}\033[0m\n".format(msg) elif msgtype == "ERROR": show_msg = "\033[1;31m{0}\033[0m\n".format(msg) else: show_msg = "{0}\n".format(msg) print(show_msg) ###根據等級將異常信息輸出到日志文件### def write_log(content,levelname): """ 將程序執行過程上中的異常信息記錄到日志文件 :param content: 日志信息 :param levelname:日志級別 :return: 無返回,寫入文件 game.log """ ###指定日志文件的路徑### _filename = os.path.join(setting.LOG_PATH, "game.log") ###自定義日志的格式和等級### logging.basicConfig(level=logging.INFO, encoding = "UTF-8", format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', filename=_filename, filemode='a+') if levelname == 'debug': logging.debug(content) elif levelname == 'info': logging.info(content) elif levelname == 'warning': logging.warning(content) elif levelname == 'error': logging.error(content) elif levelname == 'critical': logging.critical(content) else: show_message('輸入錯誤',"ERROR") ###根據等級將異常信息輸出到日志文件### def write_file(content,levelname,file_name): """ 將程序執行過程上中的異常信息記錄到指定日志文件 :param content: 日志信息 :param levelname:日志級別 :return: 無返回,寫入文件 game.log """ ###自定義日志的格式和等級### logging.basicConfig(level=logging.INFO, encoding = "UTF-8", format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', filename = file_name, filemode='a+') if levelname == 'debug': logging.debug(content) elif levelname == 'info': logging.info(content) elif levelname == 'warning': logging.warning(content) elif levelname == 'error': logging.error(content) elif levelname == 'critical': logging.critical(content) else: show_message('輸入錯誤',"ERROR") ###將PK記錄單獨的記錄到一個VS日志中,並非report### def log_input_file(attack_name,defence_name,flag=True): ''' 將PK記錄單獨的記錄到一個VS日志 :param attack_name: 日志中的挑戰用戶 :param defence_name: 日志中的守擂用戶 :param flag: 對應挑戰是否成功,輸出的標志位 :return: 無返回,直接寫日志到相應文件 ''' if flag: info_str = '[{0}] is fail,[{1}] is success' else: info_str = '[{0}] is success,[{1}] is fail' log_info = info_str.format(attack_name,defence_name) vs_log = os.path.join(setting.LOG_PATH, "vs.log") write_file(log_info,'info',vs_log) ###將數字星期轉換為中文數字### def numtochr(num_of_weekday): """ 將數字星期轉換為中文數字 :param num_of_weekday: 星期幾的數字字符( 0,1,2,3,4,5,6) :return: 中文 星期幾 """ chrtuple = ('一', '二', '三', '四', '五', '六','日') num = int(num_of_weekday) return chrtuple[num] ###獲取漢字個數### def get_chinese_num(uchar): i = 0 for utext in uchar: if u'\u4e00' <= utext <= u'\u9fa5': i += 1 return i ###中英文混合左對齊### def myljust(str1, width, fillchar = None): ''' 中英文混合左對齊 :param str1: 欲對齊字符串 :param width: 寬度 :param fillchar: 填充字符串 :return: 新的經過左對齊處理的字符串對象 ''' if fillchar == None: fillchar = ' ' ###將中文轉化為gb2312進行計算字符長度,一般一個漢字占2個字節### length = len(str1.encode('gb2312')) fill_char_size = width - length if width >= length else 0 return "%s%s" %(str1, fillchar * fill_char_size) ###中英文混合右對齊### def myrjust(str1, width, fillchar = None): ''' 中英文混合右對齊 :param str1: 欲對齊字符串 :param width: 寬度 :param fillchar: 填充字符串 :return: 新的經過右對齊處理的字符串對象 ''' if fillchar == None: fillchar = ' ' ###將中文轉化為gb2312進行計算字符長度,一般一個漢字占2個字節### length = len(str1.encode('gb2312')) fill_char_size = width - length if width >= length else 0 return "%s%s" %(fillchar * fill_char_size, str1) ###中英文混合居中### def mycenter(str1, width, fillchar = None): ''' 中英文混合居中對齊 :param str1: 欲對齊字符串 :param width: 寬度 :param fillchar: 填充字符串 :return: 新的經過居中對齊處理的字符串對象 ''' if fillchar == None: fillchar = ' ' ###將中文轉化為gb2312進行計算字符長度,一般一個漢字占2個字節### length = len(str1.encode('gb2312')) fill_char_size = width - length if width >= length else 0 if length%2 == 0: return "%s%s%s" %(fillchar * (fill_char_size //2), str1, fillchar* (fill_char_size // 2)) else: return "%s%s%s" %(fillchar * (fill_char_size //2 + 1), str1, fillchar* (fill_char_size // 2)) ###判斷input輸入的信息是否在指定列表中的公共檢測函數### def input_msg_choose(message, limit_value=list()): """ 判斷input輸入的信息是否為空的公共檢測函數,為空繼續輸入,不為空返回輸入的信息 :param limit_value: 對輸入的值有限制,必須為limit_value的值;ex:["admin","user"] :param message: input()函數的提示信息 :return: 返回輸入的信息 """ is_null_flag = True while is_null_flag: input_value = input(message).strip().lower() if not input_value: show_message("輸入不能為空!", "ERROR") continue ###輸出q,則退出判斷循環### elif limit_value == 'q': is_null_flag = False continue elif len(limit_value) > 0: ###輸入信息不在指定列表中### if input_value not in limit_value: show_message("輸入的值不正確,請重新輸入!", "ERROR") continue else: is_null_flag = False else: pass return input_value ###判斷input輸入的信息是否為空的公共檢測函數### def input_msg(message): """ 判斷input輸入的信息是否為空的公共檢測函數,為空繼續輸入,不為空返回輸入的信息 :param message: input()函數的提示信息 :return: 返回輸入的信息 """ is_null_flag = True while is_null_flag: input_value = input(message).strip().lower() if not input_value: show_message("輸入不能為空!", "ERROR") continue else: is_null_flag = False return input_value ###對輸入的日期進行判斷是否正確### def input_date(msg, default_date): """ 對輸入的日期進行判斷是否正確 yyyy-mm-dd or yyyy-m-d :param msg:輸入提示信息 :param default_date: 默認日期 :return:返回日期 str類型 """ check_flag = False while not check_flag: strdate = input(msg).strip() if not strdate: strdate = default_date try: date_list = strdate.split("-") ###對輸入的日期以-進行分隔,並判斷是否是日期數字### result = date(int(date_list[0]), int(date_list[1]), int(date_list[2])) check_flag = True except ValueError: show_message("輸入日期不合法,請重新輸入!", "ERROR") continue return result.strftime("%Y-%m-%d") ###對列表進行冒泡排序### def list_sort_by(sort_list,num1,num2): ''' 根據name對列表進行排序 :param sort_list:要排序的列表 :param num1要排序的主列編號 :param num1要排序的次列編號 :return: 排序后的列表 ''' ###因輸出的列表內容是以多個空格分隔的字符串,故要進行字符串匹配和分隔### r = re.compile('\s+') for i in range(len(sort_list)-1): for j in range(i+1,len(sort_list)): ###對字符串進行正則表達式分隔處理,並對相應的列進行大小比對,對列表進行冒泡操作### if r.split(sort_list[i])[num1] < r.split(sort_list[j])[num1]: tmp = sort_list[i] sort_list[i] = sort_list[j] sort_list[j] = tmp ###如果排序的主列值相同,則對次列進行大小判斷,並對列表進行冒泡操作### elif r.split(sort_list[i])[num1] == r.split(sort_list[j])[num1]: if r.split(sort_list[i])[num2] < r.split(sort_list[j])[num2]: tmp = sort_list[i] sort_list[i] = sort_list[j] sort_list[j] = tmp else: pass return(sort_list)
5.4.2 報表模塊report.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 主要對報表的讀取、寫入、修改等操作 ''' import calendar import os from datetime import datetime, timedelta from datetime import date from database import dbapi from conf import menu,setting from modules import common ###將角色PK的記錄寫回到指定的報表文件### def record_input_file(attack_role,attack_name,defence_role,defence_name,flag=True): ''' 將角色PK的記錄寫回到指定的報表文件 :param attack_role: 挑戰方的角色 :param attack_name: 挑戰方的名字 :param defence_role: 守擂方的角色 :param defence_name: 守擂方的名字 :param flag: 挑戰是否成功的標志位 :return: 沒有返回值,直接回寫報表文件 ''' result = False if flag: report_str = '【{0}:{1}】挑戰失敗,【{2}:{3}】守擂成功' else: report_str = '【{0}:{1}】挑戰成功,【{2}:{3}】守擂失敗' result = True report_info = report_str.format(attack_role,attack_name,defence_role,defence_name) ###報表要記錄的內容格式### report_record = {"time": datetime.now().strftime("%Y-%m-%d %H:%M"), "attack_role": attack_role, "attack_name": attack_name, "defence_role": defence_role, "defence_name": defence_name, "attack_result": result, "detail": report_info } vs_file = os.path.join(setting.LOG_PATH, "vs_report") dbapi.append_db_json(report_record,vs_file) ###日期輸入及判斷### def get_date(): """ 用戶輸入一個時間段,如果顯示報表是要提供開始、結束日期,返回開始,結束時間 :return: 字典格式,{"start":startdate, "end": enddate} """ startdate = common.input_date("輸入查詢開始時間(yyyy-mm-dd)[default:2016-01-01]: ", "2016-01-01") enddate = common.input_date("輸入查詢結束時間(yyyy-mm-dd)[default: today]: ", datetime.now().strftime("%Y-%m-%d")) return {"start": startdate, "end": enddate} ###根據具體用戶來獲取PK的記錄### def print_vs_report(user,date_dict): """ 根據具體用戶來獲取PK的記錄 :param user: 角色用戶的名字 :param date_dict:起始和結束日期的字典 :return: 返回用戶的PK結果和記錄 """ ###獲取到起始和結束日期### startdate = date_dict["start"] enddate = date_dict["end"] ###定義PK的信息輸出的列表和字典### msglist = list() msgdict = dict() ###調用報表加載函數來獲取報表記錄### _recordlist = dbapi.load_vs_report(startdate, enddate,user) ###初始化PK記錄的初始變量### attack_sum = 0 attack_ok = 0 defence_sum = 0 defence_ok = 0 ok_sum = 0 all_sum = 0 ###對具體用戶的PK記錄,來統計挑戰、守擂和PK的成功次數和總次數### for record in _recordlist: tmpmsg = "{time} {detail}".format(time=record["time"],detail=record['detail']) msglist.append(tmpmsg) if user == record['attack_name']: if record['attack_result']: attack_ok += 1 attack_sum += 1 if user == record['defence_name']: if not record['attack_result']: defence_ok += 1 defence_sum += 1 all_sum += 1 ###總的PK成功次數### ok_sum = attack_ok + defence_ok ###定義返回字典的具體信息### msgdict = { 'user':user, 'startdate':startdate, 'enddate':enddate, 'attack_sum':attack_sum, 'attack_ok':attack_ok, 'defence_sum':defence_sum, 'defence_ok':defence_ok, 'all_sum':all_sum, 'ok_sum':ok_sum, 'vs_record':"\n".join(msglist) } return msgdict ###輸出所有用戶的PK報表信息### def print_vs_all_report(user_list,dates,num=0): """ 輸出所有用戶的PK報表信息 :param user_list: 角色用戶名字列表 :param dates 起始和結束的日期字典 :param num 指定信息的排序編號 :return: """ ###定義PK的信息輸出的列表和字典### msgdict = dict() msglist = list() ###對所有角色名字列表進行遍歷並格式化輸出信息### for user in user_list: record_dict = print_vs_report(user,dates) _user = common.mycenter(str(record_dict['user']),10) _attack_sum = common.mycenter(str(record_dict['attack_sum']),10) _attack_ok = common.mycenter(str(record_dict['attack_ok']),10) _defence_sum = common.mycenter(str(record_dict['defence_sum']),10) _defence_ok = common.mycenter(str(record_dict['defence_ok']),10) _all_sum = common.mycenter(str(record_dict['all_sum']),10) _ok_sum = common.mycenter(str(record_dict['ok_sum']),10) record_list = [_user,_attack_sum,_attack_ok,_defence_sum,_defence_ok,_all_sum,_ok_sum] record_msg = "{0}{1}{2}{3}{4}{5}{6}".format(*record_list) msglist.append(record_msg) ###根據輸入的排序編號進行相應處理### if num == 0: sorted_msglist = msglist elif num == 1: sorted_msglist = common.list_sort_by(msglist,3,2) elif num == 2: sorted_msglist = common.list_sort_by(msglist,5,4) elif num == 3: sorted_msglist = common.list_sort_by(msglist,7,6) else: pass return(sorted_msglist)
5.4.3 角色類模塊role.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 定義角色的類和三種角色的子類 ''' import os from conf import setting,menu from modules import common from database import dbapi class role(object): ''' 定義角色的根類 :param role_num 角色對應的數字編號 :return 沒有返回值 ''' ###指定角色的數據庫文件#### __database = "{0}.db".format(os.path.join(setting.DATABASE['dbpath'], setting.DATABASE["tables"]["role"])) def __init__(self,role_num): self.life = setting.init_hp ###角色的初始血量### ###定義角色初始化技能參數### self.role = '' self.init_skill = '' self.init_skill_flag = 0 self.init_chance_rate = '' self.init_harm_rate = '' self.dict_role_list = {} self.role_num = role_num self.db_load() ###調用執行角色數據庫文件的讀取和賦值### self.skill_init() ###角色初始技能的賦值### ###調用執行角色數據庫文件的讀取,並賦值給dict_role_list### def db_load(self): self.dict_role_list = dbapi.load_data_from_db(self.__database) ###角色初始技能的賦值### def skill_init(self): self.dict_role = self.dict_role_list[self.role_num] self.role = self.dict_role["role"] self.init_skill = self.dict_role["init_skill"] self.init_chance_rate = self.dict_role["chance_rate"] self.init_harm_rate = self.dict_role["harm_rate"] ###根據輸入的初始技能開關進行賦值### def init_skill_choose(self,flag): if flag == "y": self.init_skill_flag = self.dict_role["init_skill_flag"] return True else: return False ###定義戰士角色的子類### class zhanshi(role): ''' 定義戰士角色的類,繼承role類 ''' def __init__(self,role_num): super(zhanshi,self).__init__(role_num) ###戰士子類的角色介紹函數### def role_instruction(self): self.mess = ''' 戰士介紹: 出身於鄉村,依靠出色的才能,光靠一把武器從事佣兵生活的少年。 性格直率,充滿正義感,像孩子一樣,從來不會掩飾自己的感受。 容易相信別人,雖然偶爾會因此受傷,但很快就會克服傷痛,重新站起來。 是堅韌不拔的熱血英雄。 戰士具有強大的近戰攻擊力,一直活躍在戰斗的最前方。 強大的力量和充沛的體力讓他可以摧毀敵人的一切防御。 初始技能: 【%s】:%s%% 機率減少傷害 %s%% ''' % (self.init_skill,self.init_chance_rate,self.init_harm_rate) common.show_message(self.mess, "INFORMATION") ###定義弓箭手角色的子類### class gongjianshou(role): ''' 定義弓箭手角色的類,繼承role類 ''' def __init__(self,role_num): super(gongjianshou,self).__init__(role_num) ###弓箭手子類的角色介紹函數### def role_instruction(self): self.mess = ''' 弓箭手介紹: 雖然身在外地,但一直固守着自己特有的文化,是天生的弓箭手。 原來是謹慎、善良的和平主義者,為了對抗破壞自然的龍而站出來戰斗,是出色的戰士。 弓箭手擅長使用弓箭,在后方進行遠距離攻擊。 憑借快速的移動和多樣的遠程攻擊,使敵人根本無法靠近自己。 初始技能: 【%s】:%s%% 機率減少傷害 %s%% ''' % (self.init_skill,self.init_chance_rate,self.init_harm_rate) common.show_message(self.mess, "INFORMATION") ###定義法師角色的子類### class fashi(role): ''' 定義法師角色的類,繼承role類 ''' def __init__(self,role_num): super(fashi,self).__init__(role_num) ###法師子類的角色介紹函數### def role_instruction(self): self.mess = ''' 法師介紹: 擁有卓越的魔法才能,從小就離開了父母,加入魔法師團的天才少女。 對自己的才能充滿自信,並對未來充滿希望,因此眼光很高。 自尊心很強,甚至有點過於自信。對認可自己能力的人,表現出很強的依賴心。 潑辣的語言,會讓人對她的性格產生誤解。其實她也有善良、溫柔、可愛的一面。 魔法師擁有可以同時攻擊多個敵人的強力魔法,但防御力較低。 一旦被敵人包圍,很容易陷入危險之中。 初始技能: 【%s】:%s%% 機率減少傷害 %s%% ''' % (self.init_skill,self.init_chance_rate,self.init_harm_rate) common.show_message(self.mess, "INFORMATION")
5.4.4 技能類模塊skill.py
#_*_ coding=utf-8 _*_ ''' Created on 2016年3月15日 @author: 王凱 定義角色的技能類 ''' import os from conf import setting,menu from modules import common from database import dbapi ###技能的根類### class skill(object): ''' 定義技能的類 ''' ###指定角色技能的數據庫文件#### __database = "{0}.db".format(os.path.join(setting.DATABASE['dbpath'],setting.DATABASE["tables"]["skill"])) def __init__(self,role_num): self.life = setting.init_hp ###角色的初始血量### ###定義技能值初始化參數### self.id = '' self.level = '' self.skill = '' self.init_harm = '' self.chance_rate = '' self.harm_rate = '' self.dict_skill_list = {} self.role_num = role_num self.db_load() ###調用執行技能數據庫文件的讀取和賦值### self.dict_skill = self.dict_skill_list[self.role_num] self.role = self.dict_skill["role"] self.skill_list = self.dict_skill["skill"] ###調用執行技能數據庫文件的讀取和賦值### def db_load(self): self.dict_skill_list = dbapi.load_data_from_db(self.__database) ###輸出角色技能列表### def print_skill_list(self): """ 將角色技能列表中的輸出到屏幕 :return: 輸出到屏幕 """ print("|{0}|{1}|{2}|".format('技能編號'.center(8), '技能名稱'.center(18),'技能描述'.center(40))) print('%s' % '-' * 85) for skill_info in self.skill_list: sk_name = '{0}:{1}'.format(skill_info['level'],skill_info['name']) sk_name_chinese_num = common.get_chinese_num(sk_name) sk_name_len_num = len(sk_name) sk_name_space_str = (20 - sk_name_len_num - sk_name_chinese_num) * " " sk_desc = '基礎攻擊:{0} {1}%機率產生暴擊傷害,為基礎傷害的{2}%'.format(skill_info['init_harm'],skill_info['chance_rate'],skill_info['harm_rate']) sk_desc_chinese_num = common.get_chinese_num(sk_name) sk_desc_len_num = len(sk_name) sk_desc_space_str = (70 - sk_name_len_num - sk_name_chinese_num) * " " print('| %-10s | %s |%s|' % (skill_info['id'], sk_name + sk_name_space_str,sk_desc + sk_desc_space_str)) print('%s' % '-' * 85,"\n") ###獲取技能的編號列表### def skill_id_list(self): """ 獲取技能編號,並追加到技能列表,在對戰中進行攻擊,最后返回技能編號列表 :return: 技能列表 """ _skill_list = [] _skill_tuple = self.dict_skill["skill"] # 開始遍歷,並生成技能編號列表 for _skill in _skill_tuple: _skill_list.append(_skill['id']) return _skill_list ###角色PK中,技能的傷害計算### def skill_harm(self,skill_id,attack,defence): """ 根據輸入的技能編號,在對戰中進行攻擊,輸入相應信息,並進行傷害和血量的計算 :param skill_id 技能的編號 :param attack 挑戰方的參數字典 :param defence 守擂方的參數字典 :return 返回對戰雙方的血量 """ ###技能元組的賦值### _skill_tuple = self.dict_skill["skill"] attack_harm = 0 ###開始遍歷,並判斷賦值### for _skill in _skill_tuple: ###技能匹配成功,並進行參數賦值### if _skill['id'] == skill_id: skill_name = _skill['name'] skill_init_harm = _skill['init_harm'] skill_chance_rate = _skill['chance_rate'] skill_harm_rate = _skill['harm_rate'] ###調用隨機數的生成和對比函數,來判斷技能暴擊屬性是否觸發### attack_skill_trigger = common.random_decide(100,skill_chance_rate,'lt') ###PK信息輸出的變量初始化### mess_attack_init = '進攻方【{0}({1})】發動技能【{2}】,'.format(attack['name'],attack['role'],skill_name) mess_attack_trigger = '【{0}({1})】發動技能【{2}】並觸發屬性【暴擊】,'.format(attack['name'],attack['role'],skill_name) mess_attack_harm = '造成傷害【{0}】,' mess_defence_init = '防守方【{0}({1})】'.format(defence['name'],defence['role']) mess_defence_trigger = '防守方【{0}({1})】觸發初始技能【{2}】,'.format(defence['name'],defence['role'],defence['init_skill']) mess_defence_life = '剩余血量【{0}】' mess_attack_info = mess_attack_init mess_defence_info = mess_defence_init ###守擂方的初始技能是否開啟### if defence['init_skill_flag'] == 1: ###調用隨機數的生成和對比函數,來判斷防守方的初始屬性是否觸發### defence_skill_trigger = common.random_decide(100,defence['init_chance_rate'],'lt') ###挑戰和防守雙方的技能均觸發成功,計算傷害值### if defence_skill_trigger and attack_skill_trigger: attack_harm = (skill_init_harm * (100 + skill_harm_rate) /100) * (100 - defence['init_harm_rate']) / 100 mess_attack_info = mess_attack_trigger mess_defence_info = mess_defence_trigger ###挑戰方攻擊技能暴擊屬性觸發成功,計算傷害值### elif attack_skill_trigger: attack_harm = skill_init_harm * (100 + skill_harm_rate) /100 mess_attack_info = mess_attack_trigger ###防守方的技能觸發成功,計算傷害值### elif defence_skill_trigger: attack_harm = skill_init_harm * (100 - defence['init_harm_rate']) / 100 mess_defence_info = mess_defence_trigger ###雙方均未觸發成功,計算傷害值### else: attack_harm = skill_init_harm else: ###挑戰方攻擊技能暴擊屬性觸發成功,計算傷害值### if attack_skill_trigger: attack_harm = skill_init_harm * (100 + skill_harm_rate) /100 mess_attack_info = mess_attack_trigger ###雙方均未觸發成功,計算傷害值### else: attack_harm = skill_init_harm ###計算守擂方的剩余血量### defence['life'] -= attack_harm defence['life'] = int(defence['life']) message = mess_attack_info + mess_attack_harm.format(attack_harm) + mess_defence_info + mess_defence_life.format(defence['life']) common.show_message(message,"INFORMATION") ###返回雙方的剩余血量### return(attack['life'],defence['life'])
5.5 日志報表目錄log:
5.5.1 錯誤日志game.log
2016-03-18 23:28:44 PM ERROR init table role failed,no function init_db_role found 2016-03-18 23:29:23 PM ERROR init table role failed,no function init_db_role found 2016-03-18 23:29:32 PM ERROR init table role failed,no function init_db_role found 2016-03-18 23:29:44 PM ERROR init table role failed,no function init_db_role found 2016-03-18 23:31:19 PM ERROR init table role failed,no function init_db_role found 2016-03-20 20:33:36 PM ERROR init table skill failed,no function init_db_skill found 2016-03-20 23:47:45 PM CRITICAL dbapi > load_vs_report > 'defence_name_name' 2016-03-20 23:52:19 PM CRITICAL dbapi > load_vs_report > 'defence_name_name' 2016-03-20 23:52:33 PM CRITICAL dbapi > load_vs_report > 'defence_name_name'
5.5.2 對戰日志vs.log
2016-03-20 22:40:48 PM INFO [za] is fail,[ga] is success 2016-03-20 22:42:07 PM INFO [fb] is fail,[fa] is success 2016-03-20 22:43:14 PM INFO [za] is success,[fb] is fail 2016-03-20 23:33:52 PM INFO [za] is fail,[zb] is success 2016-03-21 00:02:09 AM INFO [gb] is success,[za] is fail 2016-03-21 00:05:33 AM INFO [fb] is success,[fa] is fail 2016-03-22 22:47:32 PM INFO [zb] is success,[ga] is fail 2016-03-22 22:48:20 PM INFO [fa] is success,[fb] is fail 2016-03-26 12:22:40 PM INFO [za] is fail,[fb] is success 2016-03-26 20:47:11 PM INFO [gb] is success,[fa] is fail 2016-03-26 20:47:50 PM INFO [gb] is fail,[za] is success 2016-03-26 21:02:20 PM INFO [zb] is success,[fa] is fail 2016-03-26 21:02:59 PM INFO [zb] is success,[ga] is fail 2016-03-26 21:04:01 PM INFO [fb] is success,[ga] is fail 2016-03-26 22:35:46 PM INFO [gb] is fail,[fa] is success 2016-03-27 01:50:00 AM INFO [zb] is fail,[fa] is success 2016-03-27 01:51:07 AM INFO [ga] is success,[fa] is fail 2016-03-27 16:17:58 PM INFO [za] is success,[fa] is fail
5.5.3 對戰報表vs_report
{"defence_name": "ga", "attack_result": false, "attack_name": "za", "time": "2016-03-20 22:40", "attack_role": "\u6218\u58eb", "defence_role": "\u5f13\u7bad\u624b", "detail": "\u3010\u6218\u58eb\uff1aza\u3011\u6311\u6218\u5931\u8d25,\u3010\u5f13\u7bad\u624b\uff1aga\u3011\u5b88\u64c2\u6210\u529f"}
{"defence_name": "fa", "attack_result": false, "attack_name": "fb", "time": "2016-03-20 22:42", "attack_role": "\u6cd5\u5e08", "defence_role": "\u6cd5\u5e08", "detail": "\u3010\u6cd5\u5e08\uff1afb\u3011\u6311\u6218\u5931\u8d25,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u6210\u529f"}
{"defence_name": "fb", "attack_result": true, "attack_name": "za", "time": "2016-03-20 22:43", "attack_role": "\u6218\u58eb", "defence_role": "\u6cd5\u5e08", "detail": "\u3010\u6218\u58eb\uff1aza\u3011\u6311\u6218\u6210\u529f,\u3010\u6cd5\u5e08\uff1afb\u3011\u5b88\u64c2\u5931\u8d25"}
{"defence_role": "\u6218\u58eb", "time": "2016-03-20 23:33", "attack_result": false, "attack_role": "\u6218\u58eb", "defence_name": "zb", "attack_name": "za", "detail": "\u3010\u6218\u58eb\uff1aza\u3011\u6311\u6218\u5931\u8d25,\u3010\u6218\u58eb\uff1azb\u3011\u5b88\u64c2\u6210\u529f"}
{"attack_result": true, "detail": "\u3010\u5f13\u7bad\u624b\uff1agb\u3011\u6311\u6218\u6210\u529f,\u3010\u6218\u58eb\uff1aza\u3011\u5b88\u64c2\u5931\u8d25", "attack_role": "\u5f13\u7bad\u624b", "attack_name": "gb", "defence_name": "za", "defence_role": "\u6218\u58eb", "time": "2016-03-21 00:02"}
{"defence_role": "\u6cd5\u5e08", "time": "2016-03-21 00:05", "attack_result": true, "attack_name": "fb", "attack_role": "\u6cd5\u5e08", "detail": "\u3010\u6cd5\u5e08\uff1afb\u3011\u6311\u6218\u6210\u529f,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u5931\u8d25", "defence_name": "fa"}
{"time": "2016-03-22 22:47", "detail": "\u3010\u6218\u58eb\uff1azb\u3011\u6311\u6218\u6210\u529f,\u3010\u5f13\u7bad\u624b\uff1aga\u3011\u5b88\u64c2\u5931\u8d25", "defence_name": "ga", "attack_result": true, "defence_role": "\u5f13\u7bad\u624b", "attack_role": "\u6218\u58eb", "attack_name": "zb"}
{"time": "2016-03-22 22:48", "detail": "\u3010\u6cd5\u5e08\uff1afa\u3011\u6311\u6218\u6210\u529f,\u3010\u6cd5\u5e08\uff1afb\u3011\u5b88\u64c2\u5931\u8d25", "defence_name": "fb", "attack_result": true, "defence_role": "\u6cd5\u5e08", "attack_role": "\u6cd5\u5e08", "attack_name": "fa"}
{"time": "2016-03-26 12:22", "defence_role": "\u6cd5\u5e08", "detail": "\u3010\u6218\u58eb\uff1aza\u3011\u6311\u6218\u5931\u8d25,\u3010\u6cd5\u5e08\uff1afb\u3011\u5b88\u64c2\u6210\u529f", "attack_name": "za", "attack_role": "\u6218\u58eb", "defence_name": "fb", "attack_result": false}
{"attack_role": "\u5f13\u7bad\u624b", "attack_name": "gb", "defence_name": "fa", "attack_result": true, "time": "2016-03-26 20:47", "defence_role": "\u6cd5\u5e08", "detail": "\u3010\u5f13\u7bad\u624b\uff1agb\u3011\u6311\u6218\u6210\u529f,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u5931\u8d25"}
{"attack_role": "\u5f13\u7bad\u624b", "attack_name": "gb", "defence_name": "za", "attack_result": false, "time": "2016-03-26 20:47", "defence_role": "\u6218\u58eb", "detail": "\u3010\u5f13\u7bad\u624b\uff1agb\u3011\u6311\u6218\u5931\u8d25,\u3010\u6218\u58eb\uff1aza\u3011\u5b88\u64c2\u6210\u529f"}
{"attack_name": "zb", "defence_name": "fa", "detail": "\u3010\u6218\u58eb\uff1azb\u3011\u6311\u6218\u6210\u529f,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u5931\u8d25", "attack_result": true, "attack_role": "\u6218\u58eb", "defence_role": "\u6cd5\u5e08", "time": "2016-03-26 21:02"}
{"attack_name": "zb", "defence_name": "ga", "detail": "\u3010\u6218\u58eb\uff1azb\u3011\u6311\u6218\u6210\u529f,\u3010\u5f13\u7bad\u624b\uff1aga\u3011\u5b88\u64c2\u5931\u8d25", "attack_result": true, "attack_role": "\u6218\u58eb", "defence_role": "\u5f13\u7bad\u624b", "time": "2016-03-26 21:02"}
{"attack_name": "fb", "defence_name": "ga", "detail": "\u3010\u6cd5\u5e08\uff1afb\u3011\u6311\u6218\u6210\u529f,\u3010\u5f13\u7bad\u624b\uff1aga\u3011\u5b88\u64c2\u5931\u8d25", "attack_result": true, "attack_role": "\u6cd5\u5e08", "defence_role": "\u5f13\u7bad\u624b", "time": "2016-03-26 21:04"}
{"attack_role": "\u5f13\u7bad\u624b", "defence_name": "fa", "attack_result": false, "detail": "\u3010\u5f13\u7bad\u624b\uff1agb\u3011\u6311\u6218\u5931\u8d25,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u6210\u529f", "defence_role": "\u6cd5\u5e08", "time": "2016-03-26 22:35", "attack_name": "gb"}
{"defence_role": "\u6cd5\u5e08", "attack_name": "zb", "attack_result": false, "detail": "\u3010\u6218\u58eb\uff1azb\u3011\u6311\u6218\u5931\u8d25,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u6210\u529f", "time": "2016-03-27 01:50", "defence_name": "fa", "attack_role": "\u6218\u58eb"}
{"defence_role": "\u6cd5\u5e08", "attack_name": "ga", "attack_result": true, "detail": "\u3010\u5f13\u7bad\u624b\uff1aga\u3011\u6311\u6218\u6210\u529f,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u5931\u8d25", "time": "2016-03-27 01:51", "defence_name": "fa", "attack_role": "\u5f13\u7bad\u624b"}
{"defence_role": "\u6cd5\u5e08", "attack_role": "\u6218\u58eb", "defence_name": "fa", "detail": "\u3010\u6218\u58eb\uff1aza\u3011\u6311\u6218\u6210\u529f,\u3010\u6cd5\u5e08\uff1afa\u3011\u5b88\u64c2\u5931\u8d25", "time": "2016-03-27 16:17", "attack_result": true, "attack_name": "za"}
6.程序部分功能模塊截圖展示:
6.1 主菜單:

6.2 輸入1,進入角色介紹菜單,並查看戰士的介紹:


6.3 返回主菜單,輸入2,進入PK場:
說明:
每個角色有二個用戶,挑戰和應戰方不能同時選擇同一種角色下的同一用戶,例當挑戰方選擇了戰士的za時,應戰方如果選擇戰士角色,則只有zb可以選擇。
首先輸入挑戰方的角色、名字以及是否開啟初始技能

其次輸入應戰方的角色、名字以及是否開啟初始技能

6.4對戰開始,可以選擇自動戰斗,也可以手動戰斗
說明:
自動戰斗即在技能范圍內隨機生成一個數;而手動戰斗是手工輸入技能的編號
初始技能和暴擊屬性的觸發,也是根據隨機生成數和機率進行比較,從而對傷害進行增加或減少。
因挑戰方先發起攻擊,必然在PK有多出一招的優勢,故為了平衡,在防守方的初始血量多加了100
挑戰方1000血量,應戰方1100血量

每一回合來計算對戰雙方的血量,如果血量小於0,則結束對戰

6.5 返回主菜單,輸入3,查看戰績榜:
首先輸入查詢的開始和結束時間

說明:正常輸出PK戰績結果,默認是以角色用戶來排序,可以根據其他三種方式進行排序,正常有主排序和次排序字段
輸入1,則以挑戰成功數為主排序字段,以挑戰次數為次排序字段

輸入2,則以守擂成功數為主排序字段,以守擂次數為次排序字段

輸入3,則以PK成功數為主排序字段,以PK總次數為次排序字段

6.6 輸入0,進行具體用戶查詢環節,並可以查看具體的PK記錄信息:

6.7 最后,返回主菜單,輸入0,退出程序,結束:

