Bootstrap

基于python设计的文字对战游戏(二、完善记录)

基于python设计的文字对战游戏(完善记录)

自己看的

上一篇文章主要记录了学习python类与对象时的应用,但是最终运行起来太麻烦了而且还有很多功能没有能够成功搭建,因此这篇文章主要记录一下自己对旧代码的完善。
目标:
请添加图片描述

1.重新修正精灵定义部分:

这次把精灵的基础属性直接定义到精灵主体当中,要不每次都得通过函数给精灵属性,同时函数生成的属性没有办法直接地调用到战斗功能当中去。
遇到的问题:我设计的精灵主体部分包含"火\土属性"功能,但是生命攻击等值又受"火\土属性"的影响,解决这部分浪费了时间
首先在定义处加上了combat_attribute

def __init__(self,name=None,skill=None,attribute=None,combat_attribute=None)

**添加功能:**当赋予精灵火属性后给定一些基础数值,通过修改add_attribute函数,通过检测不同的输入,从而调用不同的函数,进一步得到不同的属性:

    def add_attribute(self):   
        self.attribute = input('请在火、水、土中选择生成属性:')
        if self.attribute == '火':
            self.combat_attribute = self.fire_combat_attribute()
        elif self.attribute == '水':
            self.combat_attribute = self.water_combat_attribute()
        elif self.attribute == '土':
            self.combat_attribute = self.land_combat_attribute()
    def fire_combat_attribute(self):
        Value_life = self.Value_life - random.randint(10,30)
        Value_attack = self.Value_attack + random.randint(5, 10)
        Value_defense = self.Value_defense - random.randint(2, 3)
        Value_speed = self.Value_speed + random.randint(2, 4)
        return {'value_life': Value_life, 'value_attack': Value_attack, 'value_defense': Value_defense, 'value_speed': Value_speed}

2.修改精灵对战部分

==在这部分判定技能方面浪费了时间:==因为要判定技能影响了什么属性以及技能数值,对比好长时间发现还是re字符串是最方便的如下:

text = random.choice(list(Spirit1.skill.values()))
match = re.search(r'(增加|加|增|提升|生|恢复|提高)(\D+)?(\d+).*(..)$', text)
                if match.group(4) == '攻击':
                    pass
                elif match.group(4) == '防御':
                    pass
                elif match.group(4) == '生命':
                   	pass

首先取得精灵技能中一个随机技能的说明,然后通过re将自己需要的值提取到group中,然后再进行调用,在这里能力有限,只能保证技能描述最后是’攻击’、‘防御’、'生命’才可以,否则没办法进行下一步,之能限定输入了。接下来就是将他们放入到对战代码中:

ef Spirit_vs(Spirit1,Spirit2): #这里输入的两个就是精灵主体
    #{'value_life': Value_life, 'value_attack': Value_attack, 'value_defense': Value_defense, 'value_speed': Value_speed}
    count = 0 #回合数
    turn = 0 #
    life_1 = Spirit1.combat_attribute['value_life']
    attack_1 = Spirit1.combat_attribute['value_attack']
    defense_1 = Spirit1.combat_attribute['value_defense']
    speed_1 = Spirit1.combat_attribute['value_speed']
    life_2 = Spirit2.combat_attribute['value_life']
    attack_2 = Spirit2.combat_attribute['value_attack']
    defense_2 = Spirit2.combat_attribute['value_defense']
    speed_2 = Spirit2.combat_attribute['value_speed']
    while life_1 > 0 and life_2 > 0 : #第一个元素为生命,当生命<=0时便会退出循环
        count += 1 #查看回合数
        if speed_1 > speed_2 : #速度判断谁先出手 这里是1先出手
            text = random.choice(list(Spirit1.skill.values()))
            pattern = re.search(r'(..)$')
            if pattern == "伤害" :
                number_damage_1 = int(re.search(r'\d+', text).group())
            else :
                match = re.search(r'(增加|加|增|提升|生|恢复|提高)(\D+)?(\d+).*(..)$', text)
                if match.group(4) == '攻击':
                    attack_1 += match.group(3)
                elif match.group(4) == '防御':
                    defense_1 += match.group(3)
                elif match.group(4) == '生命':
                    life_1 += match.group(3)
            life_2 -= attack_1 - defense_2 + number_damage_1
            if life_2 <= 0 :
                break
            text = random.choice(list(Spirit2.skill.values()))
            pattern = re.search(r'(..)$')
            if pattern == "伤害":
                number_damage_2 = int(re.search(r'\d+', text).group())
            else:
                match = re.search(r'(增加|加|增|提升|生|恢复|提高)(\D+)?(\d+).*(..)$', text)
                if match.group(4) == '攻击':
                    attack_2 += match.group(3)
                elif match.group(4) == '防御':
                    defense_2 += match.group(3)
                elif match.group(4) == '生命':
                    life_2 += match.group(3)
            life_1 -= attack_2 - defense_1 + number_damage_2

