Python Forum
Tutorial for making a "choose a path" game
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tutorial for making a "choose a path" game
#1
First off, when making one of these, I think that the player should be able to choose which game they want to play. I think the games should be displayed with info so the player can choose which one they want to play. The easiest way to do this would be to make a dictionary for each game. For example -
Game1dict = {'Character Name' : 'James',
         'Character age' : '16',
         'Gender' : 'Boy',
         'Personality' : 'Prideful, Arrogant, Understanding, Thoughtful',
         'Extra' : 'Gamer, Volunteers at local charity',
         'Current Ally' : 'Best friend, Luke',
         'Ally Name' : 'Luke',
         'Ally age' : '15',
         'Ally Gender' : 'Boy',
         'Ally Personality' : 'Nerdy, Hard Working, Laid Back',
         'Ally Extra' : 'Chore Boy, Braces, Always carries a computer, Borrows grandmas glasses',
         'Background' : 'Your house is seen on fire from the TV in Luke\'s house. you rush home as fast as you can, only to find... your house perfectly intact. You must have mistaken another house for yours. Your house may not be on fire but something is different. Your mom has left a note and is not home. The note reads - \n        Come to Billy\'s Burritos at 3:00 A.M. or I\'ll have to kill your mom. \n        P.S. Bring me money to buy a burrito'
         }
Here I made a dictionary which holds all the data on the first game. I can later use this dictionary to display the data, rather than typing the whole print module every time. If you don't understand that, you will later. For this game we need at least 3 functions. Of course main, then two others. I made main get which game they want to play and then execute another function based on which one they want to play. If they want to play game 1, I execute the Game1 function rather than keeping the choices for the story in main. The third function is a decide function. This is for the decisions. This makes the code less bulgy in the Game1 function. So far, for functions, we have this -
def decide():
    pass

def main():
    pass

def Game1():
    pass
For main we need to find out which game they want to play. Doing this is simple and goes as follows -
def Main():
    print('Welcome to PathLithe. This game consists of different games (Currently 1 game). Typing "items" will give you a list of your current items during the game. Hope you enjoy!\n')
    GameDict = Game1dict
    print(f'Game 1 -\n\n    Main Character Bio - \n    Character Name: {GameDict["Character Name"]}\n    Character age: {GameDict["Character age"]}\n    Gender: {GameDict["Gender"]}\n    Description - \n        Personality: {GameDict["Personality"]}\n        Extra: {GameDict["Extra"]}\n    Current Ally: {GameDict["Current Ally"]}\n\n    {GameDict["Ally Name"]} Bio - \n        Character age: {GameDict["Ally age"]}\n        Gender: {GameDict["Ally Gender"]}\n        Description - \n           Personality: {GameDict["Ally Personality"]}\n           Extra: {GameDict["Ally Extra"]}\n\n    Background: {GameDict["Background"]}')
    while True:
        gameMode = input('\nType the number of the game you would like to play - ')
        try:
            if int(gameMode) == 1:
                Game1()
                break
            else:
                print('Game mode chosen is out of range')
        except:
            print('Your answer was invalid, please use a number for your answer')
Now allow me to explain everything here. First we have an introduction. Then we have a GameDict variable. The print function will refer to whichever dictionary the GameDict points to. Now we can copy paste the print function for every game we have, and just change the dictionary of GameDict before printing again. Next the while True is to keep repeating until they answer with a valid answer. The try and except is to get no errors if they don't answer with a number. gameMode tell us what game they want to play. We can then use gameMode to decide which function to execute. If they put 1 it will execute the Game1 Function.
Next up is the decide function. The decide function should look like this -
def decide(choice1, choice2, output1, output2):
    print('\n - ' + choice1 + '\n\nor\n')
    print(' - ' + choice2 + '\n')
    while True:
        decision = input('Choose a path (1 or 2) \n')
        if decision == '1' or decision == '2':
            break
        elif decision.lower() == 'items':
            print()
            for x in Items:
                print(' - ' + x)
            print()
        else:
            print('Please use a number for your answer')
    if decision == '1':
        print(output1)
        return 1
    else:
        print(output2)
        return 2
Here is how it works. The parameters are the two choices of the character (Can be more than two choices if you wish) and then the two outputs for there decisions. First the choices are printed with a few modifications - "\n" and "-" - for order. Then again the while True and try are for the same reasons as main. Then we store there answer in decision. If it is one, we print the output1 and if not, meaning it is 2, we print output2. I also have something else there to print the items they have. If they type items it prints a list I made called "Items". The list can be appended to throughout the story. Finally we will need to return the number path player chose for use in our Game function.

For the Game1 function we can use the decide function because we have already given a Background, but you can also print something before having them make a decision.

The Game1 function may start by looking mike this -
def Game1():
    num = decide('I don\'t care about my mom', 'I must go find my mom', 'You sit at home for the next few hours playing video games', 'You\'ve decided you need to rescue your mom')
    if num == 1:
        #Don't save mom
        pass
    else:
        #Save mom
        pass
In the making of this game you will find yourself making one path while still having others unmade. It helps to hash a note for what happens, then you know what to put.

