第一章:采用面向对象编程实现兽人之袭文本游戏
1、采用面向对象编程实现
# python应用开发实战
#兽人之袭v1.0.面向对象编程
'''
需求分析:
1、获得所有木屋击败木屋里的所有敌人
2、可以在同伴或者无人居住的木屋中治疗自身
3、可以选择放弃战斗,在木屋中治疗后返回战斗
4、引入一个或者多个骑士帮助FOO先生,他们可以轮流占领木屋
5、可以为每个敌人和骑士配置最大的攻击点
6、木屋数量实现可配置
7、木屋中可以存放一些黄金或者武器,Foo先生和他的同伴可以捡起这把武器
8、可以让一个精灵骑士加入队伍,更大几率获胜
'''
import random
import textwrap
import sys
if sys.version_info<(3,0):
print('本代码需要在python3.5以上的版本运行')
print('当前版本号为%d.%d'%(sys.version_info[0],sys.version_info[1]))
print('正在退出')
sys.exit(1)
def print_dotted_line(width=72):
print('-'*width)
def show_theme_message(width=72):
print_dotted_line()
print('\033[1;35;34m'+'兽人之袭V0.0.1:'+'\033[0m')
#---------------------------------------
#输出字体颜色格式的更改
#1:高亮显示,35:前景色为紫红色,34:背景色为蓝色
#格式为‘\033[显示方式;前景色;背景色 +'text' +'\033[0m'
msg=(
'人类和他们的敌人——兽人之间的战争即将开始,'
'foo爵士,守卫在南部平原的勇敢骑士之一,开'
'始了一段漫长的旅途。在一个未知的茂密的森'
'林,他发现了一个小的孤立居住点,因为'
'疲劳的原因,再加上希望能补充到粮食储备,他'
'决定绕道而行。当他走进村庄时,他看见5个木屋'
',周围没有任何敌人。犹豫之后,他决定走进其中'
'一间木屋......'
)
print(textwrap.fill(msg, width=width//2))#调整输出格式,以填充的形式输出
def weighted_random_selection(obj1,obj2):
weighted_list=3*[id(obj1)]+7*[id(obj2)]
selction=random.choice(weighted_list)
if selction==id(obj1):
return obj1
else:
return obj2
def print_bold(msg,end='\n'):
print('\033[1m'+msg+'\033[0m',end=end)
class gameunit():
def __init__(self,name=''):
self.max_hp=0
self.name=name
self.health_meter=0
self.enemy=None
self.unit_type=None #表示NPC人物的阵营
def info(self):
'''Information on the unit (overridden in subclasses'''
pass
def attack(self,enemy):
injured_unit=weighted_random_selection(self,enemy)
injury=random.randint(10,15)
injured_unit.health_meter = max(injured_unit.health_meter - injury, 0)
print("攻击! ", end='')
self.show_health(end=' ')
enemy.show_health(end=' ')
def heal(self, heal_by=2, full_healing=True):
"""Heal the unit replenishing all the hit points"""
if self.health_meter == self.max_hp:
return
if full_healing:
self.health_meter = self.max_hp
else:
self.health_meter += heal_by
print_bold("已被治疗!", end=' ')
self.show_health(bold=True)
def reset_health_meter(self):
"""Reset the `health_meter` (assign default hit points)"""
self.health_meter = self.max_hp
def show_health(self, bold=False, end='\n'):
"""Show the remaining hit points of the player and the enemy"""
# TODO: what if there is no enemy?
msg = "生命值: %s: %d" % (self.name, self.health_meter)
if bold:
print_bold(msg, end=end)
else:
print(msg, end=end)
class knight(gameunit):
def __init__(self,name='Foo先生'):
super().__init__(name=name)#调用超类的初始化函数
self.max_hp=40
self.health_meter=self.max_hp
self.unit_type='朋友'
def info(self):
print ('我是一名骑士')
def acquire_hut(self,hut):
print_bold('进入%d号木屋'%hut.number,end='')
is_enemy=(isinstance(hut.occupant,gameunit)and hut.occupant.unit_type=='敌人')
continue_attack='y'
if is_enemy:
print_bold('发现敌人!')
self.show_health(bold=True,end=' ')
hut.occupant.show_health(bold=True,end='')
while continue_attack:
continue_attack=input('是否继续攻击?(y/n): ')
if continue_attack=='n':
self.runaway()
break
self.attack(hut.occupant)
if hut.occupant.health_meter<=0:
print(' ')
hut.acquire(self)
break
if self.health_meter<=0:
print(' ')
break
else:
if hut.get_occupant_type()=='无人居住':
print_bold('木屋无人居住')
else:
print_bold('找到一个朋友')
hut.acquire(self)
self.heal()
def runaway(self):
print_bold('溜了溜了...')
self.enemy=None
class hut():
def __init__(self,number,occupant):
self.occupant=occupant
self.number=number
self.is_acquired=False #木屋是否被调查
def acquire(self,new_occupant):
self.occupant=new_occupant
self.is_acquired=True
print_bold('干得好!,%d号木屋已经被调查'%self.number)
def get_occupant_type(self):
if self.is_acquired:
occupant_type='已被调查'
elif self.occupant is None:
occupant_type='无人居住'
else:
occupant_type=self.occupant.unit_type
return occupant_type
class orcrider(gameunit):
def __init__(self,name=''):
super().__init__(name=name)
self.max_hp=30
self.health_meter=self.max_hp
self.unit_type='敌人'
self.hut_number=0
def info(self):
print('啊啊啊啊!兽人永不为奴!别惹我')
class attackoftheorcs:
def __init__(self):
self.huts = []
self.player=None
def get_occupants(self):
return [x.get_occupant_type() for x in self.huts]
def show_game_mission(self):
print_bold('任务1:')
print('1、打败所有敌人')
print('2、调查所有木屋,获取所有木屋的控制权')
print_dotted_line()
def process_user_choice(self):
verifying_choice=True
idx=0
print("木屋调查情况: %s" % self.get_occupants())
while verifying_choice:
user_choice=input('选择一个木屋进入(1-5):')
idx=int(user_choice)
if self.huts[idx-1].is_acquired:
print('你已经调察过这个木屋,请再尝试一次'
'提示:不能再已调查的木屋得到治疗')
else:
verifying_choice=False
return idx
def occupy_huts(self):
for i in range(5):
choice_list=['敌人','朋友',None]
computer_choice=random.choice(choice_list)
if computer_choice=='敌人':
name='敌人-'+str(i+1)
self.huts.append(hut(i+1,orcrider(name)))
elif computer_choice=='朋友':
name='骑士-'+str(i+1)
self.huts.append(hut(i+1,knight(name)))
else:
self.huts.append(hut(i+1,computer_choice))
def play(self):
self.player=knight()
self.occupy_huts()
acquires_hut_counter=0
self.show_game_mission()
self.player.show_health(bold=True)
while acquires_hut_counter<5:
idx=self.process_user_choice()
self.player.acquire_hut(self.huts[idx-1])
if self.player.health_meter<=0:
print_bold('你输了!祝下次好运!')
break
if self.huts[idx-1].is_acquired:
acquires_hut_counter+=1
if acquires_hut_counter==5:
print_bold('祝贺你!,你已经调查完所有的木屋')
if __name__=='__main__':
game=attackoftheorcs()
game.play()
2、关于书中1.7节所涉及到的 python中的抽象基类
- 装饰器:可以实现动态修改方法,类,函数功能的方法。理解装饰器,装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
def use_logging(func):
def wrapper():
print("%s is running" % func.__name__)
return func() # 把 foo 当做参数传递进来时,执行func()就相当于执行foo()
return wrapper
def foo():
print('i am foo')
foo = use_logging(foo) # 因为装饰器 use_logging(foo) 返回的时函数对象 wrapper,这条语句相当于 foo = wrapper
foo()
foo = use_logging(foo) 这一语句,首先调用use_logging函数,直接返回wrapper函数对象,相当于foo=wrapper,运行foo()语句后,相当于直接执行wrapper函数,打印出foo is running后,返回func(),打印出i am foo。
更多请参考12步教你理解Python装饰器。
-
抽象基类: ABC,Abstract Base Class(抽象基类),主要定义了基本类和最基本的抽象方法,可以为子类定义共有的API,不需要具体实现。相当于是Java中的接口或者是抽象类。 抽象基类可以不实现具体的方法(当然也可以实现,只不过子类如果想调用抽象基类中定义的方法需要使用super())而是将其留给派生类实现。抽象基类提供了逻辑和实现解耦的能力,即在不同的模块中通过抽象基类来调用,可以用最精简的方式展示出代码之间的逻辑关系,让模块之间的依赖清晰简单。同时,一个抽象类可以有多个实现,让系统的运转更加灵活。而针对抽象类的编程,让每个人可以关注当前抽象类,只关注其方法和描述,而不需要考虑过多的其他逻辑,这对协同开发有很大意义。极简版的抽象类实现,也让代码可读性更高。