python: local variable referenced before assignment error - python

I am completing a text based game for an intro to python class. It is not complete but I was working on the main_menu function and the functions called within the main_menu function when I ran into this error message. I have encountered this error several times in my learning experience and it was usually attributed to a basic mistake when assigning variables, but this one has me stumped...
This is the script in question (lines in traceback commented in BOLD):
import random
from sys import exit
# Item variables
coal = ('Coal', 'some coal which can be used in a furnace.')
eng_key = ('Key', 'a key to a house.')
bomb = ('Bomb', 'a combustible device which creates a powerfull explosion. Possibly used for demolition...')
tonic = ('Tonic', 'a weak healing tonic. Adds \'5\' health points.')
sTonic = ('Super Tonic', 'a strong healing tonic. Adds \'10\' health points.')
# LOCATIONS
# Below are the possible locations you can 'travel' to, along with a title (first item in tuple), a description, any items that might be found in the location which can be discovered and entered into 'inventory' through 'search' command
# location variable = (title, description, item for discovery)
sub_base = ('Sub-Base', 'This is DeepBlue\'s base of operations in the Atlantis excavation zone. Your submarine is docked ahead', 'nothing useful here.')
cave = ('Underwater Cave', 'You have entered the mouth of an underwater cave with your sub.', 'nothing useful here.')
cemetery = ('Cemetery Chamber', 'You are in a large chamber within the cave. This seems to be a cemetery. There are symmetrically lined mounds of dirt, with obelisks at the head.', 'nothing useful here.')
city_gate = ('City Gate', 'You stand at a crossroad of sorts, at the bottom of an upward sloping ramp.', 'nothing useful here.')
city_outskirts = ('City Outskirts', 'You find yourself just outside the city walls.', 'nothing useful here.')
castle_outskirts = ('Rear of Castle Ruins', 'You are standing at the rear of the castle ruins. There is a layer of rubble blocking the way, but you can clearly see a passage leading inside. Perhaps you can devise a way to move it...', 'nothing useful here.')
castle_inside = ('Inside the Grand Castle of Atlantis', 'You have made it inside of the castle. All the advanced knowledge of the Atlanteans is at your disposal.', 'nothing useful here.')
city_block0 = ('Beginning of Main Avenue in City', 'You are standing at the beginning of the main avenue of the city.', 'nothing useful here.')
ruins1 = ('Rubble of Dilapidated House', 'You are standing in the middle of the ruins of what seems to have been a house.', tonic)
mystic_house = ('Mystic House', 'You are standing inside the city Mystic\'s house.', sTonic)
city_block1 = ('Second Block in City', 'You have moved to the second block of the city\'s main avenue.', 'nothing useful here.')
abandoned_house = ('Abandoned House', 'You are standing in the middle of an abandoned house.', eng_key)
blacksmith_house = ('Blacksmith\'s House', 'You are standing in what seems to be a blacksmith\'s building. There is a furnace, iron ore, smith\'s tools and various components for making swords. No coal though...', 'nothing useful here. But with the right items, something can be created here...')
city_block2 = ('Third Block in City', 'You have moved to the third block of the city\'s main avenue.', 'nothing useful here.')
marketplace = ('Abandoned Marketplace', 'You are standing in the middle of an abandoned marketplace. There might be some useful items laying around...', coal)
engineer_house = ('Engineer\'s House', 'You are standing in the engineer\'s house. There might be some useful items lying around...', bomb)
castle_main = ('Castle Main Entrance', 'You are standing in front of the main entrance of a huge castle. The grand entrance is blocked off by massive amounts of rubble. There must be another way in...', 'nothing useful here.')
# ITEMS
# below are the items which may be added to the inventory
items = {
coal: (engineer_house,),
eng_key: (engineer_house,),
bomb: (castle_inside,),
tonic: ('anywhere',),
sTonic: ('anywhere',)
}
# INTERACTIONS(location-based)
# below is a dictionary of events. Each location has certain events which can only take place there.
# interactions dictionary = {location: (use+item response, search response)}
lEvents = {sub_base: (cave,),
cave: (sub_base, cemetery, city_gate),
cemetery: (cave, city_outskirts),
city_gate: (cave, city_outskirts, city_block0),
city_outskirts: (cemetery, castle_outskirts, city_gate),
castle_outskirts: (city_outskirts,castle_inside),
castle_inside: (castle_outskirts,),
city_block0: (city_gate, ruins1, mystic_house, city_block1),
ruins1: (city_block0,),
mystic_house: (city_block0,),
city_block1: (city_block0, abandoned_house, blacksmith_house, city_block2),
abandoned_house: (city_block1,),
blacksmith_house: (city_block1,),
city_block2: (city_block1, marketplace, engineer_house, castle_main),
marketplace: (city_block2,),
engineer_house: (city_block2,),
castle_main: (city_block2,)
}
# TRAVEL OPTIONS
# Below is a dictionary outlining the possible places to travel to depending on where you are currently located, this peice is essential to the travel function
travelOpt = {
sub_base: (cave,),
cave: (sub_base, cemetery, city_gate),
cemetery: (cave, city_outskirts),
city_gate: (cave, city_outskirts, city_block0),
city_outskirts: (cemetery, castle_outskirts, city_gate),
castle_outskirts: (city_outskirts,castle_inside),
castle_inside: (castle_outskirts,),
city_block0: (city_gate, ruins1, mystic_house, city_block1),
ruins1: (city_block0,),
mystic_house: (city_block0,),
city_block1: (city_block0, abandoned_house, blacksmith_house, city_block2),
abandoned_house: (city_block1,),
blacksmith_house: (city_block1,),
city_block2: (city_block1, marketplace, engineer_house, castle_main),
marketplace: (city_block2,),
engineer_house: (city_block2,),
castle_main: (city_block2,)
}
def eHouseAccess(action, location, eHouse):
if eHouse == 'locked':
print "The door is locked! You need to find a key for this door."
travel(location)
else:
location = travelOpt[location][action - 1]
travel(location)
def cInsideAccess(action, location, cInside):
if cInside == 'blocked':
print "The path is blocked by rubble! You need to find a way to clear the rubble."
travel(location)
else:
location = travelOpt[location][action - 1]
travel(location)
def travel(location):
while True:
print "You are in the", location[0]+"."
print location[1]
print 'You can travel to:'
for (i, t) in enumerate(travelOpt[location]):
print i + 1, t[0]
action = raw_input("Pick a destination, or enter 'menu' for the main menu: ")
if action == 'menu':
main_menu(location, inventory, items)
else:
action = int(action)
if travelOpt[location][action - 1] == engineer_house:
eHouseAccess(action, location, eHouse)
elif travelOpt[location][action - 1] == castle_inside:
cInsideAccess(action, location, cInside)
else:
location = travelOpt[location][action - 1]
def main_menu(location, inventory, items):
travel = travel(location) # **this is line 133**
invtry = showInv(inventory)
use = use(items, inventory)
quit = exit(0)
while True:
print "You are in the", location[0]
menu_list = [('Travel', travel), ('Inventory', invtry), ('Use', use), ('Search', search), ('Map', map), ('Quit', quit)]
print "Choose one:"
for (num, t) in enumerate(menu_list):
print num + 1, t[0]
main_choice = int(raw_input("> "))
action = menu_list[main_choice - 1]
action[1]
def search(location):
pass
def map(location):
pass
def showInv(inventory):
if inventory == []:
print "Your inventory is empty"
inv = 'empty'
return inv
else:
for (num, i) in enumerate(inventory):
print num + 1, i
inv = inventory
return inv
def use(items, inventory):
a = showInv(inventory)
if a == 'empty':
print "There is nothing to use."
else:
showInv(inventory)
uItem = int(raw_input("Choose an item to use: "))
location = sub_base
inventory = []
eHouse = 'locked'
cInside = 'blocked'
hp = 20
map = """
Key:
* = indicates a point of entry
______ ______
|Castle|Castle|
|Outsk-| |
|irts |
___|**____|__**__|
| City | | |
|Outsk-| | City |
| irts | | |
_____|*____*|___|*_____|
| | | |
| Grave | | City |
| Yard | | Gates |
|_____**|__|*______|
| |
| Cave |
| |
|__**___|
| |
| Sub- |
| Base |
|_______|
"""
cityMap = """
Key:
* = indicates a point of entry
________
| |
| Castle |
| |
______|___**___|________
| | City | Engin- |
|Market| Block | eer |
|Place * 3 * House |
|______|___ ___|________|
|Aband-| City | Black- |
| oned | Block | smith |
|House * 2 * House |
|______|___**___|________|
| | City | |
|Rubble| Block |Mystic's|
| * 1 * House |
|______|________|________|
"""
name = raw_input("Enter your name: ")
print "Welcome to the Atlantis Excavation Zone, %s." % name
print "Your first day on the job and we already have a new cave for you to map... LUCKY!"
print "The DeepBlue team takes you down to the sub base. Time to get to work."
main_menu(location, inventory, items) # **this is line 236**
And here is the traceback:
Traceback (most recent call last):
File "ex36_2.py", line 236, in <module>
main_menu(location, inventory, items)
File "ex36_2.py", line 133, in main_menu
travel = travel(location)
UnboundLocalError: local variable 'travel' referenced before assignment
I thought the variable had been assigned in line 133. What am I missing here?

