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