python之在线PK游戏(第六天)

时间:2023-03-10 04:17:26
python之在线PK游戏(第六天)

 

本节作业:

熟练使用类和模块,写一个交互性强、有冲突的程序。

故本次写了一个文字回合制的PK游戏,系统主程序为根目录下的:game_menu.py

1. 系统功能模块:

第六天的作业:文字游戏程序是在python3.4环境下开发,在python2.7环境下大同小异,主要功能模块如下图:

python之在线PK游戏(第六天)

2. 系统目录结构:

程序采用分层的方式编写,包括系统配置conf、数据库访问层database、业务逻辑层modules,业务处理主程序game_menu.py,主要分类如下图:

python之在线PK游戏(第六天)

3.应用知识点:

a) 类的使用

b) 文件的读写操作

c) 系统模块、自定义模块的操作

d) 日志模块的使用

4.程序流程图如下:

python之在线PK游戏(第六天)

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]: ", ["", "", "","b"]).strip()
if role_choose == '':
roleadj = role.zhanshi(role_choose)
elif role_choose == '':
roleadj = role.gongjianshou(role_choose)
elif role_choose == '':
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]: ", ["", "", "","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]: ", ["", "", "","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 = { "" : ['za','zb'],
"" : ['ga','gb'],
"" : ['fa','fb']
} ###显示游戏的主菜单界面,分别有角色,PK场,战绩榜###
print(menu.main_menu.format(today, common.numtochr(weekoftoday)))
choose = common.input_msg_choose("选择功能编号[0-3]: ", ["", "", "", ""]).strip() ###0、退出游戏###
if choose == "":
flag = True
continue ###1、角色及技能介绍###
if choose == "":
role_skill_show() ###调用角色信息显示函数### ###2、PK场###
if choose == "":
battlefield(_role_list) ###调用PK场函数### ###3、战绩榜###
if choose == "": ###定义初始的用户列表和用户选择菜单###
_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]:", ["","","",""]).strip()
###选择0时,结束排序,进行用户查询环节###
if sort_input != "":
###根据输入的排序编号进行具体排序###
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")

game_menu

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

