Create random, unique variable names for objects - python

I'm playing around with Python and any programming language for the first time, so please bear with me. I started an online class two weeks ago, but try to develop a small game at the side to learn faster (and have fun). It's a text adventure, but is shall have random encounters and fights with enemies that have random equipment that the players can then loot.
This is my problem: If I create random objects/weapons for my random encounter, I need to make sure that the object has a unique name. The way the level is designed there could in theory be an infinite number of objects (it can be open ended, with encounters just popping up).
This is my approach so far
class Item_NPCs: #create objects for NPCs
def__init__(self, item_type, item_number):
# e.g. item_type 1 = weapons, item_type2 = potions, etc.
if item_type == 1 and item number == 1:
self.property1 = 5
self.property2 = 4
if item_type == 1 and item_number ==2:
# etc. :)
def prepare_encounter():
inventory_NPC = [] # empty list for stuff the NPC carries around
XXX = Class_Item(item_type, item_number) # I might randomize the arguments.
What is important is that I want "XXX" to be unique and random, so that no object exists more than once and can later be put into the player's inventory.
How to do that?
Joe

Why do you need it to be random ? You could simply use a list, and append every new object to the list, with its index being its unique identifier :
items = []
items.append( Class_Item(item_type, item_number) )
But if you really need random identifier, maybe you can use a dictionary :
items = dict()
items[random_id] = Class_Item(item_type, item_number)
This requires random_id to be hashable (but it should be if it is a number or a string).

I don't know why others haven't thought of this:
yourvariableName = randint(0,1000)
exec("var_%s = 'value'" % yourVariableName)
I just thought of it myself. I hope it helps you.
A downside is you can't just do this:
print(var_yourVariableName)
you can only do this:
exec("print(var_%s)" % yourVariableName)
But you can probably circumvent this one way or another. Leave a comment if you manage to figure it out.
One more downside — if used in certain ways, it could be very insecure (as we are using exec), so make sure to cover any holes!

Related

How to correctly use a loop within a Python game inventory system?

