Python:在__init __

时间:2018-02-25 01:45:48

标签: python text adventure

所以我想做的事情很难在标题中描述。

这就是我想要做的事情: 在下面的代码中,我希望有一些可以在Room类(例如Search,Loot)和Player类(例如quit,heal)上调用的一般方法。我希望这种情况发生的方式是玩家在输入中输入他们想要做的事情,而python将在dict中查找该选项,该选项与方法的选择相匹配。

我已经成功完成了房间出口。我可以通过创建一个子类并在那里列出方法来实现,但我真的不想这样做,因为这看起来很麻烦。

当我运行下面的代码时,它只是自动退出。如果我用第一个字典注释出来运行它,我得到一个错误,说__init __()缺少一个必需的位置参数。

from textwrap import dedent
from sys import exit

class Player(object):


    actions = {
        'QUIT': quit
    }
    def __init__(self, actions):
        self.actions = actions
        # Want actions to be a list of actions like in the Room Class
        # 

    def quit(self):
        # Quits the game
        exit(0)

class Room(object):

    # Description is just a basic room description. No items needed to be added here.
    def __init__(self, desc, exits, exitdesc):
        self.desc = desc
        self.exits = exits
        self.exitdesc = exitdesc
        # Also want list of general actions for a room here.

    def enterroom(self):
        #First print the description of the room
        print(self.desc)
        #Then print the list of exits.
        if len(self.exits) > 1:
            print(f"You see the following exits:")
            for exd in self.exitdesc:
                print(self.exitdesc[exd])
        elif len(self.exits) == 1:
            print(f"There is one exit:")
            for exd in self.exitdesc:
                print(self.exitdesc[exd])
        else:
            print("There are no exits.")
        # Then allow the player to make a choice.
        self.roomactivity()

    # Here's what I mean about calling the methods via a dictionary
    def roomactivity(self):
        while True:
            print("What do you want to do?")
            choice = input("> ").upper()
            if choice in self.exits:
                self.exits[choice].enterroom()

    #And here's where I want to call actions other than directions.
            elif choice in player.actions:
                player.actions[choice]
            else:
                print("I don't understand.")

class VoidRoom(Room):
    def __init__(self):
        super().__init__(
            desc = "ONLY VOID.",
            exits = {},
            exitdesc = {})

class TestRoom(Room):
    def __init__(self):
        super().__init__(
            desc = dedent("""
                This room is only a test room.
                It has pure white walls and a pure white floor.
                Nothing is in it and you can hear faint echoes
                of some mad sounds."""),

            exitdesc = {
                'NORTH': 'To the NORTH is a black door.',
                'SOUTH': 'To the SOUTH is a high window.',
                'EAST': 'To the EAST is a red door.',
                'WEST': 'To the WEST is a blue door.'},
            exits = {
                'NORTH': void_room,
                'SOUTH': void_room,
                'EAST': void_room,
                'WEST': void_room})

void_room = VoidRoom()
test_room = TestRoom()
player = Player()

test_room.enterroom()

我希望我已经清楚地解释了这个问题。还在学习这种语言,我现在可能已经咬过的东西比我现在可以咀嚼的还多。

编辑:新代码:

我已经改变了一些东西,我将播放器命令和内容放在一个单独的py文件中,这样我就可以扩展播放器范围,而不会使rooms.py文件变得混乱。

from textwrap import dedent
from sys import exit
from player import *
from enemies import *

# This is the base class for a room.
class Room(object):

    # Description is just a basic room description. No items needed to be added here.
    def __init__(self, desc, exits, exitdesc, inventory):
        self.desc = desc
        self.exits = exits
        self.exitdesc = exitdesc
        self.inventory = inventory

    def enterroom(self):
        #First print the description of the room
        Player.currentroom = self
        print(self.desc)
        for item in self.inventory:
            print(self.inventory[item].lootdesc)
        #Then print the list of exits.
        if len(self.exits) > 1:
            print(f"You see the following exits:")
            for exd in self.exitdesc:
                print(exd)
        elif len(self.exits) == 1:
            print(f"There is one exit:")
            for exd in self.exitdesc:
                print(exd)
        else:
            print("There are no exits.")
        # Then allow the player to make a choice.
        self.roomactivity()

    def roomactivity(self):
        while True:
            print("What do you want to do?")
            choice = input("> ").upper()
            if choice in self.exits:
                self.exits[choice]().enterroom()
            elif choice in Player.actions:
                Player.actions[choice]()
            else:
                print("I don't understand.")
                #Player.actions[choice]()

class Room3(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                You are in a large, dimly lit room.
                Torches sit in empty alcoves, giving off an eerie red glow.
                You hear scratching and squeaking from behind the walls."""),
            exits = {
                'NORTHEAST': StartRoom
            },
            exitdesc = [
                'A sturdy looking door leads to the NORTHEAST'
            ],
            inventory = {})



class Room1(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                You are in a medium sized, dimly lit room.
                Busts of dead men you don't know sit atop web-strewn pedestals."""),
            exits = {
                'EAST': StartRoom
            },
            exitdesc = [
                'An arch leading into a dimly lit hall lies to the EAST.'
            ],
            inventory = {'IRON SWORD': iron_sword}
        )



class StartRoom(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                PLACEHOLDER LINE 49"""),
            exits = {
                'SOUTHWEST': Room3,
                'WEST': Room1
            },
            exitdesc = [
                'An arch leading into a dimly lit room lies to the WEST',
                'A sturdy looking door lies to the SOUTHWEST'],
            inventory = {}
        )



class HelpPage(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                All actions will be listed in all caps
                When asked for input you may:
                QUIT the game
                Check your INVENTORY
                Check your player STATUS
                SEARCH the room
                EXAMINE an object or point of interest
                USE an item from your inventory or the room
                ATTACK a creature
                GET an item from the room
                or pick a direction (listed in caps)"""),
            exits = {},
            exitdesc = [
                'Press ENTER to return to the Main Menu'],
            inventory = []
            )

    def enterroom(self):
        print(self.desc)
        for exd in self.exitdesc:
            print(exd)
        self.roomactivity()

    def roomactivity(self):
        input()
        MainMenu.enterroom()

