“笨办法”学Python 3 ——练习43 面向对象的分析和设计基础

练习43 面向对象的分析和设计基础

面向对象编程(OOP)方式构建的基本流程

这是一种“自上而下”(top down))的方式,它从非常抽象、松散的想法开始,然后慢慢提炼,直到想法变得具体。
1、把要解决的问题写下来,或者画出来(问题描述、结构关系图等)
2、将第一条中的关键概念提取出来并加以研究(问题名词、动词提取到代码命名中)
3、创建一个类层次结构和对象图(结构关系图、父类子类、函数方法的关系)
4、用代码实现各个类,并写一个测试来运行它们(骨架代码逐步细化)
5、重复上述步骤并细化代码

一个简单的游戏引擎分析

**游戏名:**来自25号行星的哥顿人

一、写或者画出这个问题

游戏描述:“外星人入侵了一艘宇宙飞船,我们的英雄必须穿过迷宫般的房间打败他们,这样他才能逃到逃生舱去到下面的星球。游戏更像是 Zork 之类的文字冒险游戏,并且有着很有意思的死亡方式。这款游戏的引擎会运行一张满是房间或场景的地图。当玩家进入游戏时,每个房间都会打印自己的描述,然后告诉引擎下一步该运行地图中的哪个房间。”
场景描述:
死亡(Death):玩家死的时候,会非常有意思。
中央走廊(Central Corridor):这是起点,已经有一个哥顿人站在那里,在继续之前,玩家必须用一个笑话来击败他。
激光武器军械库(Laser Weapon Armory):这是英雄在到达逃生舱之前用中子弹炸毁飞船的地方。这里有一个键盘,英雄必须猜出数字。
桥(The Bridge):另一个和哥顿人战斗的场景,英雄在这里放置了炸弹。
逃生舱(Escape Pod):英雄逃脱的地方,前提是他猜出正确的逃生舱。

二、抽取关键概念并予以研究

提取名词列表:
Alien(外星人)
Player(玩家)
Ship(飞船)
Maze(迷宫)
Room(房间)
Scene(场景)
Gothon(哥特人)
Escape Pod(逃生舱)
Planet(行星)
Map(地图)
Engine(引擎)
Death(死亡)
Central Corridor(中央走廊)
Laser Weapon Armory(激光武器军械库)
The Bridge(桥)

三、为这些概念创建类的层级结构和对象地图

可以发现“场景”和“房间”基本上是一个东西,所以可以使用“场景”来代替“房间”,而“死亡”适合“死亡场景”,就将其归为“场景”,“迷宫”和“地图”大致一样,就用“地图”。
创建类的层级结构:
Map
Engine
Scene
-Death
-Central Corridor
-Laser Weapon Armory
-The Bridge
-Escape Pod
添加动词结构:
Map
– next_scene
– opening_scene
Engine
– play
Scene
– enter
-Death
-Central Corridor
-Laser Weapon Armory
-The Bridge
-Escape Pod

四、编写类代码并通过测试来运行

根据类和函数的树状图,把它们编辑成类。(类和函数树状图从下到上写类)

#场景-类,enter-函数
class Scene(object):
    def enter(self):
        pass

#引擎-类,play-函数
class Engine(object):
    def __init__(self, scene_map):
        pass
    def play(self):
        pass

#Scene的子类
class Death(Scene):
    def enter(self):
        pass

class CentralCorridor(Scene):
    def enter(self):
        pass

class LaserWeaponArmory(Scene):
    def enter(self):
        pass

class TheBridge(Scene):
    def enter(self):
        pass

class EscapePod(Scene):
    def enter(self):
        pass

# 地图-类。next_scene-函数,opening_scene-函数
class Map(object):
    def __init__(self, start_scene):
        pass
    def next_scene(self, Scene_name):
        pass
    def opening_scene(self):
        pass

a_map = Map('central_corridor') #地图初始场景
a_game = Engine(a_map) #游戏引擎
a_game.play() #游戏启动

