pythoncsvtext-based

Text-Based RPG Python Bug


i'm new to python and am trying to make a text-based RPG using VScode. I keep running into this bug and i'm not sure what is causing it, please help me :O

Here is the code:

from csv import reader

def import_csv_layout(path):
    terrain_map = []
    with open(path) as level_map:
        layout = reader(level_map,delimiter = ',')
        for row in layout:
            terrain_map.append(list(row))
        return terrain_map

coord_y,coord_x = 5,3

active_map = 1

map_1 = import_csv_layout('map-1.csv')

inspectable_objects = []
print(inspectable_objects)
inventory = []

w_inventory = None
picked = [False,False]

def inspect_object(subject):
    if active_map == 1:
        if subject == 'beach':
            print('the beach is made of soft, white, glistening sand')
        elif subject == 'grassland':
            print('the grassland is made of lucious, green grass, still wet from the morning dew')
        elif subject == 'ocean':
            print("the ocean glistens in the sun, and is slightly warm on top, but cool by the sea bed")
        elif subject == 'forest':
            print("the forest is birch, with dappled sunlight projected on the dirt floor, You can see berry bushes dotted on it")
            inspectable_objects = ['berry bushes','trees']
        elif subject == 'berry bushes':
            print('the berry bushes have dark green leaves, and are laden with juicy red berries')
            inspectable_objects = ['berries','leaves']
        elif subject == 'berries':
            if picked[0] == False:
                if input('the berries are juicy and bright red, would you like to pick them?') == 'yes':
                    print('you have picked the berries')
                    inventory.extend(('berry', 'berry', 'berry', 'berry', 'berry'))
                    picked[0]=True
                else:
                    print("you dont pick the berries")
            else:
                print("you have already picked the berries")

            inspectable_objects = []
        elif subject == 'leaves':
            if picked[1] == False:
                print("the leaves are dark green, pointed and have a medicinal odour")
                if input("pick them?\n") == 'yes':
                    print("you pick the leaves")
                    inspectable_objects = ['berries']
                    inventory.extend(['medicinal leaf','medicinal leaf','medicinal leaf','medicinal leaf','medicinal leaf'])
                    picked[1] = True
                else:
                    print("you do not pick the leaves")
            else: 
                print("you have already picked the leaves")
        elif subject in ['trees','birch trees']:    
            if (coord_y,coord_x == 5,3):
                print("the birch trees vary in shape and size, but they all have silver bark and oval shaped leaves, all except for the one nearest to you, which is oak")
                inspectable_objects = ['tree','oak tree','oak']
            else:
                print("the birch trees vary in shape and size, but they all have silver bark and oval shaped leaves")
        elif subject in ['tree', 'oak tree', 'oak']:
                print("the oak tree has dark brown bark and has a yellow note nailed to it: you dont know how you didn't see it before")
                inspectable_objects = ['yellow note', 'note']
        elif subject in ['yellow note', 'note']:
            print('the yellow note reads: follow the forest east, then search the sand for the chest')
            inspectable_objects = []

        else:
            print("you dont pick the berries")
        
        print(inspectable_objects,0)

