pythonpython-3.xdecision-treefsmdesign-decisions

Why doesn't my character sheet work with input() when trying to choose a race in a text based adventure? python3.x


So this is just the beginning of a long line of questions I know that I am going to have. In this text based adventure I would like to eventually have puzzles and multiple branching paths, factions you can eventually join, choice dialogue that affects the morality of situations(like mass effect or kotor but.. text based-ish), etc., etc., but I feel like the early set up is VERY important for this learning journey. I also would like to eventually convert it over to PYQT5 and maybe eventually host it with a UI on a website I've built for my portfolio. I just wanted to get that out of the way in case you see me on here a lot. PM me with advice for that if you'd like(Because I definitely could use the help from a patron saint!).

Okay, so the problem at hand is:

I have a list of races to choose from:

races = ['Human', 'Dwarf', 'Elf', 'Dragonborn', 'Tiefling', 'Half-Elf']

I would like for it to ask the player to 'Choose a race'. After the player types what they want to play it asks 'Are you sure?' |Here is where I am stuck| If the player says 'yes' it ends the program and I can attempt to continue building this application. If the player types 'no', it doesn't return back to the original question and allow them to answer it again.

So, the things I have tried are defined as different methods:

Character.charRace()
Character.charDict()
Character.charTry()

I think my poor code attempts speak for themselves in terms of what I've been trying.

class Character:

    def charRace():
        raceOptions = ['Human', 'Dwarf', 'Elf', 'Dragonborn', 'Tiefling', 'Half-Elf']
        raceChoice = input(f'Choose a Race: {raceOptions} \n')

        if raceChoice == 'Human':
            res = input(
                """
                Choose Human? 
                (Y   /    N)
                """)

            if res == 'Y':
                print(f'You Chose {raceChoice}!')
            if res == 'N':
                del raceChoice
                raceChoice = input(f'Choose a Race: {raceOptions} \n')
                res = input(
                    """
                    Choose Human? 
                    (Y   /    N)
                    """)

        if raceChoice == 'Dwarf':
            res = input(
                """
                Choose Dwarf? 
                (Y    /    N)
                """)
            if res == 'Y':
                print(f'You Chose {raceChoice}!')
            if res == 'N':
                del raceChoice
                raceChoice = input(f'Choose a Race: {raceOptions} \n')

        if raceChoice == 'Elf':
            res = input(
                """
                Choose Elf? 
                (Y   /    N)
                """)

            if res == 'Y':
                print(f'You Chose {raceChoice}!')
            if res == 'N':
                del raceChoice
                raceChoice = input(f'Choose a Race: {raceOptions} \n')

        if raceChoice == 'Dragonborn':
            res = input(
            """
            Choose Dragonborn?
            (Y    /    N)
            """)

            if res == 'Y':
                print(f'You Chose {raceChoice}!')
            if res == 'N':
                del raceChoice
                raceChoice = input(f'Choose a Race: {raceOptions} \n')

        if raceChoice == 'Tiefling':
            res = input(
            """
            Choose Tiefling?
            (Y    /    N)
            """)

            if res == 'Y':
                print(f'You Chose {raceChoice}!')
            if res == 'N':
                del raceChoice
                raceChoice = input(f'Choose a Race: {raceOptions} \n')

        if raceChoice == 'Half-Elf':
            res = input(
            """
            Choose Half-Elf?
            (Y    /    N)
            """)

            if res == 'Y':
                print(f'You Chose {raceChoice}!')
            while res == 'N':
                del raceChoice
                raceChoice = input(f'Choose a Race: {raceOptions} \n')
                res = input(
                    """
                    Choose Half-Elf?
                    (Y    /    N)
                    """)

        if raceChoice == 'Orc':
            res = input(
                """
                Choose Orc?
                (Y    /    N)
                """)
            while res:
                if res == 'y':
                    print(f'You Chose {raceChoice}!')
                    break
                if res == 'n':
                    del raceChoice
                    raceChoice = input(f'Choose a Race: {raceOptions} \n')
                    res = input(
                        """
                        Choose Orc?
                        (Y    /    N)
                        """)

    def charDict():
        raceOptions = ['Human', 'Dwarf', 'Elf', 'Dragonborn', 'Tiefling', 'Half-Elf']
        raceChoice = input(f'Choose a Race: {raceOptions} \nRace: ')
        if raceChoice == 'Human' or 'human' or 'h':
            print(f'Choose {raceChoice}?\n')
            ans = input()
            if ans != 'Yes' or  'yes' or 'y':
                print(f'You chose {raceChoice}! ')
            elif ans == 'No' or 'no' or 'n':
                return raceChoice
            if raceChoice != 'Human' or 'human' or 'h' or 'Dwarf' or 'dwarf' or 'd' or 'Elf' or 'elf' or 'e' or 'Dragonborn' or 'dragonborn' or 'DB' or 'Tiefling' or 'tiefling' or 't':
                return 'That is not a race that can be chosen at this time!'

    def charTry():
        races = ['Human', 'Dwarf', 'Elf', 'Dragonborn', 'Tiefling', 'Half-Elf']
        res = input(f'Choose a Race: {races}. \nRace: ')
        race = res.capitalize()
        if race in races:
            if race == 'human' or 'Human' or 'h':
                print(f'Do you want to choose {race}? ')

    Character.charRace()
    Character.charDict()
    Character.charTry()

