随着玩家想要添加更多功能,传统的函数式编程已经无法满足变得越来越困难。

面对对象编程可以拯救你。

 

首先声明三个类,一个骑士类Knight;一个敌人类OrcRider;一个房子类Huts;

骑士类中有name,health_meter,show_health,info,attack,heal,acquire_hut,run_away,weapons,gold

房子类中有number,occupant,occupant_type,acquire,weapons,gold,food,history

敌人类中有name,health_meter,show_health,info,attack,heal,acquire_hut,run_away,weapons,gold;其中一些功能如治疗、逃跑之类的不会有

 

你会发现,敌人类和骑士类有些共同的东西,那么我们会用继承原则来为这些东西创建一个叫做GameUnit的超类,然后把共同的代码移入超类中,然后让子类去重写

对应的功能。

 

uml的一些原则:+表示公有、-表示私有,空心箭头表示继承,实心菱形表示组合,空心菱形表示对象聚合。

 

组合是一种重要的面向对象的原则,意味着一种has a的关系。例如:木屋里has a 骑士/敌人

 

聚合,指的是一个类会创建另一个类的某些实例。

 

 



import random
import sys

if sys.version_info < (3, 0):
print("代码需要python3.5以上版本 ")
print("Looks like you are trying to run this using "
"Python version: %d.%d " % (sys.version_info[0],
sys.version_info[1]))
print("Exiting...")
sys.exit(1)


def weighted_random_selection(obj1, obj2):
"""随机选择一个对象,3、7分
"""
weighted_list = 3 * [id(obj1)] + 7 * [id(obj2)] # id()函数获取对象的内存地址
selection = random.choice(weighted_list)

if selection == id(obj1):
return obj1

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.health_meter = 0
self.name = name
self.enemy = None
self.unit_type = None

def info(self):
"""单位的信息显示(子类中重写)"""
pass

def attack(self, enemy):
"""The main logic to determine injured unit and amount of injury伤害的主逻辑和谁遭到伤害

.. todo:: Check if enemy exists!
"""
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:
# 否则治疗2血 TODO: Do you see a bug here? it can exceed max hit points!
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):
""" 骑士角色Class that represents the game character 'Knight'

The player instance in the game is a Knight instance. Other Knight
instances are considered as 'friends' of the player and is
indicated by the attribute `self.unit_type` .
"""

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 basic information about this character"""
print("我是一个骑士!")

def acquire_hut(self, hut):
"""Fight the combat (command line) to acquire the hut

.. todo:: acquire_hut method can be refactored.
Example: Can you use self.enemy instead of calling
hut.occupant every time?
"""
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.run_away()
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 run_away(self):
"""Abandon the battle.

.. seealso:: `self.acquire_hut`
"""
print_bold("逃跑...")
self.enemy = None


class OrcRider(GameUnit):
"""兽人类Class that represents the game character Orc Rider"""

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 basic information about this character"""
print("呃呃呃.我是狼骑士! Don't mess with me.")


class Hut:
"""Class to create hut object(s) in the game Attack of the Orcs"""

def __init__(self, number, occupant):
self.occupant = occupant
self.number = number
self.is_acquired = False

def acquire(self, new_occupant):
"""Update the occupant of this hut"""
self.occupant = new_occupant
self.is_acquired = True
print_bold("干得好! 屋子 %d 被访问" % self.number)

def get_occupant_type(self):
"""Return a string giving info on the hut occupant"""
if self.is_acquired:
occupant_type = '已访问'
elif self.occupant is None:
occupant_type = '空屋'
else:
occupant_type = self.occupant.unit_type

return occupant_type


class AttackOfTheOrcs:
"""Main class to play Attack of The Orcs game"""

def __init__(self):
self.huts = []
self.player = None

def get_occupants(self):
"""Return a list of occupant types for all huts.

.. todo::

Prone to bugs if self.huts is not populated.
Chapter 2 talks about catching exceptions
"""
return [x.get_occupant_type() for x in self.huts]

def show_game_mission(self):
"""Print the game mission in the console"""
print_bold("任务:")
print(" 1. 和敌人战斗.")
print(" 2. 铲除所有屋子中的敌人")
print("---------------------------------------------------------\n")

def _process_user_choice(self):
"""Process the user input for choice of hut to enter"""
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):
"""Randomly occupy the huts with one of: friend, enemy or 'None'"""
for i in range(5):
choice_lst = ['敌人', '朋友', None]
computer_choice = random.choice(choice_lst)
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):
"""Workhorse method to play the game.

Controls the high level logic to play the game. This is called from
the main program to begin the game execution.
"""
self.player = Knight()
self._occupy_huts()
acquired_hut_counter = 0

self.show_game_mission()
self.player.show_health(bold=True)

while acquired_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:
acquired_hut_counter += 1

if acquired_hut_counter == 5:
print_bold("恭喜! 你赢了!!!")


if __name__ == '__main__':
game = AttackOfTheOrcs()
game.play()