在这里考虑到只需要输入精灵就可以战斗因此只做了两个类作为输入,但不方便的是不能直接调用Spirit1.combat_attribute[‘value_life’]这些属性,因为如果战斗中这些数值发生了变化,会影响战斗完之后精灵的属性,因此在一开始进行了一个赋值过程,将值给到life_1等变量,上面的代码是在精灵1先出手的代码。2的代码几乎一样全是重复的,也没想到好方法进行优化因此先这样用着。第一次写的有很多错误完整能运行的在末尾

3.创建保存与读取文件部分

精灵定义与对战功能调试没问题了,接下来就是设计输入与输出,这部分想的是把已经编辑过的精灵名字和技能储存在文件当中,每次运行程序的时候都能看一下,同时可以直接选择编辑过的精灵,然后只要赋予他们一个属性就可以战斗了,首先是要创建一个这个文件在这里我将新建的精灵名字和技能全部储存在txt中,并且可以分行保存,同时给他们加上一个序号让我们可以再选择精灵时可以直接选择:

def create_spirit(): #创建新精灵函数
    if not os.path.exists('save_spirit.txt'): #检测储存文件是否存在
        with open('save_spirit.txt','w') as f:
            pass
    with open('save_spirit.txt','r',encoding='utf-8') as file_row:
        row_content = file_row.readlines()
        row = len(row_content) #读取已经存在多少行文本
    with open('save_spirit.txt', 'a', encoding='utf-8') as f:
        target = Spirit()
        target.add_name()
        target.add_skill()
        f.write('{}.'.format(row))
        f.write(json.dumps(target.name, ensure_ascii=False))  # 设置ensure_ascii属性否则默认输出编码格式的字符
        f.write(',')
        f.write(json.dumps(target.skill, ensure_ascii=False))
        f.write(';')
        f.write('\r')  # windows中txt文本默认换行是\r 也可以使用os.linesep来进行换行

之后在创建一个读取的功能,能够通过读取txt返回一个精灵:

def choose_spirit(a): #通过读取序号返回对应的精灵类
    with open('save_spirit.txt','r',encoding='utf-8') as f:
        content = f.read().split(';')
        for i in content:
            if a in i[:2]:
                print(i)
                data_1 = i.split(',')
                name_1 = data_1[0].strip('"')#移除多余的字符
                data_2 = name_1.split('.')#将前面的序号去掉
                name_2 = data_2[1].strip('"')
                skill = eval(data_1[1].strip()) #这部分只适用于储存一个技能技能在2或以上咋办?
                spirit = Spirit(name_2,skill)
                return spirit

在这部分出了个大问题: 我在调试的时候只是用Spirit创建的精灵,他们只有一个技能,因此一开始没发现问题,当我用VIP_Spirit进行创建的时候精灵有两个技能,就没有办法利用上述代码进行拆分了,因此想了一下能不能创建类似json文件的格式,这样容易创建和读取。
解决方法1: 在网上找了找发现直接利用列表合并然后利用eval创建为字典就可以了。