The first line
travel = travel(location)
implicitly marks the name travel as local for the whole function. All look-ups for this name look for a local name, including the one on the right-hand side of the cited line. At that time, there is no value assigned to the local name, though, hence the error. There might be a global name travel, but since the compiler identified travel as a local name, it will only look in the local namespace. Use a different name for the local variable.

Related

How do I combine elements from two loops without issues?

When I execute this code...
from bs4 import BeautifulSoup
with open("games.html", "r") as page:
doc = BeautifulSoup(page, "html.parser")
titles = doc.select("a.title")
prices = doc.select("span.price-inner")
for game_soup in doc.find_all("div", {"class": "game-options-wrapper"}):
game_ids = (game_soup.button.get("data-game-id"))
for title, price_official, price_lowest in zip(titles, prices[::2], prices[1::2]):
print(title.text + ',' + str(price_official.text.replace('$', '').replace('~', '')) + ',' + str(
price_lowest.text.replace('$', '').replace('~', '')))
The output is...
153356
80011
130187
119003
73502
156474
96592
154207
155123
152790
165013
110837
Call of Duty: Modern Warfare II (2022),69.99,77.05
Red Dead Redemption 2,14.85,13.79
God of War,28.12,22.03
ELDEN RING,50.36,48.10
Cyberpunk 2077,29.99,28.63
EA SPORTS FIFA 23,41.99,39.04
Warhammer 40,000: Darktide,39.99,45.86
Marvels Spider-Man Remastered,30.71,27.07
Persona 5 Royal,37.79,43.32
The Callisto Protocol,59.99,69.41
Need for Speed Unbound,69.99,42.29
Days Gone,15.00,9.01
But I'm trying to get the value next to the other ones on the same line
Expected output:
Call of Duty: Modern Warfare II (2022),69.99,77.05,153356
Red Dead Redemption 2,14.85,13.79,80011
...
Even when adding game_ids to print(), it spams the same game id for each line.
How can I go about resolving this issue?
HTML file: https://jsfiddle.net/m3hqy54x/
I feel like all 3 details (title, price_official, price_lowest) are probably all in a shared container. It would be better to loop through these containers and select the details as sets from each container to make sure the wight prices and titles are being paired up, but I can't tell you how to do that without seeing at least a snippet from (or all of) "games.html"....
Anyway, assuming that '110837\nCall of Duty: Modern Warfare II (2022)' is from the first title here, you can rewrite your last loop as something like:
for z in zip(titles, prices[::2], prices[1::2]):
z, lw = list(z), ''
for i in len(z):
if i == 0: # title
z[0] = ' '.join(w for w in z[0].text.split('\n', 1)[-1] if w)
if '\n' in z[0].text: lw = z[0].text.split('\n', 1)[0]
continue
z[i] = z[i].text.replace('$', '').replace('~', '')
print(','.join(z+[lw]))
Added EDIT: After seeing the html, this is my suggested solution:
for g in doc.select('div[data-container-game-id]'):
gameId = g.get('data-container-game-id')
title = g.select_one('a.title')
if title: title = ' '.join(w for w in title.text.split() if w)
price_official = g.select_one('.price-wrap > div:first-child span.price')
price_lowest = g.select_one('.price-wrap > div:first-child+div span.price')
if price_official:
price_official = price_official.text.replace('$', '').replace('~', '')
if price_lowest:
price_lowest = price_lowest.text.replace('$', '').replace('~', '')
print(', '.join([title, price_official, price_lowest, gameId]))
prints
Call of Duty: Modern Warfare II (2022), 69.99, 77.05, 153356
Red Dead Redemption 2, 14.85, 13.79, 80011
God of War, 28.12, 22.03, 130187
ELDEN RING, 50.36, 48.10, 119003
Cyberpunk 2077, 29.99, 28.63, 73502
EA SPORTS FIFA 23, 41.99, 39.04, 156474
Warhammer 40,000: Darktide, 39.99, 45.86, 96592
Marvel's Spider-Man Remastered, 30.71, 27.07, 154207
Persona 5 Royal, 37.79, 43.32, 155123
The Callisto Protocol, 59.99, 69.41, 152790
Need for Speed Unbound, 69.99, 42.29, 165013
Days Gone, 15.00, 9.01, 110837
Btw, this might look ok for just four values, but if you have a large amount of details that you want to extract, you might want to consider using a function like this.