Desired Result Example:

>>> f'Choose a race {races}!:
>>> Human
>>> Do you want to play a Human?
>>> (Y    /    N)
>>> N
>>> Continue to browse...
>>> Choose a race: Human, Dwarf, Elf, Dragonborn, Tiefling, Half-Elf
>>> Dwarf
>>> Do want to play a Dwarf?
>>> Y
>>> You have chosen to play a Dwarf!

I've tried a few different methods to acquire the desired result but they don't seem to work. Should I build a finite state machine? How would I do that? What is the best method for longevity and making the code modular for future update?


Solution

  • What you are try to do is to build a menu, where the user may make choices and confirm and retry their choices as often as necessary.

    The way to do this is with an infinite while loop. Essentially, you just want to keep repeating the same set of options until the user makes a selection, or quits.

    Also, try to keep your code indifferent to the particular selection that the user makes. We care that they select an item from the list; we don't need to care which item, as long as we have some way of retrieving it when necessary. In the following code, note that there is no explicit mention of the individual races except in the original list.

    class Character:                                                                                                                                                                                                                                                                                
    
        RACES = ['Human', 'Dwarf', 'Elf', 'Dragonborn', 'Tiefling', 'Half-Elf']                                                                                      
    
        def choose(self):
            # list choices as (0) Human, (1) Dwarf etc                                                                                                                                                                                                                                                                             
            choices = ', '.join([f'({i}) {race}' for i, race in enumerate(self.RACES)])    
            # Loop forever!                                                                          
            while True:                                                                                                                                              
                choice = input(f'Choose a race: {choices} ')                                                                                                         
                choice = choice.upper()                                                                                                                              
                if choice == 'Q':                                                                                                                                    
                    print('Bye!')  
                    # Break out of the loop                                                                                                                                  
                    break                                                                                                                                            
                elif not(choice.isdigit()):                                                                                                                          
                    # Not a number                                                                                                                                   
                    print('Sorry, please choose a number')                                                                                                                       
                elif not 0 <= int(choice) <= len(self.RACES):                                                                                                        
                    # Number outside the range of choices                                                                                                            
                    print('Sorry, please choose again')                                                                                                                                                                                                                                        
                else:   
                    # The number input by the user matches the position
                    # of their choice in the list of races                                                                                                                                             
                    selection = self.RACES[int(choice)]                                                                                                              
                    confirm = input(f'You chose {selection} - confirm (Y/N)? ')                                                                                      
                    if confirm.upper() == 'Y':                                                                                                                       
                        print(f'Confirmed - you\'re a {selection}!')
                        # Break out of the loop                                                                                                 
                        break                                                                                                                                        
                    else:                                                                                                                                            
                        print('OK, let\'s try again')                                                                                                                                                                                                                                                   
            return