五、重复和改进

不断的循环上面的步骤,逐步细化。
它不仅仅是一个单一层面上做的事,而是遇到一个特定的问题时,可以在每个层面上做的事情。例如不知道怎么写 Engine.play 这个方法。可以停下来,把整个过程专注在这一个函数上来弄明白代码应该怎么写。

自上而下 vs 自下而上

从写代码开始,然后逐渐“上升”到抽象的概念,这种方式被称为“自下而上”。它的步骤大致如下:
1.从问题中拿出一小部分,开始写简单的能运行的代码。
2.然后用类和自动化测试来把代码改进地更正式一些。
3.抽象出你所使用的关键概念,试着探究一下它们。
4.针对正在发生的事情写一段描述。
5.回过头去继续改进代码,也可能把之前写的删掉重新开始。
6.转到这个问题的其他部分,然后重复以上步骤。
这个过程只有在你对编程已经比较熟练并且面对问题能够自然使用编程思维的情况下才会更好,同时,当你知道整个工程的一小部分、却对全局概念的信息掌握不全的时候,这个方法也很好用。

“来自25号行星的哥顿人”游戏代码

1.导入游戏代码所需要的库(包)

from sys import exit  #退出程序。退出python程序首选方法
from random import randint #随机数取整
from textwrap import dedent #删除字符串中的前导空格

2.在代码框架中,细化第一个父类,具有所有场景都具有的公共功能。

class Scene(object):
    
    def enter(self):
        print("This scene is not yet configured.") #这个场景还没有被设置
        print("Subclass it and implemet enter().") #设置其子类并且执行enter()函数
        exit(1) #出现程序异常退出程序

3.Engine类,其中Map.opening_sceneMap.next_scene已经使用,在这里已经提前计划好了,后面在Map类中会将这些方法写出来。

class Engine(object):
    def __init__(self, scene_map):#scene_map是Map类的对象
        self.scene_map = scene_map

    def play(self):
        current_scene = self.scene_map.opening_scene() #目前所在场景,通过Map对象调用Map类中的函数opening_scene
        last_scene = self.scene_map.next_scene('finished') #最后一个场景,同上,通过Map对象调用Map类中函数next_scene

        while current_scene != last_scene: #while循环,当前场景不是最后一个场景的情况下
            next_scene_name = current_scene.enter()
            current_scene = self.scene_map.next_scene(next_scene_name)

            #be sure to print out the last scene
            current_scene.enter()

4.创建第一个也是最简单的一个场景Death场景。

class Death(Scene):
    
    quips = [
        "You died. You kinda suck at this.",
        "Your Mom would be proud...if she were smarter.",
        "Such a luser.",
        "I have a small puppy that's better at this.",
        "You're worse than your Dad's jokes."
    ] #字符串列表,各种不同情况

    def enter(self):
        print(Death.quips[randint(0,len(self.quips)-1)]) #打印,quips列表中的值,该索引为0到列表长度-1中的随机数值。
        exit(1)#程序异常退出

5.创建了中央走廊场景,这是游戏的开始。把游戏的场景放在 Map 之前,是因为需要在随后引用它们。