Eventually you ma end up with something like this (The current progress on mine)-
import sys, time

Game1dict = {'Character Name' : 'James',
         'Character age' : '16',
         'Gender' : 'Boy',
         'Personality' : 'Prideful, Arrogant, Understanding, Thoughtful',
         'Extra' : 'Gamer, Volunteers at local charity',
         'Current Ally' : 'Best friend, Luke',
         'Ally Name' : 'Luke',
         'Ally age' : '15',
         'Ally Gender' : 'Boy',
         'Ally Personality' : 'Nerdy, Hard Working, Laid Back',
         'Ally Extra' : 'Chore Boy, Braces, Always carries a computer, Borrows grandmas glasses',
         'Background' : 'Your house is seen on fire from the TV in Luke\'s house. you rush home as fast as you can, only to find... your house perfectly intact. You must have mistaken another house for yours. Your house may not be on fire but something is different. Your mom has left a note and is not home. The note reads - \n        Come to Billy\'s Burritos at 3:00 A.M. or I\'ll have to kill your mom. \n        P.S. Bring me money to buy a burrito'
         }

Items = []

def decide(choice1, choice2, output1, output2):
    print('\n - ' + choice1 + '\n\nor\n')
    print(' - ' + choice2 + '\n')
    while True:
        decision = input('Choose a path (1 or 2) \n')
        if decision == '1' or decision == '2':
            break
        elif decision.lower() == 'items':
            print()
            for x in Items:
                print(' - ' + x)
            print()
        else:
            print('Please use a number for your answer')
    if decision == '1':
        print(output1)
        return 1
    else:
        print(output2)
        return 2

def Main():
    print('Welcome to PathLithe. This game consists of different games (Currently 1 game). Typing "items" will give you a list of your current items during the game. Hope you enjoy!\n')
    GameDict = Game1dict
    print(f'Game 1 -\n\n    Main Character Bio - \n    Character Name: {GameDict["Character Name"]}\n    Character age: {GameDict["Character age"]}\n    Gender: {GameDict["Gender"]}\n    Description - \n        Personality: {GameDict["Personality"]}\n        Extra: {GameDict["Extra"]}\n    Current Ally: {GameDict["Current Ally"]}\n\n    {GameDict["Ally Name"]} Bio - \n        Character age: {GameDict["Ally age"]}\n        Gender: {GameDict["Ally Gender"]}\n        Description - \n           Personality: {GameDict["Ally Personality"]}\n           Extra: {GameDict["Ally Extra"]}\n\n    Background: {GameDict["Background"]}')
    while True:
        gameMode = input('\nType the number of the game you would like to play - ')
        try:
            if int(gameMode) == 1:
                Game1()
                break
            else:
                print('Game mode chosen is out of range')
        except:
            print('Your answer was invalid, please use a number for your answer')
    
def Game1():
    num = decide('I don\'t care about my mom', 'I must go find my mom', 'You sit at home for the next few hours playing video games', 'You\'ve decided you need to rescure your mom')
    if num == 1:
        #Not saving mom
        print('You\'ve decided it\'s not worth it for your mom')
        num = decide('Mom isn\'t here , I can stay up', 'i should go to sleep', '', '')
        if num == 1:
            #Stay up
            print('You stay up on video games, until you hear a knock on the door')
            num = decide('I guess I should answer the door', 'I shouldn\'t answer the door', 'You walk down stairs and open the door...', 'You stay where you are listening for any more knocks')
            if num == 1:
                #Answer door
                print('to be stabbed in the chest')
            else:
                #Don't answer the door
                print('Then you hear another knock, even louder. Suddenly they are banging on the door')
                num = decide('Fine I\'ll answer the door', 'I should call 911', 'You answer the door to...', 'You pick up your phone and call 911')
                if num == 1:
                    #Finally answer door
                    print('an angry man who pins you down and stabs you ferociously')
                else:
                    #Call 911
                    print('"911 what\'s your emergency" comes from the phone')
                    num = decide('Give your address', 'Give the emergency', 'You tell them your adress...', 'You tell them the emergency...')
                    if num == 1:
                        #Give your address
                        print('but you\'re dragged away from the phone')
                        num = decide('Fight back', 'Don\'t resist', 'You try to resist but get silenced by a knife', 'You allow yourself to get dragged...')
                        if num == 2:
                            print('and find yourself in the kitchen. You are slowly stabbed and feel your concious ebbing away')
                            time.sleep(3)
                            print('You awake in a hospital bed with an iv')
                            print('The news is then broke to you that your mom is dead. Atleast, thanks to you, the murderer has been caught and sentenced to jail for 32 years with parole')
                    else:
                        #Give the emergency
                        print('but don\'t get a chance to tell them your address as you\'re pulled back and muted by the intruder')
                        num = decide('Fight back', 'Don\'t resist', 'You try to resist but get silenced by a knife', 'You allow yourself to get dragged...')
                        if num == 2:
                            print('but then get slowly stabbed to death')
        else:
            #Go to sleep
            print('You never woke up again')
    else:
        #Saving mom
        print('You walk through the house thinking...')
        num = decide('I should leave now, theres no telling what could happen', 'I still have time to plan this out', 'Alright!, let\'s go', 'Alright! I need paper...')
        if num == 1:
            #Leave now
            pass
        else:
            #Plan it out
            print('You find paper in the printer to use, and a pen in a drawer (You aquired two items)')
            Items.append('Paper')
            Items.append('Pen')
            num = decide('Should I do what he says', 'Maybe I should be a hero', 'Let\'s get a snack and a phone (Two items aquired)', 'Let\'s get lots of supplies')
            if num == 1:
                #Get snack and phone (Follow note)
                print('After grabbing those few things, you leave for Billy\'s Burritos, but should you walk or drive')
                Items.append('Snack')
                Items.append('Phone')
                num = decide('I should drive my car', 'I\'ll just walk there', 'You\'ve decided driving is the best options', 'Walking may turn out for the better, you think')
                if num == 1:
                    #Drive car
                    print('You start up the car and start the drive to Billy\'s Burritos')
                    num = decision('', '', '', '')
                else:
                    #Walk
                    pass
                    
            else:
                #Try to be hero (Getting lots of supplies)
                pass