i = '0."小鱼人",{"跳跃": "造成50点伤害", "汲水": "恢复自身100点生命"}'
data_1 = i.split(',')
data_2 = ','.join(data_1[1:])
print(type(data_2))
my_dict = eval(data_2)
print(type(my_dict))

4.主界面输入输出部分

这部分我就做的有点蠢了,全是一步一步的因为没想到怎样嵌套函数进行优化,这里就不放了因为没有意义,将他们与其他代码直接放到最后了。

5.日志部分

在程序运行没有错误之后输出实在是太单调了,不符合我这种回合制玩家的心理,想着得加一个日志,起码让我知道战斗实在进行的,因此又去修改日志函数,只要简单地在战斗过程中将这些输入加进去就可以解决了:

print(f"{Spirit1.name} used {skill1_random}:{text} ")
print(f"{Spirit2.name} used {skill2_random}:{text} ")
print(f"回合 {count}:")
        print(f"{Spirit1.name}: life={life_1}, attack={attack_1}, defense={defense_1}, speed={speed_1}")
        print(f"{Spirit2.name}: life={life_2}, attack={attack_2}, defense={defense_2}, speed={speed_2}")

同时发现了一个重大错误: 从日志输出以后才会发现当精灵1的攻击小于精灵2的防御力时攻击就会给精灵2回血,这部分没有设计好是一个失误,但是如果做平衡又要改很多东西,毕竟我是为了练习语法才写这个的因此主体运行没有错误就能接受。

大佬传送门(可运行代码)

整体代码

import random
import re
import os
import json
class Spirit(object): #父类
    __doc__ = "Spirit创建"
    __name__= "类的名字"
    __author__ = "silverbullet"
    skill_special = {'淬火':'增加自身50点攻击','汲水':'恢复自身100点生命','炼体':'增加自身2点防御'}
    Value_life = 500
    Value_attack = 20
    Value_defense = 5
    Value_speed = 10
    def __init__(self,name=None,skill=None,attribute=None,combat_attribute=None):   #可以在创建 Spirit 对象时不提供这些参数的值,而是使用默认值
        self.name = name
        self.skill = dict(skill) if skill else {}
        self.attribute = attribute
        self.combat_attribute = combat_attribute #{'value_life':None,'value_attack':None,'value_defense':None,'value_speed':None}
    def check(self):
        print(' spirit name is {} \n spirit skill is {} \n spirit attribute is {}'.format(self.name,self.skill,self.attribute))

    def add_name(self):
        self.name = input('请输入精灵名称:')

    def add_skill(self):
        skill_name = input('请输入技能名称:')
        skill_effect = input('请输入技能效果(设置技能效果时请以"伤害"、"生命"、"攻击"、"防御"这些词做最后两个字符\n'
                             '同时如果技能增加某种属性请以这种形式表示:"提升精灵30点攻击"):')
        skill_storage = {skill_name: skill_effect}
        self.skill.update(skill_storage)
    def add_attribute(self):   #实现在类中可以根据输入值改变内部其他值
        self.attribute = input('请在火、水、土中选择生成属性:')
        if self.attribute == '火':
            self.combat_attribute = self.fire_combat_attribute()
        elif self.attribute == '水':
            self.combat_attribute = self.water_combat_attribute()
        elif self.attribute == '土':
            self.combat_attribute = self.land_combat_attribute()
    def fire_combat_attribute(self):
        Value_life = self.Value_life - random.randint(10,30)
        Value_attack = self.Value_attack + random.randint(5, 10)
        Value_defense = self.Value_defense - random.randint(2, 3)
        Value_speed = self.Value_speed + random.randint(2, 4)
        return {'value_life': Value_life, 'value_attack': Value_attack, 'value_defense': Value_defense, 'value_speed': Value_speed}
    def water_combat_attribute(self):
        Value_life = self.Value_life
        Value_attack = self.Value_attack
        Value_defense = self.Value_defense
        Value_speed = self.Value_speed
        return {'value_life': Value_life, 'value_attack': Value_attack, 'value_defense': Value_defense, 'value_speed': Value_speed}
    def land_combat_attribute(self):
        Value_life = self.Value_life + random.randint(10, 30)
        Value_attack = self.Value_attack - random.randint(5, 10)
        Value_defense = self.Value_defense + random.randint(2, 3)
        Value_speed = self.Value_speed - random.randint(2, 4)
        return {'value_life': Value_life, 'value_attack': Value_attack, 'value_defense': Value_defense,'value_speed': Value_speed}
    @classmethod
    def getspecial_skill(cls): #选择一个随机的特殊技能
        skill_add = random.choice(list(cls.skill_special.items()))
        skill_add_key,skill_add_value = skill_add
        skill_dict = {skill_add_key:skill_add_value}
        return skill_dict