#中央走廊场景
class CentralCorridor(Scene):
    
    def enter(self):
        print(dedent("""
            The Gothons of Planet Percal #25 have invaded your ship and
            destroyed your entire crew. You are the last surviving
            member and your last mission is to get the neutron destruct
            bomb from the Weapons Armory, put it in the bridge,and
            blow the ship up after getting into an escape pod.
            
            You're running down the central corridor to the Weapons
            Armory when a Gothon jumps out, red scaly skin, drak grimy
            teeth, and evil clown costume flowing around his hate
            filled body, He's blocking the door to the Armory and 
            about to pull a weapon to blast you.
            """)) #进入游戏的前景介绍
        
        action = input("> ") #输入行为

        if action == "shoot!": #如果行动是shoot
            print(dedent("""
                Quick on the draw you yank out your blaster and fire
                it at the Gothon. His clown costume is flowing and
                moving around his body, which throws off your aim.
                Your laser hits his costume but misses him entirely.
                This completely ruins his brand new costume his mother
                bought him, which makes him fly into an insane rage
                and blast you repeatedly in the face until you are 
                dead. Then he eats you.
                """))
            return 'death' #返回值

        elif action == "dodge!": #行动是dodge时
            print(dedent("""
            Like a world class boxer you dodge, weave,slip and 
            slide right as the Gothon's blaster cranks a laser
            past your head. In the middle of your artful dodge
            your foot slips and you bang your head on the metal
            wall and pass out. You wake up shortly after only to
            die as the Gothon stomps on your head and eats you. 
            """)) 
            return 'death' #返回值
        
        elif action == "tell a joke": #如果行动是tell a joke
            print(dedent("""
            Lucky for you they made you learn Gothon insults in
            the academy. You tell the one Gothon joke you know:
            Lbhe Zbgure vf fb sng, jura fur fvgf nebhaq gur ubhfr,
            fur fvgf nebhaq gur ubhfr. The Gothon stops, tries
            not to laugh, then busts out laughing and can't move.
            While he's laughing you run up and shoot him square in
            Weapon Armory door.
            """))
            return 'laser_weapon_armory' #返回值
        
        else:
            print("DOES NOT COMPUTE")
            return 'central_corridor' #返回值

6.创建游戏的剩余场景,并思考它们之间如何流转。激光武器军械库、行星、桥、逃生仓和结束场景。

#激光武器库场景
class LaserWeaponArmory(Scene):
    def enter(self):
        print(dedent("""
        You do a dive roll into the Weapon Armory, crouch and scan
        the room for more Gothons that might be hidding. It's dead
        quiet, too quiet. You stand up and run to the far side of
        the room and find the neutron bomb in its container.
        There's a keypad lock on the box and you need the code to 
        get the bomb out. If you get the wrong 10 times then 
        the lock closes forever and you can't get the bomb. The
        code is 3 digits.
        """))  #场景提示
    
        code = f"{randint(1,9)}{randint(1,9)}{randint(1,9)}" #变量字符串格式化,密码为三个1-9之间的随机整数,包括1和9
        guess = input("[keypad]> ") #猜测密码
        guesses = 0 #猜测次数初始值

        while guess != code and guesses < 10: #while循环,无法确定循环次数时使用while而不是for循环。猜想密码与密码不一致且猜测次数小于10.
            print("BZZZZEDDDD!")
            guesses += 1 #猜测次数不断累加
            guess = input("[keypad]> ") #重新猜测密码

        if guess == code: #如果密码正确
            print(dedent("""
            The container clicks open and the seal breaks, letting
            gas out. You grab the neutron bomb and run as fast as
            you can to the bridge where you must place it in the 
            right spot.
            """)) #打印结果
            return 'the_bridge' #返回值
        else:
            print(dedent("""
            The lock buzzes one last time and then you hear a 
            sickening melting sound as the mechanism is fused
            together. You decide to sit there, and finally the 
            Gothons blow up the ship from their ship and you die.
            """)) 
            return 'death'
    
#桥场景
class TheBridge(Scene):
    def enter(self):
        print(dedent("""
        You burst onto the Bridge with the netron destruct bomb
        under your arm and surprise 5 Gothons who are trying to
        take control of the ship. Each of them has an even uglier
        clown costume than the last. They haven't pulled their
        weapons out yet, as they see the active bomb under your
        arm and don't want to set it off.
        """)) #进入时场景

        action = input("> ") #输入行动

        if action == "throw the bomb": #如果行动是throw the bomb时
            print(dedent("""
            In a panic you throw the bomb at the group of Gothons
            and make a leap for the door. Right as you drop it a 
            Gothons shoots you right in the back killing you. As
            you die you see another Gothon frantically try to
            disarm the bomb. You die knowing they will probably
            blow up when it goes off.
            """))
            return 'death' #返回值

        elif action == "slowly place the bomb": #如果行动为slowly place the bomb时
            print(dedent("""
            You point your blaster at the bomb under your arm and
            the Gothons put their hands up and start to sweat.
            You inch backward to the door, open it, and then
            carefully place the bomb on the floor, pointing your
            blaster at it. You then jump back through the door,
            punch the close button and blast the lock so the
            Gothons can't get out. Now that the bomb is placed 
            you run to the escape pod to get off this tin can.
            """)) #发生的事情
            return 'escape_pod' #返回值
        
        else:
            print("DOES NOT COMPUTE!")
            return 'the_bridge' #返回值