adjacency matrix map manipulation

0
I'm making a simple text based adventure game. My code uses an adjacency matrix as a map. I would like to navigate the map by direction ex(N,E,S,W) my current attempt can only navigate via the name of the location
current output
You are currently in Foyer.
From this location, you could go to any of the following:
Living Room
Where would you like to go? Living Room
You are currently in Living Room.
From this location, you could go to any of the following:
Foyer
Bedroom 2
Powder Room
Kitchen
Where would you like to go? -__________________________________________________
I would like an output like
You are currently in Foyer.
From this location, you could go to any of the following:
South
Where would you like to go? South
You are currently in Living Room.
From this location, you could go to any of the following:
North
West
South
East
Where would you like to go?
import pygame
Inventory = []
names = ["Foyer", "Living Room", "Bedroom 2", "Full Bath", "Bedroom 3","Powder Room","Dinning", "Home Office", "Kitchen","Walkin Closet", "Hallway", "Bedroom1", "Sitting Room","Balcony", "Storage", "Garage", "Supply Closet", "Utility Closet", "Front Yard", "Sidewalk"]
graph = [[0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0], [0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0]]
directions =["North", "East", "South", "West"]
curr_location = "Foyer"
while True:
print("You are currently in ", curr_location, ".", sep = '')
print()
exits = []
print("From this location, you could go to any of the following:")
indx_location = names.index(curr_location)
for each in range(len(graph[indx_location])):
if graph[indx_location][each] == 1:
print("\t", names[each])
exits.append(names[each])
print()
next_location = input("Where would you like to go? ")
if not (next_location in exits):
print()
print("You cannot go this way.")
else:
curr_location = next_location
print()
Maybe add North, South, East, West to exits conditionally if it's possible to move in that direction?