help_page = HelpPage()

# Main menu, lil bit different from a regular room
class MainMenu(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                THE DARK DUNGEON OF THE VAMPIRE KNIGHT
                A game by crashonthebeat"""),
            exits = {
                'START': StartRoom,
                'HELP': HelpPage
            },
            exitdesc = [
                'Press START to Start the Game',
                'Or go to the HELP Menu'],
            inventory = []
            )

        def enterroom(self):
            print(self.desc)
            for exd in self.exitdesc:
                print(exd)
            self.roomactivity()

        def roomactivity(self):
            while True:
                choice = input("Choose an Option: ")
                if choice in self.exits:
                    self.exits[choice]().enterroom()
                else:
                    print("I don't understand")

来自player.py的相关代码

from items import *
from rooms import *

class Player(object):

    @property
    def actions(self):
        actions_map = {
            'QUIT': 'quit_',
            'STATUS': 'status',
            'INVENTORY': 'printinventory',
            'EXAMINE': 'examine',
            'USE': 'useitem',
            'SEARCH': 'searchroom',
            'GET': 'getitem',
            'CURRENTROOM': 'getcurrentroom'
        }
        return actions_map

2 个答案:

答案 0 :(得分:0)

一种方法是

class Player(object):


    actions = {
        'QUIT': 'quit'
    }

然后

def roomactivity(self):
    while True:
        [...]
        elif choice in player.actions:
            getattr(player, player.actions[choice])()

答案 1 :(得分:0)

我看到一些潜在的问题:

  1. quit来自Player actions字典?它被表示为某种已知的名称(变量/方法/对象),但是您定义quit的唯一时间是作为Player的方法,因此类属性actions无法访问它。

  2. quit永远不会被调用。例如,当用户输入“QUIT”执行player.actions[choice]时,即使quit确实存在,也只返回它指向的任何函数。它没有调用那个功能。这是不好的。 player.actions[choice]()会帮助你。

  3. 在脚本中定义变量并在类中引用脚本变量是禁忌。可以让你的类方法调用VoidRoom()或TestRoom(),但是让它从一个完全不同的命名空间引用变量test_roomvoid_room,而不是那么多。

  4. 见下面的例子:

    actions = {
            'QUIT': quit
        }
    

    这不会退出您的计划。 “quit”也是python IDLE中的保留字,因此不是方法的最佳选择。 Python约定是在末尾放置一个'_'以避免与保留字冲突:quit_。我会完全删除该属性并使其成为属性,因此您可以在其子代中覆盖它并添加额外的功能。您牺牲了使用自定义操作初始化玩家的能力,但是那些具有相关操作的类不会更有意义吗?

    class Player(object):
        @property
        def actions(self):
            actions_map = {
                'QUIT': self.quit_
            }
            return actions_map
    
        def quit_(self):
            print("Quitting the game.")
            exit(0)
    
    class PlayerThatCanSing(Player):
        @property
        def actions(self):
            default_actions = super().actions # We still want Player actions
            new_actions = {
                'SING': self.sing
            }
            combined_actions = new_actions.update(default_actions) # Now player can quit AND sing
            return combined_actions
    
        def sing(self):
            print("Do Re Ma Fa So La Te Do")
    

    现在引用player.actions['QUIT']()会调用pl​​ayer.quit_,这就是你想要的。

    关于#3:

    class TestRoom(Room):
        def __init__(self):
            super().__init__(
                desc = dedent("""
                    This room is only a test room.
                    It has pure white walls and a pure white floor.
                    Nothing is in it and you can hear faint echoes
                    of some mad sounds."""),
    
                exitdesc = {
                    'NORTH': 'To the NORTH is a black door.',
                    'SOUTH': 'To the SOUTH is a high window.',
                    'EAST': 'To the EAST is a red door.',
                    'WEST': 'To the WEST is a blue door.'},
                exits = {
                    'NORTH': void_room,
                    'SOUTH': void_room,
                    'EAST': void_room,
                    'WEST': void_room})
    
    void_room = VoidRoom()
    test_room = TestRoom()
    player = Player()
    

    您在脚本运行时声明void_roomtest_room,这很好。唯一的问题是你的课程对你的运行时变量一无所知,所以如果你想让North,South,East和West映射到VoidRoom的一个实例(这是一个TestRoom知道的类,因为它就坐在上面它在模块中),直接引用VoidRoom(),而不是void_room。永远不要假设您的课程对该课程之外发生的任何有任何了解,并且没有被传递到该课程的__init__

    我希望带有actions属性的Player示例(在这种情况下只考虑属性作为将函数作为变量引用的方法 - 因为操作返回dict,我们可以将其视为{{{ 1}}没有用actions()调用方法。dict将返回dict,漂亮且可读)是有道理的,因为如果你以这种方式实现它,你可以拥有特定类型的bards继承许多层,调用player.actions(他们的父类)的覆盖操作意味着即使是最具体的DwarfBlacksmithWhoSingsInHisSpareTime类也会一直获取所有父操作(因为每个操作方法都会调用其父操作,并且一直打开它直到它命中玩家),所以你得到一个可以戒掉,唱歌和铁匠的矮人。非常优雅,我希望它不会太混乱,因为它是一个非常酷的概念。祝你好运!