Main()
sys.exit()
Hope my tutorial was helpful!
Reply
#2
You should check out my tutorial on text games. It talks about how creating a text adventure (like Zork) with an if-then structure (like your choose your own adventure) leads to problems down the line, and how text adventures can be done more easily by moving the if-then structure into data. The same holds true for the choose your own adventure situation.

Here's an example I wrote, based on Monty Python's argument sketch:

ARGUMENT = {'start': {'text': "You start the argument by noting that Star Wars is fantasy, not science-fiction. John replies that, no, it isn't",
        'choices': [('Yes it is.', 'yes-is'), ('Point out that Star Wars is just swords and sorcery.', 'yes-is')]},
    'yes-is': {'text': "John replies that, no, it isn't.",
        'choices': [('Yes it is.', 'yes-is'), ("Point out that's not actually arguing.", 'not-argue')]},
    'not-argue': {'text': "You point out that an argument is not the needless gainsaying of whatever is said to you. John replies that, yes, it is.",
        'choices': [("No it isn't", 'no-is'), ("Point out that he's doing it again.", 'again')]},
    'no-is': {'text': "John replies that, yes, it is.",
        'choices': [("No it isn't", 'no-is'), ("Point out that he's doing it again.", 'again')]},
    'again': {'text': "You point out that John is just needlessly gainsaying again. He replies that no, he isn't",
        'choices': [('Yes you are!', 'yes-are'), ("Point out that he's doing it again.", 'the-end')]},
    'yes-are': {'text': "John replies that, no, he isn't.",
        'choices': [('Yes you are!', 'yes-are'), ("Point out that he's doing it again.", 'the-end')]},
    'the-end': {'text': "Ding! I'm sorry, time's up."}}

def choose(choices):
    print('\nChoose one:')
    for choice_index, choice in enumerate(choices, start = 1):
        print('{}: {}'.format(choice_index, choice[0]))
    while True:
        choice = input('\nWhat is your choice? ')
        try:
            return choices[int(choice) - 1][1]
        except (IndexError, ValueError):
            print('That is not a valid choice.')

def play(adventure):
    page_name = 'start'
    while not page_name.endswith('-end'):
        page = adventure[page_name]
        print('')
        print(page['text'])
        page_name = choose(page['choices'])
    print('')
    print(adventure[page_name]['text'])
    print('\nThanks for playing!')

if __name__ == '__main__':
    play(ARGUMENT)
Our adventure is the ARGUMENT dictionary. The keys are the names of pages (this is just an internal identifier). The values are a 'page' dictionary. Each page dictionary contains the text of the page and the choices at the end of the page. The choices are done as list of tuples, each tuple containing the text of the choice displayed to the user, and the name of the page to go to if they make that choice.

I'm not sure I explained that clearly, so lets walk through the code. First we have the play function. It sets the page_name to 'start', a special page for the start of the adventure. Then it has a while loop that goes until you get to a page ending with '-end', another special type of page for an end to the adventure. Each time through the loop, it gets the game from the adventure provided, prints the text for that page, and then gets the next page_name from the choose function, using the current page's choices.

The choice function prints the text for each with a number for that choice. Then it gets a choice from the user, and tries to use that as an index to the list of choices to return the page name associated with that choice. It keeps asking until it gets a valid choice, using try/except to catch invalid answers.

Note that the data driven code is much simpler than the if/then driven code. That makes it less likely to have bugs, easier to maintain, and easier to expand with new features. This is also aided by having less repetition in the code. Also note that it is more flexible. There are loops in my adventure, where you can visit the same page more than once. That's very hard to implement in an if then structure. This code is also not limited in the number of choices you have. You could give them three, four, or even one choice. No choices would be a problem that would put you in an infinite loop.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Ursina Engine] Ursina Engine – 3D Python Game Engine Tutorial MK_CodingSpace 0 5,780 Feb-10-2021, 03:16 AM
Last Post: MK_CodingSpace

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020