#逃生舱场景
class EscapePod(Scene):
    def enter(self):
        print(dedent("""
        You rush through the ship desperately trying to make it
        the escape pod before the whole ship explodes. It seems
        like hardly any Gothons are on the ship, so your run is
        clear of interference. You get to the chamber with the
        escape pods, and now need to pick one to take. Some of
        them could be damaged but you don't have time to look.
        There's 5 pods, which one do you take?
        """)) #进入场景
        
        good_pod = randint(1,5) #1-5之间的随机整数
        guess = input("[pod]> ") #输入猜想

        if int(guess) != good_pod: #猜想与好用的逃生舱不一致时
            print(dedent(f"""
            You jump into pod {guess} and hit the eject button.
            The pod escapes out into the void of space, then
            implodes as the hull ruptures, crushing your body into
            jam jelly.
            """))  #字符串格式化guess变量
            return 'death' #返回值
        else:
            print(dedent(f"""
            You jump into pod {guess} and hit the eject button.
            The pod easily slides out into space heading to the
            planet below. As it flies to the planet, you look
            back and see your ship implode then explode like a 
            bright star, taking out the Gothon ship at the same
            time. You won!
            """)) #字符串格式化guess变量

            return 'finished' #返回值

#结束场景
class Finished(Scene):

    def enter(self):
        print("You won! Good job.")
        return 'finished' #返回值

7.创建Map 类,其中把每个场景的名字存储在一个字典里,然后用 Map.scenes 引用那个字典。这也是为什么地图出现在场景之后的原因,因为字典必须引用场景,所以场景必须先存在。

# 地图-类。next_scene-函数,opening_scene-函数
class Map(object):

    scenes = {
        'central_corridor':CentralCorridor(),
        'laser_weapon_armory':LaserWeaponArmory(),
        'the_bridge': TheBridge(),
        'escape_pod':EscapePod(),
        'death':Death,
        'finished':Finished()
    } #字典,字符串键对应-子类值
    #初始化函数
    def __init__(self, start_scene):
        self.start_scene =start_scene #定义start_scene

    def next_scene(self, scene_name): #定义next_scene函数,作用:通过获取的场景字符串,得到对应的的字典的值,即子类场景
        val = Map.scenes.get(scene_name) #get()获取字典的值,若值不存在不报错
        return val #返回值

    def opening_scene(self): #定义函数
        return self.next_scene(self.start_scene) #返回值,返回next_scene函数,参数scene_name = start_scene.

8.运行游戏,调用play是游戏工作。

a_map = Map('central_corridor') #地图初始场景
a_game = Engine(a_map) #游戏引擎
a_game.play() #游戏启动

运行结果:

The Gothons of Planet Percal #25 have invaded your ship and
destroyed your entire crew. You are the last surviving
member and your last mission is to get the neutron destruct
bomb from the Weapons Armory, put it in the bridge,and
blow the ship up after getting into an escape pod.

You're running down the central corridor to the Weapons
Armory when a Gothon jumps out, red scaly skin, drak grimy
teeth, and evil clown costume flowing around his hate
filled body, He's blocking the door to the Armory and
about to pull a weapon to blast you.

> tell a joke