class VIP_Spirit(Spirit): #VIP创建
    def __init__(self,name=None,skill=None,attribute=None):
        super().__init__(name,skill,attribute)
    def add_name(self):
        super().add_name()
    def add_skill(self):
        super().add_skill()
        self.skill.update(Spirit.getspecial_skill())#实现添加父类中定义的特殊技能
    def add_attribute(self):
        super().add_attribute()

class VIP_non_Spirit(Spirit): #非VIP创建
    def __init__(self,name=None,skill=None,attribute=None):
        super().__init__(name,skill,attribute)
    def add_name(self):
        super().add_name()
    def add_skill(self):
        super().add_skill()
    def add_attribute(self):
        super().add_attribute()

def Spirit_vs(Spirit1,Spirit2): #这里输入的两个就是精灵主体
    #{'value_life': Value_life, 'value_attack': Value_attack, 'value_defense': Value_defense, 'value_speed': Value_speed}
    count = 0 #回合数
    turn = 0 #
    life_1 = Spirit1.combat_attribute['value_life']
    attack_1 = Spirit1.combat_attribute['value_attack']
    defense_1 = Spirit1.combat_attribute['value_defense']
    speed_1 = Spirit1.combat_attribute['value_speed']
    life_2 = Spirit2.combat_attribute['value_life']
    attack_2 = Spirit2.combat_attribute['value_attack']
    defense_2 = Spirit2.combat_attribute['value_defense']
    speed_2 = Spirit2.combat_attribute['value_speed']
    while life_1 > 0 and life_2 > 0 : #第一个元素为生命,当生命<=0时便会退出循环
        count += 1 #查看回合数
        number_damage_1 = 0
        number_damage_2 = 0#清除上一回合技能伤害
        if speed_1 >= speed_2 : #速度判断谁先出手 这里是1先出手  速度相同的情况下1也先出手
            skill1_random = random.choice(list(Spirit1.skill.keys()))
            text = Spirit1.skill[skill1_random]
            print(f"{Spirit1.name} used {skill1_random}:{text} ")
            pattern = re.search(r'(..)$',text)
            if pattern.group() == '伤害':
                number_damage_1 = int(re.search(r'\d+', text).group())
            else :
                match = re.search(r'(增加|加|增|提升|生|恢复|提高)(\D+)?(\d+).*(..)$', text)
                if match.group(4) == '攻击':
                    attack_1 += int(match.group(3))
                elif match.group(4) == '防御':
                    defense_1 += int(match.group(3))
                elif match.group(4) == '生命':
                    life_1 += int(match.group(3))
            life_2 -= attack_1 - defense_2 + number_damage_1
            if life_2 <= 0 :
                break
            skill2_random = random.choice(list(Spirit2.skill.keys()))
            text = Spirit2.skill[skill2_random]
            print(f"{Spirit2.name} used {skill2_random}:{text} ")
            pattern = re.search(r'(..)$',text)
            if pattern.group() == '伤害':
                number_damage_2 = int(re.search(r'\d+', text).group())
            else:
                match = re.search(r'(增加|加|增|提升|生|恢复|提高)(\D+)?(\d+).*(..)$', text)
                if match.group(4) == '攻击':
                    attack_2 += int(match.group(3))
                elif match.group(4) == '防御':
                    defense_2 += int(match.group(3))
                elif match.group(4) == '生命':
                    life_2 += int(match.group(3))
            life_1 -= attack_2 - defense_1 + number_damage_2
        else:       #2先出手
            skill2_random = random.choice(list(Spirit2.skill.keys()))
            text = Spirit2.skill[skill2_random]
            print(f"{Spirit2.name} used {skill2_random}:{text} ")
            pattern = re.search(r'(..)$',text)
            if pattern.group() == "伤害":
                number_damage_2 = int(re.search(r'\d+', text).group())
            else:
                match = re.search(r'(增加|加|增|提升|生|恢复|提高)(\D+)?(\d+).*(..)$', text)
                if match.group(4) == '攻击':
                    attack_2 += int(match.group(3))
                elif match.group(4) == '防御':
                    defense_2 += int(match.group(3))
                elif match.group(4) == '生命':
                    life_2 += int(match.group(3))
            life_1 -= attack_2 - defense_1 + number_damage_2
            if life_1 <= 0:
                break
            skill1_random = random.choice(list(Spirit1.skill.keys()))
            text = Spirit1.skill[skill1_random]
            print(f"{Spirit1.name} used {skill1_random}:{text} ")
            pattern = re.search(r'(..)$',text)
            if pattern.group() == "伤害":
                number_damage_1 = int(re.search(r'\d+', text).group())
            else:
                match = re.search(r'(增加|加|增|提升|生|恢复|提高)(\D+)?(\d+).*(..)$', text)
                if match.group(4) == '攻击':
                    attack_1 += int(match.group(3))
                elif match.group(4) == '防御':
                    defense_1 += int(match.group(3))
                elif match.group(4) == '生命':
                    life_1 += int(match.group(3))
            life_2 -= attack_1 - defense_2 + number_damage_1
        print(f"回合 {count}:")
        print(f"{Spirit1.name}: life={life_1}, attack={attack_1}, defense={defense_1}, speed={speed_1}")
        print(f"{Spirit2.name}: life={life_2}, attack={attack_2}, defense={defense_2}, speed={speed_2}")
    if life_1 > 0 :
        print("{}获胜!".format(Spirit1.name))
    else:
        print("{}获胜!".format(Spirit2.name))
    return count