Why does my else statement execute even after if statement condition has been met?

I'm using a for loop to search a text for a value usinf if else statement inside the for loop. Even when my search condition has been met, my else block is also being executed.
This is the text I am using to search for the value:
SKU Product Desc. Pack/ Size QtyUOM Price Extension
1 WL140.111 Clam Tuatua Medium NZ / 20-34 pcs per kilogram / 30.00 KG HK$109.25 HK$3,277.50
Locations: KIT - Butchery (8%) 30.00 Edit Line Edit Alloc
This is my code:
whole_details = re.compile(r'Item([\$\w\s\.\/\-\,:()%]+)(?:Sub Total)')
wd = whole_details.search(text)
wd_text = wd.group(1)
products = ["Yoghurt Passionfruit Organic", "Yoghurt Plain Organic Vegan", "Clam Tuatua Medium 20-", "Clam Tuatua Medium NZ /", "Oyster Pacific NZ /"]
for product in products:
if wd_text.find(product) != -1:
re_qty = re.compile(rf'{product}\s([\d.]+)')
qty_search = re_qty.search(wd_text)
qty = qty_search.group(1)
print("Product Description : " + product)
print("Quantity : " + qty)
else:
print("No product")
This the output I am getting now:
Product Description : Clam Tuatua Medium NZ /
Quantity : 20
No products

How to print list of lists without extra brackets and quotes?