Lucky for you they made you learn Gothon insults in       
the academy. You tell the one Gothon joke you know:       
Lbhe Zbgure vf fb sng, jura fur fvgf nebhaq gur ubhfr,    
fur fvgf nebhaq gur ubhfr. The Gothon stops, tries        
not to laugh, then busts out laughing and can't move.     
While he's laughing you run up and shoot him square in    
Weapon Armory door.

You do a dive roll into the Weapon Armory, crouch and scan
the room for more Gothons that might be hidding. It's dead
quiet, too quiet. You stand up and run to the far side of 
the room and find the neutron bomb in its container.      
There's a keypad lock on the box and you need the code to 
get the bomb out. If you get the wrong 10 times then
the lock closes forever and you can't get the bomb. The
code is 3 digits.

[keypad]> 123
BZZZZEDDDD!
[keypad]> 345
BZZZZEDDDD!
[keypad]> 234
BZZZZEDDDD!
[keypad]> 456
BZZZZEDDDD!
[keypad]> 347
BZZZZEDDDD!
[keypad]> 784
BZZZZEDDDD!
[keypad]> 345
BZZZZEDDDD!
[keypad]> 987
BZZZZEDDDD!
[keypad]> 675
BZZZZEDDDD!
[keypad]> 456
BZZZZEDDDD!
[keypad]> 789

The lock buzzes one last time and then you hear a
sickening melting sound as the mechanism is fused
together. You decide to sit there, and finally the
Gothons blow up the ship from their ship and you die.

Your Mom would be proud...if she were smarter.

知识点:

1. textwrap模块的dedent函数
python中,可以使用textwrap模块的dedent函数删除字符串中的前导空格,它解决了python代码缩进与书写多行字符串的冲突问题,避免在全局定义多行字符串。
代码示例:
(1)不使用dedent函数:

#不使用dedent函数
text = """
    How are you?
    I'm fine, thank you."""
print(text)

#不符合python的缩进原则
text = """
How are you?
I'm fine, thank you."""
print(text)

输出:

    How are you?
    I'm fine, thank you.

How are you?
I'm fine, thank you.

符合python缩进格式的字符串,打印时,存在缩进空格。
(2)使用dedent函数

#使用dedent函数,删除三引号中的前导空格
text = """
    How are you?
    I'm fine, thank you."""
print(dedent(text))

输出结果:

How are you?
I'm fine, thank you.

2. 类的函数调用?
类的调用需要先实例化为对象,实例化时不能忘记类本身设定的属性__init__()函数内的参数也是类实例化需要的参数。
类的函数使用,通过**.函数名(参数名),具体操作可见练习41面向对象编程术语**。
类函数的内部调用,需要确保函数内参数数量一致,且使用**self.函数名(参数名)**调用。

报错类型:TypeError: water() missing 1 required positional argument: 'food' 这里的’food’,也可以是别的参数例如’self’等。
原因:类的实例化失败,调用该函数时,类没有实例化为对象。需要先保证类已经实例化。具体可参加代码注释。
具体调用方法如下:

class Animal():
    def __init__(self, name,age): #类初始化属性
        self.name = name
        self.age = age
    
    def feed(self,num,food): #feed()函数,参数为num和food
        num += 1
        print(f"It needs {num}g {food}.")

    def water(self, n, food): #water()函数,参数为n和food,因为要调用内部函数,该函数的参数需要与调用函数一致
        #内部调用函数feed(),使用self.函数名(参数)调用,注意参数数量与之前一致
        water_num = self.feed(n,food) 
        return water_num

AM = Animal("Lily",2) #实例化类时,需要定义类的属性,若无,则不需要
AM.water(2,'apple') #类的函数外部调用,将类实例化后使用.调用
Animal.water(1,"meat") #会报错,Animal类未实例化

输出:

It needs 3g apple.
Traceback (most recent call last):
  File "c:\Users\limin\Desktop\Python3_exercises\text43_1.py", line 43, in <module>
    Animal.water(1,"meat")
TypeError: water() missing 1 required positional argument: 'food'

3. 类相互调用函数?
类相互调用的方式见下面示例,以及代码中的注释说明。