I'm putting together an inventory system for a dressup game (Python/Ren'py) and I'm stuck at the very last hurdle. I have the Inventory object, Clothing object and Items all set up like so:
class Clothing(store.object):
def __init__(self,name,desc,place):
self.name = name
self.desc = desc
self.place = place
place = []
class Inventory(store.object):
def __init__(self, name):
self.name=name
self.wearing=[]
def wear(self,item):
self.wearing.append(item)
return
def is_wearing(self, item):
if item in self.wearing:
return True
else:
return False
def remove(self,item):
if item in self.wearing:
self.wearing.remove(item)
return
def drop(self, item):
self.wearing.remove(item)
def remove_all(self):
list = [item for item in self.wearing]
if list!=[]:
for item in list:
self.wearing.remove(item)
return
player_inv = Inventory("Player")
wardrobe_inv = Inventory("Wardrobe")
jeans = Clothing(name="Jeans", desc="blue jeans", place=["legs"])
tshirt = Clothing(name="T-shirt", desc="white tee", place=["torso"])
boxers = Clothing(name="Boxer shorts", desc="white boxer shorts", place=["crotch"])
dress = Clothing(name="Dress", desc="a pretty pink dress", place=["legs", "torso"])
socks = Clothing(name="Socks", desc="sports socks", place=["shins"])
sneakers = Clothing(name="Sneakers", desc="beat up old sneakers", place=["feet"])
heels = Clothing(name="High Heels", desc="sky high stilettos", place=["feet"])
towel = Clothing(name="Towel", desc="a basic towel", place=["torso", "chest", "legs", "crotch", "shins", "feet"])
wardrobe_inv.wear(towel)
wardrobe_inv.wear(heels)
wardrobe_inv.wear(dress)
player_inv.wear(jeans)
player_inv.wear(tshirt)
player_inv.wear(boxers)
player_inv.wear(socks)
player_inv.wear(sneakers)
So all going well so far. But a super important part of the above is the 'place' tags that are set up within each clothing object. Reason being, say a player was wearing jeans (place: legs) and a tee (place: torso), and they wanted to put on a dress, they'd have to take the jeans and tee off first (so in other words I need a function that scans through those place tags and sends items with any tag that matches from the player to the wardrobe before they put on the new item ...
And i've almost done it (Well, I say 'I' - a lot of the following was actually suggested by a kind soul on another forum). But I feel my goodwill is running out there and I'm sooo close to getting this working. So yeah, here's what I have so far:
def try_on(self,item):
for all_clothes in self.wearing:
for matching_tags in all_clothes.place:
if matching_tags in item.place:
wardrobe_inv.wear(all_clothes)
self.remove(all_clothes)
self.wearing.append(item)
wardrobe_inv.remove(item)
return
And it's very nearly fully functional. As intended it scans through the tags and send items back to the wardrobe. Only issue is, it only sends one item back, the first item with a matching tag that it encounters. I know there must be a really basic easy way of getting the code to loop through the items in that particular section, move each matching one over to the wardrobe, then carry on with the rest. But I can't for the life of me work out what it is! I've tried making "if matching_tags in item.place:" another for loop but that seemed to make all kinds of strange funky unintended stuff happen!
(Please bear in mind that i've cobbled the inventory together from a few different examples I found online and have taken what feels like an intensive crash-course in Python over the weekend, but am still a total beginner and really out of my depth here! I just want to get my inventory working while I still have some hair left on my head!) So somebody, please - is there some way of making sure that this try_on function works as intended and sends every item with a matching 'place' tag back to the wardrobe and not just the first one it encounters?
Thanks in advance and sorry for the wall of text. I really didn't know how to explain this connundrum more succinctly! x

creating a variable number of variables and populating them from a list

I'm trying to create a few variables at the same time.
I want the user to specify a value and as a result create that many unique variables, populate them with values from an already created list and then print the results.
I can do this if I specify the number of variables each time, but I want the program to ask the user for the number instead.
This works as I would like; but, it assumes I know the number of Hands to create
Deck = ["AC","AH","AS","AD","KC","KH","KS","KD"]
Hand1 = [Deck.pop(),Deck.pop()]
Hand2 = [Deck.pop(),Deck.pop()]
...
HandN = [Deck.pop(),Deck.pop()]
print("Hand1: ", Hand1)
print("Hand2: ", Hand2)
...
print("HandN: ", HandN)
I want to do the same but instead ask the user for how many hands to create, Something like:
Deck = ["AC","AH","AS","AD","KC","KH","KS","KD"]
NumberOfHands = int(input("How Many Hands? "))
for each in range(1,NumberOfHands+1):
Hand+str(each) = [DeckList.pop(),DeckList.pop]
for each in range(1,NumberOfHands+1):
print(Hand+str(each))
The way I thought this would have worked results in a syntax error.
I've seen some other questions that look similar and hint at doing this with a dictionary; but, its not making sense to me on how to apply it for this type of scenario...
Thanks for your help!
Here is how to do it with a dict:
hands = {f"Hand{each + 1}": [Deck.pop(), Deck.pop()] for each in range(NumberOfHands)}
This will create a dict of size NumberOfHands containing all the hands from 1 to NumberOfHands
You can do it
But you shuldn't
Deck = ["AC","AH","AS","AD","KC","KH","KS","KD"]
NumberOfHands = int(input("How Many Hands? "))
for n in range(1,NumberOfHands+1):
globals()["Hand" + str(n)] = [Deck.pop(),Deck.pop()]
for n in range(1,NumberOfHands+1):
print( globals()['Hand{}'.format(n)])
example:
How Many Hands? 4
['KD', 'KS']
['KH', 'KC']
['AD', 'AS']
['AH', 'AC']
this is a dirty approach of how to do it, but seriously, consider to create only one variable and store them in a list, and access them by index, something safer.
Consider this nice blog to read: http://stupidpythonideas.blogspot.com/2013/05/why-you-dont-want-to-dynamically-create.html

Fixing a meeting room function schedule with double and triple bookings to determine space usage

I need to calculate the total amount of time each group uses a meeting space. But the data set has double and triple booking, so I think I need to fix the data first. Disclosure: My coding experience consists solely of working through a few Dataquest courses, and this is my first stackoverflow posting, so I apologize for errors and transgressions.
Each line of the data set contains the group ID and a start and end time. It also includes the booking type, ie. reserved, meeting, etc. Generally, the staff reserve a space for the entire period, which would create a single line, and then add multiple lines for each individual function when the details are known. They should segment the original reserved line so it's only holding space in between functions, but instead they double book the space, so I need to add multiple lines for these interim RES holds, based on the actual holds.
Here's what the data basically looks like:
Existing data:
functions = [['Function', 'Group', 'FunctionType', 'StartTime', 'EndTime'],
[01,01,'RES',2019/10/04 07:00,2019/10/06 17:00],
[02,01,'MTG',2019/10/05 09:00,2019/10/05 12:00],
[03,01,'LUN',2019/10/05 12:30,2019/10/05 13:30],
[04,01,'MTG',2019/10/05 14:00,2019/10/05 17:00],
[05,01,'MTG',2019/10/06 09:00,2019/10/06 12:00]]
I've tried to iterate using a for loop:
for index, row in enumerate(functions):
last_row_index = len(functions) - 1
if index == last_row_index:
pass
else:
current_index = index
next_index = index + 1
if row[3] <= functions[next_index][2]:
next
elif row[4] == 'RES' or row[6] < functions[next_index][6]:
copied_current_row = row.copy()
row[3] = functions[next_index][2]
copied_current_row[2] = functions[next_index][3]
functions.append(copied_current_row)
There seems to be a logical problem in here, because that last append line seems to put the program into some kind of loop and I have to manually interrupt it. So I'm sure it's obvious to someone experienced, but I'm pretty new.
The reason I've done the comparison to see if a function is RES is that reserved should be subordinate to actual functions. But sometimes there are overlaps between actual functions, so I'll need to create another comparison to decide which one takes precedence, but this is where I'm starting.
How I (think) I want it to end up:
[['Function', 'Group', 'FunctionType', 'StartTime', 'EndTime'],
[01,01,'RES',2019/10/04 07:00,2019/10/05 09:00],
[02,01,'MTG',2019/10/05 09:00,2019/10/05 12:00],
[01,01,'RES',2019/10/05 12:00,2019/10/05 12:30],
[03,01,'LUN',2019/10/05 12:30,2019/10/05 13:30],
[01,01,'RES',2019/10/05 13:30,2019/10/05 14:00],
[04,01,'MTG',2019/10/05 14:00,2019/10/05 17:00],
[01,01,'RES',2019/10/05 14:00,2019/10/06 09:00],
[05,01,'MTG',2019/10/06 09:00,2019/10/06 12:00],
[01,01,'RES',2019/10/06 12:00,2019/10/06 17:00]]
This way, I could do a simple calculation of elapsed time for each function line and add it up to see how much time they had the space booked for.
What I'm looking for here is just some direction I should pursue, and I'm definitely not expecting anyone to do the work for me. For example, am I on the right path here, or would it be better to use pandas and vectorized functions? If I can get the basic direction right, I think I can muddle through the specifics.
Thank-you very much,
AF

Filter search function in Tkinter python for lists

So this is what my GUI looks like:
GUI
,and where i need help with is if i type a subject code it must show all the students with the that particular subject. Here is my code for the search function and add function:
def add_student():
Sname = Student_name.get()
Ssurnname = Student_surname.get()
Sdetail = Student_detail.get()
Snumber = Student_number.get()
i = Students(Sname,Ssurnname,Sdetail,Snumber)
Sinfo.append(i)
iName = Student_subject.get()
iCode = Student_code.get()
iMark1 = Student_Mark1.get()
iMark2 = Student_Mark2.get()
iMark3 = Student_Mark3.get()
iProject = Student_project.get()
j = Subjects(iName,iCode,iMark1,iMark2,iMark3,iProject)
SSubject.append(j)
kCourse = Degree_course.get()
kCode = Degree_code.get()
kYear = Degree_year.get()
v = Degrees(kCourse,kCode,kYear)
SDegree.append(v)
popup_add()
student_list.append(Sinfo)
student_list.append(SSubject)
student_list.append(SDegree)
def filter_data():
top3 = Toplevel()
top3.geometry('300x300')
top3.title("Search")
Searchlabel = Label(top3, text = "Please enter the Subject code: ")
Searchlabel.grid(column=1, row=1, sticky = (W,E))
searchValue = StringVar()
top3.searchBox = ttk.Entry(top3, textvariable=searchValue).grid(column=1, row=2, sticky = (W,E))
def searchdata(*args):
print("*")
resultList.delete(0,END)
searchkey = searchValue.get()
for student in student_list:
if searchkey == student[0]:
resultList.insert(END,str(student))
elif searchkey == student[1]:
resultList.insert(END,str(student))
top3.button_1 = Button(top3, text = "Search", command = searchdata)
top3.button_1.grid(column=3, row=2, sticky = (W,E))
Observations
In the code you posted, it appears that student_list is a list with exactly three elements: a list of Students objects, a list of Subjects objects, and a list of Degrees objects. I make that observation based on these lines of code:
...
Sinfo.append(i)
...
SSubject.append(j)
...
SDegree.append(v)
...
student_list.append(Sinfo)
student_list.append(SSubject)
student_list.append(SDegree)
I have no way of knowing if that's your intent, or if that's the first bug. I also have no way of knowing if it will always have exactly three or more than three (but always a multiple of three).
Assuming that it's intentional that student_list will always have exactly three elements, this loop is incorrect:
for student in student_list:
if searchkey == student[0]:
resultList.insert(END,str(student))
The first time through the loop, student will itself be a list of Students. The second time through the loop, student will be a list of Subjects), and the third time through it will be a list of Degrees.
Suggestions
Assuming that your data structures are intentional and that your ultimate goal is to be able to generate a list of students based on a given subject code, you will need to iterate over the list of subjects, not students.
Given the current code structure, you would need to do something like this (using a temporary variable subjects for clarity):
subjects = student_list[1]
for subject in subjects:
...
However, given that the students are in one list but the subjects are in another, you need to keep track of the index in the list of the subjects so that you can use the same index to reference the related student.
Note: This would be much easier if the subjects were an attribute of the student, so you might want to consider making the subjects and degrees attributes of a student.
We can keep track of the index within the list of subjects by using python's enumerate function:
for index, subject in enumerate(subjects):
...
Within the loop, you need to compare what the user entered with the subject code, and if you find it, you need to insert the corresponding student in the window.
Without knowing for certain, I'm going to assume that the Subjects class provides the subject code as the attribute code. I have no way of knowing if that's a correct assumption.
students = student_list[0]
subjects = student_list[1]
for index, subject in enumerate(subjects):
if searchkey == subject.code:
this_student = students[index]
resultList.insert(END, str(thisstudent))
Solving the problem through better data structures
The real solution to your problem might be to rethink some of your design choices. Instead of keeping student info, student subjects, and student grades in three separate lists, you might want to consider creating a Student class that has the info, subjects and lists as attributes. With that, all of the data for a student is in one place.
For example:
class Student(object):
def __init__(self, info, subjects, grades):
self.info = info
self.subjects = subjects
self.grades = grades
You would then create student_list like this:
student_list.append(Student(Sinfo, SSubject, SDegree))
With that you can loop over these students in a slightly more easy and understandable way:
for student in student_list:
for subject in student.subjects:
if subject.code == searchkey:
resultList.insert(END, str(student.info))
You can make this even easier by creating a method that can do the test for you:
class Student(object):
def has_subject(code):
for subject in self.subjects:
if subject.code == code:
return True
return False
Then, your loop becomes even clearer:
for student in student_list:
if student.has_code(searchkey):
resultList.insert(END, str(student.info))
Final thoughts
My answer could be wrong, because your question lacks a considerable amount of information. This is why we ask for a Minimal, Complete, and Verifiable Example that actually runs. Without it, we have to make many guesses and assumptions about your code. If the assumptions are bad, I will have wasted half an hour addressing the wrong problem, and you will have wasted time reading an answer that isn't relevant.
Finally, it would be easier for you to get help if you were to write code that conforms to PEP8 naming standards. Your code is difficult to read because of your unconventional use of uppercase characters. People tend to not want to provide answers to code that is difficult to read.

