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':" ".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