(1)第一种同文件内类之间的函数调用:

#类相互之间调用函数
class Car():
    def __init__(self,make,model): #初始化函数,属性make和model
        self.make = make
        self.model =model

    def engine(self,num): #定义Car()函数
        print(f"The car has {num} engine.")

class Dealership():
    def __init__(self,name): #初始化函数,属性为name,调用实例需要填写name属性
        self.name = name
        self.cars = [] #定义新变量,列表

    def add_car(self, make, model): #定义函数,其参数数量由于调用Car()类属性而与其对应参数相同
        new_car = Car(make,model) #调用Car()类属性,即初始化函数
        self.cars.append(new_car)
    
    def show_inventory(self,make,model,num): #定义函数,参数数量由调用Car()类的engine()函数确定,因此参数为3个
        for car in self.cars:
            print(car.make,car.model)
        Car(make,model).engine(num) #调用Car()类中的函数engine(),调用函数依旧需要实例化类

dealership = Dealership("ABC Motors")
dealership.add_car("Toyota","Camry")
dealership.add_car("Honda","Civic")
dealership.show_inventory("ABC","BIG",3)

输出结果:

Toyota Camry
Honda Civic
The car has 3 engine.

(2)跨文件类函数的相互调用
跨文件类的相互调用是指在不同的.py文件中定义的两个或多个类之间的相互调用。
要实现跨文件类的相互调用,需要遵循如下步骤:
·将需要被调用的类定义在一个单独的.py文件中,这个文件称为模块。
·在另一个文件中,使用import语句导入该模块。
·在当前文件中使用该模块中定义的类时,需要使用模块名加点号进行引用。例如,如果在module.py文件中定义了一个类MyClass,那么在另一个文件中使用该类时可以这样写:module.MyClass()。
具体操作如下代码:
(1)创建第一个类ClassA
text43_3.py

class ClassA():
    def __init__(self):
        self.name = 'ClassA'  

    def greet(self): # 定义函数
        return 'Hello from ' + self.name  # 返回字符串

(2)创建第二个类Class B,并调用第一个文件中的ClassA类
text43_4.py

from text43_3 import ClassA  #调用模块

class ClassB():  #定义类
    def __init__(self):  #定义属性
        self.name = 'ClassB'  

    def greet(self): #定义函数
        return 'Hello from ' + self.name #返回值

    def call_class_a(self): #定义函数,返回class_a类
        a = ClassA() #调用class_a实例
        return a.greet() #返回值

(3) 运行主代码
text_5.py

from text43_4 import ClassB #调用ClassB模块

b = ClassB() #实例化ClassB()
print(b.greet())  #打印实例ClassB()的函数greet()
print(b.call_class_a()) #打印实例ClassB()的函数call_class_a()

附加练习

1. 这段代码有一个bug。为什么门锁猜了11次?
原代码:

code = f"{randint(1,9)}{randint(1,9)}{randint(1,9)}" #变量字符串格式化,密码为三个1-9之间的随机整数,包括1和9
        guess = input("[keypad]> ") #猜测密码
        guesses = 0 #猜测次数初始值

        while guess != code and guesses < 10: #while循环,无法确定循环次数时使用while而不是for循环。猜想密码与密码不一致且猜测次数小于10.
            print("BZZZZEDDDD!")
            guesses += 1 #猜测次数不断累加
            guess = input("[keypad]> ") #重新猜测密码

主要原因为:guesses = 0 且while guesses < 10时,while循环将发生10次,0~9。
修改bug为,将guesses =0改为guesses=1。
结果如下:

code = f"{randint(1,9)}{randint(1,9)}{randint(1,9)}" #变量字符串格式化,密码为三个1-9之间的随机整数,包括1和9
        guess = input("[keypad]> ") #猜测密码
        guesses = 1 #猜测次数初始值

        while guess != code and guesses < 10: #while循环,无法确定循环次数时使用while而不是for循环。猜想密码与密码不一致且猜测次数小于10.
            print("BZZZZEDDDD!")
            guesses += 1 #猜测次数不断累加
            guess = input("[keypad]> ") #重新猜测密码