def create_spirit(): #创建新精灵函数
    if not os.path.exists('save_spirit.txt'): #检测储存文件是否存在
        with open('save_spirit.txt','w') as f:
            pass
    with open('save_spirit.txt','r',encoding='utf-8') as file_row:
        row_content = file_row.readlines()
        row = len(row_content) #读取已经存在多少行文本
    with open('save_spirit.txt', 'a', encoding='utf-8') as f:
        target = VIP_Spirit()
        target.add_name()
        target.add_skill()
        f.write('{}.'.format(row))
        f.write(json.dumps(target.name, ensure_ascii=False))  # 设置ensure_ascii属性否则默认输出编码格式的字符
        f.write(',')
        f.write(json.dumps(target.skill, ensure_ascii=False))
        f.write(';')
        f.write('\r')  # windows中txt文本默认换行是\r 也可以使用os.linesep来进行换行
def choose_spirit(a): #通过读取序号返回对应的精灵类
    with open('save_spirit.txt','r',encoding='utf-8') as f:
        content = f.read().split(';')
        for i in content:
            if a in i[:2]:
                print(i)
                data_1 = i.split(',')
                name_1 = data_1[0].strip('"')#移除多余的字符
                data_2 = name_1.split('.')#将前面的序号去掉
                name_2 = data_2[1].strip('"')
                data_1_1 = ','.join(data_1[1:])
                skill = eval(data_1_1)
                spirit = Spirit(name_2,skill)
                return spirit