setting

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}
'''

menu

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 = {
"": {"role": "战士", "init_skill":"守护","init_skill_flag":1,"chance_rate" : 50 , "harm_rate" : 20},
"": {"role": "弓箭手", "init_skill":"闪避","init_skill_flag":1,"chance_rate" : 40 , "harm_rate" : 25},
"": {"role": "法师", "init_skill":"法盾","init_skill_flag":1,"chance_rate" : 30 , "harm_rate" : 40},
} ###角色的技能列表###
role_skill_list = {
"": {"role": "战士", "skill": (
{"id": "", "level": "初级技能", "name": "野蛮冲锋","init_harm": 100, "chance_rate" : 40 , "harm_rate" : 20},
{"id": "", "level": "中级技能", "name": "旋风斩", "init_harm": 150, "chance_rate" : 30 , "harm_rate" : 20},
{"id": "", "level": "高级技能", "name": "百刃斩" ,"init_harm": 200, "chance_rate" : 20 , "harm_rate" : 20},
)},
"": {"role": "弓箭手", "skill": (
{"id": "", "level": "初级技能", "name": "点射","init_harm": 100, "chance_rate" : 40 , "harm_rate" : 20},
{"id": "", "level": "中级技能", "name": "连射", "init_harm": 150, "chance_rate" : 30 , "harm_rate" : 20},
{"id": "", "level": "高级技能", "name": "爆裂箭" ,"init_harm": 200, "chance_rate" : 20 , "harm_rate" : 10},
)},
"": {"role": "法师", "skill": (
{"id": "", "level": "初级技能", "name": "火球术","init_harm": 100, "chance_rate" : 40 , "harm_rate" : 20},
{"id": "", "level": "中级技能", "name": "冰咆哮", "init_harm": 150, "chance_rate" : 30 , "harm_rate" : 20},
{"id": "", "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()

db_init

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")

dbapi

5.3.3 数据文件role.db

{"": {"init_skill": "\u6cd5\u76fe", "harm_rate": 40, "chance_rate": 30, "init_skill_flag": 1, "role": "\u6cd5\u5e08"}, "": {"init_skill": "\u5b88\u62a4", "harm_rate": 20, "chance_rate": 50, "init_skill_flag": 1, "role": "\u6218\u58eb"}, "": {"init_skill": "\u95ea\u907f", "harm_rate": 25, "chance_rate": 40, "init_skill_flag": 1, "role": "\u5f13\u7bad\u624b"}}

role.db

5.3.4 数据文件skill.db

{"": {"skill": [{"level": "\u521d\u7ea7\u6280\u80fd", "chance_rate": 40, "id": "", "name": "\u706b\u7403\u672f", "init_harm": 100, "harm_rate": 20}, {"level": "\u4e2d\u7ea7\u6280\u80fd", "chance_rate": 30, "id": "", "name": "\u51b0\u5486\u54ee", "init_harm": 150, "harm_rate": 20}, {"level": "\u9ad8\u7ea7\u6280\u80fd", "chance_rate": 20, "id": "", "name": "\u5730\u72f1\u96f7\u5149", "init_harm": 200, "harm_rate": 20}], "role": "\u6cd5\u5e08"}, "": {"skill": [{"level": "\u521d\u7ea7\u6280\u80fd", "chance_rate": 40, "id": "", "name": "\u91ce\u86ee\u51b2\u950b", "init_harm": 100, "harm_rate": 20}, {"level": "\u4e2d\u7ea7\u6280\u80fd", "chance_rate": 30, "id": "", "name": "\u65cb\u98ce\u65a9", "init_harm": 150, "harm_rate": 20}, {"level": "\u9ad8\u7ea7\u6280\u80fd", "chance_rate": 20, "id": "", "name": "\u767e\u5203\u65a9", "init_harm": 200, "harm_rate": 20}], "role": "\u6218\u58eb"}, "": {"skill": [{"level": "\u521d\u7ea7\u6280\u80fd", "chance_rate": 40, "id": "", "name": "\u70b9\u5c04", "init_harm": 100, "harm_rate": 20}, {"level": "\u4e2d\u7ea7\u6280\u80fd", "chance_rate": 30, "id": "", "name": "\u8fde\u5c04", "init_harm": 150, "harm_rate": 20}, {"level": "\u9ad8\u7ea7\u6280\u80fd", "chance_rate": 20, "id": "", "name": "\u7206\u88c2\u7bad", "init_harm": 200, "harm_rate": 10}], "role": "\u5f13\u7bad\u624b"}}

skill.db

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)

common

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)

report

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")

role类

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'])

skill类

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'

game.log

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

vs.log

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"}

vs_report

6.程序部分功能模块截图展示:

6.1 主菜单:

python之在线PK游戏(第六天)

6.2 输入1,进入角色介绍菜单,并查看战士的介绍:

python之在线PK游戏(第六天)

python之在线PK游戏(第六天)

6.3 返回主菜单,输入2,进入PK场:

说明:

每个角色有二个用户,挑战和应战方不能同时选择同一种角色下的同一用户,例当挑战方选择了战士的za时,应战方如果选择战士角色,则只有zb可以选择。

首先输入挑战方的角色、名字以及是否开启初始技能

python之在线PK游戏(第六天)

其次输入应战方的角色、名字以及是否开启初始技能

python之在线PK游戏(第六天)

6.4对战开始,可以选择自动战斗,也可以手动战斗

说明:

自动战斗即在技能范围内随机生成一个数;而手动战斗是手工输入技能的编号

初始技能和暴击属性的触发,也是根据随机生成数和机率进行比较,从而对伤害进行增加或减少。

因挑战方先发起攻击,必然在PK有多出一招的优势,故为了平衡,在防守方的初始血量多加了100

挑战方1000血量,应战方1100血量

python之在线PK游戏(第六天)

每一回合来计算对战双方的血量,如果血量小于0,则结束对战

python之在线PK游戏(第六天)

6.5 返回主菜单,输入3,查看战绩榜:

首先输入查询的开始和结束时间

python之在线PK游戏(第六天)

说明:正常输出PK战绩结果,默认是以角色用户来排序,可以根据其他三种方式进行排序,正常有主排序和次排序字段

输入1,则以挑战成功数为主排序字段,以挑战次数为次排序字段

python之在线PK游戏(第六天)

输入2,则以守擂成功数为主排序字段,以守擂次数为次排序字段

python之在线PK游戏(第六天)

输入3,则以PK成功数为主排序字段,以PK总次数为次排序字段

python之在线PK游戏(第六天)

6.6 输入0,进行具体用户查询环节,并可以查看具体的PK记录信息:

python之在线PK游戏(第六天)

6.7 最后,返回主菜单,输入0,退出程序,结束:

python之在线PK游戏(第六天)