2. 解释一下如何返回next_scene下一个场景。
在每个场景的最后都会通过函数return返回一个字符串,在Map类中有一个字典,存储了场景的键值对,其中字符串为键,对应的对象(类实例化)为值。next_scene()函数通过获取每个场景最后的返回值,即字符串,再调用函数get()获取字典scenes中的对应的值,从而进入该场景(调用该类)。

class Map(object):
    scenes = {
        'central_corridor':CentralCorridor(),
        'laser_weapon_armory':LaserWeaponArmory(),
        'the_bridge': TheBridge(),
        'escape_pod':EscapePod(),
        'death':Death(),
        'finished':Finished()
    } #字典,字符串键对应-子类值
    #初始化函数
    def __init__(self, start_scene):
        self.start_scene =start_scene #定义start_scene

    def next_scene(self, scene_name): #定义next_scene函数,作用:通过获取的场景字符串,得到对应的的字典的值,即子类场景
        val = Map.scenes.get(scene_name) #get()获取字典的值,若值不存在不报错
        return val #返回值

3. 在游戏中添加作弊代码,这样你就可以通过比较难的房间。我可以通过在一行写两个字来实现这一点。
个人是否通过游戏主要和最后renturn的结果有关,可以通过更改return 的值,直接进入下一个场景。
例如,将else后面的return ‘death’ 改为return ‘the_bridge’。

#激光武器库场景
class LaserWeaponArmory(Scene):
    def enter(self):
        print(dedent("""
        You do a dive roll into the Weapon Armory, crouch and scan
        the room for more Gothons that might be hidding. It's dead
        quiet, too quiet. You stand up and run to the far side of
        the room and find the neutron bomb in its container.
        There's a keypad lock on the box and you need the code to 
        get the bomb out. If you get the wrong 10 times then 
        the lock closes forever and you can't get the bomb. The
        code is 3 digits.
        """))  #场景提示
    
        code = f"{randint(1,9)}{randint(1,9)}{randint(1,9)}" #变量字符串格式化,密码为三个1-9之间的随机整数,包括1和9
        guess = input("[keypad]> ") #猜测密码
        # guesses = 0 #猜测次数初始值
        guesses = 1 #修改初始值

        while guess != code and guesses < 10: #while循环,无法确定循环次数时使用while而不是for循环。猜想密码与密码不一致且猜测次数小于10.
            print("BZZZZEDDDD!")
            guesses += 1 #猜测次数不断累加
            guess = input("[keypad]> ") #重新猜测密码

        if guess == code: #如果密码正确
            print(dedent("""
            The container clicks open and the seal breaks, letting
            gas out. You grab the neutron bomb and run as fast as
            you can to the bridge where you must place it in the 
            right spot.
            """)) #打印结果
            return 'the_bridge' #返回值
        else:
            print(dedent("""
            The lock buzzes one last time and then you hear a 
            sickening melting sound as the mechanism is fused
            together. You decide to sit there, and finally the 
            Gothons blow up the ship from their ship and you die.
            """)) 
            return 'the_bridge' #即使输出的结果错误,依旧可以跳到下一个场景,而不是death场景

4. 回到我的描述和分析,然后尝试为这个英雄和他遇到的各种哥特人建立一个小的战斗系统。
暂时不会写,稍微有点难度,可通过更多的练习后完成。

5. 这实际上是“有限状态机”(finite state machine)的一个小版本。读读相关的内容,你可能看不懂,但无论如何都要试一试。
可以参考:https://blog.csdn.net/wangyubin2010n/article/details/118002733
基本概念如下:
有限状态机(Finite State Machine) 缩写为 FSM。以下简称为状态机。
状态机有 3 个组成部分:状态、事件、动作。
状态:所有可能存在的状态。包括当前状态和条件满足后要迁移的状态。
事件:也称为转移条件,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是* 必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值