def read_spirit():
    if not os.path.exists('save_spirit.txt'): #检测储存文件是否存在
        with open('save_spirit.txt','w') as f:
            pass
    print("查看已保存精灵:")
    with open('save_spirit.txt', 'r', encoding='utf-8') as f:
        content = f.read()
        print(content)

def choose_vs(): #选择精灵进行游戏
    serial_number_1 = input("请选择要对战的精灵1的序号:")
    target_1 = choose_spirit(serial_number_1)
    target_1.add_attribute()
    serial_number_2 = input("请选择要对战的精灵2的序号:")
    target_2 = choose_spirit(serial_number_2)
    target_2.add_attribute()
    Spirit_vs(target_1, target_2)
def menu(): #编辑头文字部分
    print("\t\t\t\t\t1.查看精灵已储存精灵信息")
    print("\t\t\t\t\t2.选择精灵进行游戏")
    print("\t\t\t\t\t3.添加新精灵")
    print("\t\t\t\t\t4.退出游戏")

if __name__ == '__main__':
    button_1 = 1
    button_2 = 1
    while button_1 :
        menu()
        choice = int(input('请选择'))
        if choice in [1, 2, 3, 4]:
            if choice == 1:
                read_spirit()
                choice = int(input('1.返回主界面 2.开始精灵对战\n请选择下一步:'))
                if choice == 1:
                    continue
                elif choice == 2:
                    read_spirit()
                    choose_vs()
                    choice = int(input("1.返回主界面 2.退出游戏\n请选择下一步"))
                    if choice == 1:
                        continue
                    elif choice == 2:
                        button_1 = 0
                        continue
            elif choice == 2:
                read_spirit()
                choose_vs()
                choice = int(input("1.返回主界面 2.退出游戏\n请选择下一步"))
                if choice == 1:
                    continue
                elif choice == 2:
                    button_1 = 0
                    continue
            elif choice == 3:
                button_2 = 1
                while button_2: #内循环加一个判定
                    create_spirit()
                    read_spirit()
                    choice = int(input('1.开始精灵对战 2.返回主界面 3.退出游戏 4.继续添加\n请选择下一步'))
                    if choice == 1:
                        read_spirit()
                        choose_vs()
                        choice = int(input("1.返回主界面 2.退出游戏\n请选择下一步"))
                        if choice == 1:
                            break
                        elif choice == 2:
                            button_1 = 0
                            break
                    elif choice == 2:
                        break
                    elif choice == 3:
                        button_1 = 0
                        break
                    elif choice == 4:
                        continue
            elif choice == 4:
                button_1 = 0
                continue

注意事项: 1.每次选择完精灵之后要会提示设置属性请在“火”、“土”、“水”中选择,因为代码中只有赋予属性才会给定相应的基础属性。
2.技能方面:设置技能效果时请以“生命”、“攻击”、“防御”、“伤害”进行结尾,在这里我用的是re搜寻,并且只设计了接受增加这些伤害,不会出现减少的情况。
3.没有设置清除txt文本的功能,如果是第一次使用请先新建精灵。
可修改部分: 1.修改基础属性在"10-13"行代码
2.修改赋予’火’属性后所带来的不同属性在‘39-56’,或直接搜索fire_combat_attribute,对应的函数在这里。
3.修改战斗中防御过高带来的回血bug在’85’或搜索Spirit_vs(Spirit1,Spirit2),对应的函数在这里。
4.修改创建精灵是否为VIP在’185’行或搜索target = VIP_Spirit(),默认为vip创建可以多一个技能。

;