Separating lists in a list through iteration

First off, this is a homework assignment, but I've been working on it for a week now and haven't made much headway. My goal for this function is to take a list of lists (each list contains data about a football player) and separate the lists based off of the teams which the players belong to. I also want to add up each player's data so that I wind up with one list for each team with all the player's stats combined.
Here's the code I have so far. The problem I'm currently running into is that some teams are printed multiple times with different data each time. Otherwise it appears to be working correctly. Also, we have the limitation imposed on us that we are not allowed to use classes.
def TopRushingTeam2010(team_info_2010): #running into trouble calculating the rusher rating for each team, it also prints out the same team multiple times but with different stats. And just not getting the right numbers and order.
total_yards = 0
total_TD = 0
total_rush = 0
total_fum = 0
#works mostly, but is returning some teams twice, with different stats each time, which
#should not be happening. so... yeah maybe fix that?
for item in team_info_2010:
team = item[0]
total_yards = item[2]
total_TD = item[3]
total_rush = item[1]
total_fum = item[4]
new_team_info_2010.append([team, total_yards, total_TD, total_rush, total_fum])
for other_item in team_info_2010:
if other_item[0] == team:
new_team_info_2010.remove([team, total_yards, total_TD, total_rush, total_fum])
total_yards = total_yards + other_item[2]
total_TD = total_TD + other_item[3]
total_rush = total_rush + other_item[1]
total_fum = total_fum + other_item[4]
new_team_info_2010.append([team, total_yards, total_TD, total_rush, total_fum])
Any help or tips as to which direction I should head, or if I'm even headed in the right direction?
One possible problem is that you are removing from team_info_2010 while you are iterating through the list. Try deleting that line of code. I don't see a clear reason why you would want to delete from team_info_2010 and behavior is often undefined when you modify an object while iterating through it. More specifically, try deleting the following line of code:
team_info_2010.remove(item)

Categories