def play(command):
    global coord_y, coord_x, map_1, inspectable_objects, inventory

    if (command == 'move'):
        direction = str(input("Enter Direction\n"))

        if (direction == 'north'):
            coord_y -= 1
            print(f"You have moved {direction}")
        elif (direction == 'south'):
            coord_y += 1
            print(f"You have moved {direction}")
        elif (direction == 'east'):
            coord_x += 1
            print(f"You have moved {direction}")
        elif (direction == 'west'):
            coord_x -= 1
            print(f"You have moved {direction}")
        else:
            print("Error - Please enter north, east, south or west as a direction")
    
    elif (command == 'inspect'):
        print(inspectable_objects,1)
        subject = input("What/Where would you like to inspect\n")

        if subject in ['north','south','east','west','here']:

            # inspect tile
            if subject == 'here':
                i_y_pos, i_x_pos = coord_y, coord_x
            elif subject == 'north':
                i_y_pos, i_x_pos = coord_y - 1, coord_x
            elif subject == 'south':
                i_y_pos, i_x_pos = coord_y + 1, coord_x
            elif subject == 'east':
                i_y_pos, i_x_pos = coord_y, coord_x + 1
            elif subject == 'west':
                i_y_pos, i_x_pos = coord_y, coord_x - 1


            if int(map_1[i_y_pos][i_x_pos]) == 2: terrain = 'ocean'
            elif int(map_1[i_y_pos][i_x_pos]) == 1: terrain = 'beach'
            elif int(map_1[i_y_pos][i_x_pos]) == 4: terrain = 'grassland'
            elif int(map_1[i_y_pos][i_x_pos]) == 3: terrain = 'forest'
            elif int(map_1[i_y_pos][i_x_pos]) == 16: terrain = 'mountainous area'
            elif int(map_1[i_y_pos][i_x_pos]) == 0: terrain = 'boulder'
            elif int(map_1[i_y_pos][i_x_pos]) == -1: terrain = 'place that is outside the map'
            else: terrain = 'unrecognised terrain'

            if terrain[0] in ['a','e','i','o','u']:
                start_vowel = True
            else:
                start_vowel = False
    
            if subject == 'here':
                if start_vowel: print(f"you are in an {terrain}")
                else: print(f"you are in a {terrain}")
            elif subject == 'north':
                if start_vowel: print(f"north of you is an {terrain}")
                else: print(f"north of you is a {terrain}")
            elif subject == 'south':
                if start_vowel: print(f"south of you is an {terrain}")
                else: print(f"south of you is a {terrain}")
            elif subject == 'east':
                if start_vowel: print(f"east of you is an {terrain}")
                else: print(f"east of you is a {terrain}")
            elif subject == 'west':
                if start_vowel: print(f"west of you is an {terrain}")
                else: print(f"west of you is a {terrain}")
            
            print(0)
            inspectable_objects = [terrain]
            print(1)

        elif subject in inspectable_objects:
            inspect_object(subject)

        elif subject == 'inventory':
            if inventory == []:
                w_inventory = 'nothing'
            else:
                w_inventory = inventory
            
            print(f"your inventory contains {w_inventory}")

        else:
            print("error - please enter 'here', 'north', 'south', 'east', 'west', or an inspectable object\n")
    
    elif (command == 'help'):
        print("Hello, in this game, you must write commands to manipulate the world. The main commands are 'move', 'inspect', ''")
    
    else: 
        print("Error - That is not recognised as a command, type 'help' as a command to receive a list of commands")

    command,subject,start_vowel,direction = None, None, None, None

while True:
    play(input("Present Command\n"))


and here's what to enter to encounter the error:

[]
Present Command
inspect
[] 1
What/Where would you like to inspect
here
you are in a forest
0
1
Present Command
inspect
['forest'] 1
What/Where would you like to inspect
forest
the forest is birch, with dappled sunlight projected on the dirt floor, You can see berry bushes dotted on it
['berry bushes', 'trees'] 0
Present Command
inspect
['forest'] 1
What/Where would you like to inspect

Right there, where it says ['forest'], it should say ['berry bushes', 'trees'], as it does above.

I added in a bunch of debugging lines, so it doesn't normally have all the numbers and lists printed: they were just to help me figure out what was going on.

It seems that somewhere between the end of inspect_object() and the elif (command == 'inspect'): part of play(), the list inspectable_objects (which is causing all the issues) is reset to ['forest'].

Also, I tried running the code in a different IDE, and it came up with the same bug, so I know VScode isn't the problem

Please try to help if you can, but don't worry if you can't.

Thanks :)


Solution

  • Your issue is due to a misunderstanding of variable scope. Specifically, the changes you think you're applying to your global list inspectable_objects inside of the inspect_object function actually do not affect your global list. See this example:

    some_list = [1, 2, 3]
    
    def change_the_list():
        some_list = [4, 5, 6]
        print(f'I changed some_list to {some_list}')
    
    print(f'some_list is {some_list}')
    change_the_list()
    print(f'some_list is {some_list}')
    

    Output:

    some_list is [1, 2, 3]
    I changed some_list to [4, 5, 6]
    some_list is [1, 2, 3]
    

    All you're doing inside inspect_object is creating a local list variable that happens to have the same identifier as your global list variable. You bind that local list variable to some other list object, which has no effect on your global list variable, and then the function terminates and the local list variable goes out of scope.

    To get this to behave the way you want, you'll want to use the global keyword inside the inspect_object function, indicating to Python that all references to inspectable_objects within this scope shall refer to the global variable:

    def inspect_object(subject):
        global inspectable_objects
        if active_map == 1:
            # ...
    

    The real solution, however, would be to avoid globals in the first place.