I'm working on assignment for my Python 3 programming class. It's a database to look up movies and the year they came out. However, I'm having a hard time printing the output without extra brackets and quotes:
# Build a dictionary containing the specified movie collection
list_2005 = [["Munich", "Steven Spielberg"]]
list_2006 = [["The Departed", "Martin Scorsese"], ["The Prestige", "Christopher Nolan"]]
list_2007 = [["Into the Wild", "Sean Penn"]]
movies = {
'2005': list_2005,
'2006': list_2006,
'2007': list_2007
}
# Prompt the user for a year
# Displaying the title(s) and directors(s) from that year
user_year = str(input("Enter a year between 2005 and 2007:\n"))
if user_year in movies:
for name in movies[user_year]:
print("%s" % ', '.join(name))
print()
elif user_year not in movies:
print("N/A")
# Display menu
user_choice = ''
while user_choice != 'q':
print("MENU\nSort by:\ny - Year\nd - Director\nt - Movie title\nq - Quit")
print()
user_choice = str(input("Choose an option:\n"))
if user_choice == 'y':
for key, value in sorted(movies.items()):
print("%s:" % key)
print(" %s" % ''.join(str(movies[key])))
# Carry out the desired option: Display movies by year,
# display movies by director, display movies by movie title, or quit
I would like this output to be:
2005:
Munich, Steven Spielberg
2006:
The Prestige, Christopher Nolan
The Departed, Martin Scorsese
etc.
The output I am getting:
2005:
['Munich', 'Steven Spielberg']
2006:
[['The Prestige', 'Christopher Nolan'], ['The Departed', 'Martin Scorsese']]
etc.
Replace
print(" %s" % ''.join(str(movies[key])))
with
print("\t" + '\n\t'.join("{}, {}".format(m[0], m[1]) for m in movies[key]))

Error when creating dictionaries from text files

I've been working on a function which will update two dictionaries (similar authors, and awards they've won) from an open text file. The text file looks something like this:
Brabudy, Ray
Hugo Award
Nebula Award
Saturn Award
Ellison, Harlan
Heinlein, Robert
Asimov, Isaac
Clarke, Arthur
Ellison, Harlan
Nebula Award
Hugo Award
Locus Award
Stephenson, Neil
Vonnegut, Kurt
Morgan, Richard
Adams, Douglas
And so on. The first name is an authors name (last name first, first name last), followed by awards they may have won, and then authors who are similar to them. This is what I've got so far:
def load_author_dicts(text_file, similar_authors, awards_authors):
name_of_author = True
awards = False
similar = False
for line in text_file:
if name_of_author:
author = line.split(', ')
nameA = author[1].strip() + ' ' + author[0].strip()
name_of_author = False
awards = True
continue
if awards:
if ',' in line:
awards = False
similar = True
else:
if nameA in awards_authors:
listawards = awards_authors[nameA]
listawards.append(line.strip())
else:
listawards = []
listawards.append(line.strip()
awards_authors[nameA] = listawards
if similar:
if line == '\n':
similar = False
name_of_author = True
else:
sim_author = line.split(', ')
nameS = sim_author[1].strip() + ' ' + sim_author[0].strip()
if nameA in similar_authors:
similar_list = similar_authors[nameA]
similar_list.append(nameS)
else:
similar_list = []
similar_list.append(nameS)
similar_authors[nameA] = similar_list
continue
This works great! However, if the text file contains an entry with just a name (i.e. no awards, and no similar authors), it screws the whole thing up, generating an IndexError: list index out of range at this part Zname = sim_author[1].strip()+" "+sim_author[0].strip() )
How can I fix this? Maybe with a 'try, except function' in that area?
Also, I wouldn't mind getting rid of those continue functions, I wasn't sure how else to keep it going. I'm still pretty new to this, so any help would be much appreciated! I keep trying stuff and it changes another section I didn't want changed, so I figured I'd ask the experts.
How about doing it this way, just to get the data in, then manipulate the dictionary any ways you want.
test.txt contains your data
Brabudy, Ray
Hugo Award
Nebula Award
Saturn Award
Ellison, Harlan
Heinlein, Robert
Asimov, Isaac
Clarke, Arthur
Ellison, Harlan
Nebula Award
Hugo Award
Locus Award
Stephenson, Neil
Vonnegut, Kurt
Morgan, Richard
Adams, Douglas
And my code to parse it.
award_parse.py
data = {}
name = ""
awards = []
f = open("test.txt")
for l in f:
# make sure the line is not blank don't process blank lines
if not l.strip() == "":
# if this is a name and we're not already working on an author then set the author
# otherwise treat this as a new author and set the existing author to a key in the dictionary
if "," in l and len(name) == 0:
name = l.strip()
elif "," in l and len(name) > 0:
# check to see if recipient is already in list, add to end of existing list if he/she already
# exists.
if not name.strip() in data:
data[name] = awards
else:
data[name].extend(awards)
name = l.strip()
awards = []
# process any lines that are not blank, and do not have a ,
else:
awards.append(l.strip())
f.close()
for k, v in data.items():
print("%s got the following awards: %s" % (k,v))

Categories