python之在线PK游戏(第六天)
本节作业:
熟练使用类和模块,写一个交互性强、有冲突的程序。
故本次写了一个文字回合制的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,退出程序,结束: