I am making a text based game to teach myself python. I try to access the attribute of an object stored in the player object. The object is a copy of the map data object representing their position on the map.
When i run the function as it is, when the look method of the player object is called, the method sees the self argument as a missing argument. If I try to access the room data stored in the player object and pass it in (which doesn't seem right anyway as it should already be in the object instance), it then says the attribute doesn't exist. After the program crashes, in the interpreter I can access the attribute without error. I don't understand what I am doing wrong.
class quadPoint:
def __init__(self, data):
self.pointData = {'description' : '', 'west': '','east': '',
'north': '','south': ''}
self.exits = []
self.inventory = []
self.pointData['description'] = data[0]
self.pointData['west'] = data[1]
self.pointData['east'] = data[2]
self.pointData['north'] = data[3]
self.pointData['south'] = data[4]
def addItem(self, item):
self.inventory.append(item)
def addExit(self, ext):
self.exits.append(ext)
rooms = [
['A discription1','A discription','A discription','A discription','A discription'],
['A discription2','A discription','A discription','A discription','A discription'],
['A discription3','A discription','A discription','A discription','A discription'],
['A discription4','A discription','A discription','A discription','A discription'],
['A discription5','A discription','A discription','A discription','A discription'],
['A discription6','A discription','A discription','A discription','A discription'],
['A discription7','A discription','A discription','A discription','A discription'],
['A discription8','A discription','A discription','A discription','A discription'],
['A discription9','A discription','A discription','A discription','A discription']
]
roomExits = {
'00':[ [0,1],[1,0] ], # 0,0
'01':[ [0,0],[0,2],[1,1] ], # 0,1
'02':[ [0,1],[1,2] ], # 0,2
'10':[ [0,0],[1,1],[2,0] ], # 1,0
'11':[ [1,0],[1,2],[0,1],[2,1] ], # 1,1
'12':[ [1,1],[2,2] ], # 1,2
'20':[ [1,0],[2,1] ], # 2,0
'21':[ [2,0],[1,1],[2,2] ], # 2,1
'22':[ [2,1],[1,2] ], # 2,2
}
class World :
def __init__(self, data, exits):
self.worldData = [ [],[],[] ]
self.generate(data, exits)
def getRoom(self,x,y):
return self.worldData[x][y]
def generate(self, data, exits):
ph = 0
for array in self.worldData:
for i in range(0,3):
array.append('')
for x in range(0,3):
for i in range(0,3):
self.worldData[x][i] = quadPoint(data[ph])
ph += 1
for quards in exits:
for e in exits[quards]:
self.worldData[int(quards[0])][int(quards[1])].addExit(self.worldData[e[0]][e[1]])
class Player :
def __init__(self, room):
self.statData = {}
self.equipment = { 'head' : '', 'neck' : '', 'leftEar' : '',
'rightEar' : '', 'leftShoulder' : '',
'rightShoulder' : '', 'chest' : '',
'leftUpperArm' : '', 'rightUpperArm' : '',
'leftLowerArm' : '', 'rightLowerArm' : '',
'leftFinger0' : '','leftFinger1' : '',
'leftFinger2' : '','leftFinger3' : '',
'leftFinger4' : '','rightFinger0' : '',
'rightFinger1' : '','rightFinger2' : '',
'rightFinger3' : '','rightFinger4' : '',
'leftWrist' : '','rightWrist' : '',
'upperBack' : '','lowerBack' : '','back' : '','Waist' : '',
'leftUpperLeg' : '','rightUpperLeg' : '',
'leftLowerLeg' : '','rightLowerLeg' : '',
'leftAnkle' : '','rightAnkle' : '',
'leftFoot' : '','rightFoot' : ''}
print("What would you like your name to be?")
print()
self.name = input(">>> ")
print('''What would you like your name to be
Wizard
Fighter
Thief
''')
self.plrClass = input(">>> ")
self.currentRoom = room
def look(self, where):
return self.currentRoom.pointData[where]
class Game :
def __init__(self):
self.world = World(rooms, roomExits)
self.player = Player(self.world.getRoom(0,0))
def start(self):
self.running = True
while self.running is True:
print(player.look( 'description'))
print()
print("What do you want to do?")
print()
usrInput = input(">>> ")
if userInput == 'quit': self.running = False
game = Game()
game.start()
the error message is:
Traceback (most recent call last):
File "/home/groundscore/pytextrpg.py", line 128, in <module>
game.start()
File "/home/groundscore/pytextrpg.py", line 117, in start
print(player.look( 'description'))
TypeError: look() takes exactly 2 arguments (1 given)
aruisdante beat me to the immediate answer. A deeper problem, and the reason for the particular error message is using the same lowercase word for both class and instance thereof. If the player class were Player, then print(player...) would have failed with NameError: name 'player' is not defined and you would not have seen the confusing message that resulted from player.look being resolved as the look attribute of the player class.
Also, game = game() is more confusing than game = Game(), and prevents further access to the game class by its name.
I'm not exactly sure if you're properly describing your error (it would be helpful if you included the exact error text, not your description of it), but certainly here:
print(player.look( 'description'))
Should instead be:
print(self.player.look( 'description'))
As player is an attribute of the game class. Also, you should not use is for string comparisons, you should use ==.
Related
I've created the simple GUI as follow.
In the example only three rows are included, however the same principle can be applied to more of them.
I would like to fill all or same rows in the GUI and the save it, but most importantly when the saved files is loaded back only the filled rows (and not all) should be displayed.
I've tried in the way below but unsuccessfully..
import PySimpleGUI as sg
from datetime import datetime
import base64
from pathlib import Path
import webbrowser
sg.theme('DarkTeal9')
layout_1 = [[sg.InputText("", key="-IT2-", font='Arial 9', size=(10,1)),
sg.Combo(["Item1", "Item2", "Item3"],size=(20,1), key='-TEST2-', font='Arial 9'),
sg.CalendarButton("", close_when_date_chosen=True, target='-IN2-', font='Arial 9', no_titlebar=False, format='%d-%b-%Y'),
sg.InputText("", key='-IN2-', size=(20,1), font='Arial 9')]]
layout_a = [[sg.Button("row 2")]]
layout_2 = [[sg.InputText("", key="-IT3-", font='Arial 9', size=(10,1)),
sg.Combo(["Item1", "Item2", "Item3"],size=(20,1), key='-TEST3-', font='Arial 9'),
sg.CalendarButton("", close_when_date_chosen=True, target='-IN3-', font='Arial 9', no_titlebar=False, format='%d-%b-%Y'),
sg.InputText("", key='-IN3-', size=(20,1), font='Arial 9')]]
layout_b =[[sg.Button("row 3")]]
layout_3 = [[sg.InputText("", key="-IT4-", font='Arial 9', size=(10,1), visible=True),
sg.Combo(["Item1", "Item2", "Item3"],size=(20,1), key='-TEST4-', font='Arial 9'),
sg.CalendarButton("", close_when_date_chosen=True, target='-IN4-', font='Arial 9', no_titlebar=False, format='%d-%b-%Y'),
sg.InputText("", key='-IN4-', size=(20,1), font='Arial 9', justification="c")]]
layout = [
[sg.Column(layout_1, key='-LAY1-'), sg.Column(layout_a, visible=True, key="-LAYA-")],
[sg.Column(layout_2, visible=False, key='-LAY2-'), sg.Column(layout_b, visible=False, key='-LAYB-')],
[sg.Column(layout_3, visible=False, key='-LAY3-')],
[sg.Button ("Save"), sg.Button ("Load"), sg.Button('Exit'),],
]
window = sg.Window("", layout)
while True:
event, values = window.read()
if event == 'Save':
file_name = sg.popup_get_file("Save", save_as=True, no_window=True)
window.SaveToDisk(file_name)
if event == 'Load':
file_name = sg.popup_get_file('Load', no_window=True)
window.LoadFromDisk(file_name)
if values["-IT2-"] != "":
window[f'-LAY1-'].update(visible=True)
window[f'-LAYA-'].update(visible=False)
if values ["-IT3-"] != "":
window[f'-LAY2-'].update(visible=True)
if values["-IT4-"] != "":
window[f'-LAY3-'].update(visible=True)
if event == sg.WIN_CLOSED or event == 'Exit':
break
window.close()
if event == 'row 2':
window[f'-LAY2-'].update(visible=True)
window[f'-LAYA-'].update(visible=False)
window[f'-LAYB-'].update(visible=True)
layout = str(event)
if event == 'row 3':
window[f'-LAY3-'].update(visible=True)
window[f'-LAYB-'].update(visible=False)
layout = str(event)
window.close()
Try it
if event == 'Load':
file_name = sg.popup_get_file('Load', no_window=True)
window.LoadFromDisk(file_name)
v1, v2, v3 = window["-IT2-"].get(), window["-IT3-"].get(), window["-IT4-"].get()
if v1:
window[f'-LAY1-'].update(visible=True)
window[f'-LAYA-'].update(visible=False)
if v2:
window[f'-LAY2-'].update(visible=True)
if v3:
window[f'-LAY3-'].update(visible=True)
I'm trying to convert data from a post to Json formed.
But I still haven't had success.
I tried to do in this format
Unfortunately I couldn't think of anything.
Could anyone help?
Post
{'csrfmiddlewaretoken': 'AdbaFrsoWeZTnT07m3VjncmYnYHztaQ214qh8AYH2cI40veXfe0dmfSwkI1o2ma1',
'det[0][CNPJ]': '8768678678678',
'det[0][UF]': 'SP',
'det[0][dhEmi]': '2021-07-13T08:26:30-03:00',
'det[0][nNF]': '8267',
'det[0][xNome]': 'INDÚSTRIA',
'prod[0][0][CFOP]': '6102',
'prod[0][0][NCM]': '84384000',
'prod[0][0][UF]': 'SP',
'prod[0][0][aliquotaInterna]': '18',
'prod[0][0][counter]': '1',
'prod[0][0][mva]': '34',
'prod[0][0][tributacaoEstadual]': '7',
'prod[0][0][vICMSST]': '0',
'prod[0][0][vICMS]': '25.74',
'prod[0][0][vIPI]': '0',
'prod[0][0][vProd]': '367.68',
'prod[0][0][xProd]': 'FUSO',
'prod[0][1][CFOP]': '6102',
'prod[0][1][NCM]': '84384000',
'prod[0][1][UF]': 'SP',
'prod[0][1][aliquotaInterna]': '18',
'prod[0][1][counter]': '2',
'prod[0][1][mva]': '23',
'prod[0][1][tributacaoEstadual]': '7',
'prod[0][1][vICMSST]': '0',
'prod[0][1][vICMS]': '15.96',
'prod[0][1][vIPI]': '0',
'prod[0][1][vProd]': '228.07',
'prod[0][1][xProd]': 'PORCA',
'xNome': 'COMERCIAL'}
View
if post:
import re
pattDet = re.compile('^([a-zA-Z_]\w+.)\[([0-9_\-][\w\-]*)\]\[([a-zA-Z_\-][\w\-]*)\]$')
pattProd = re.compile('^([a-zA-Z_]\w+.)\[([0-9_\-][\w\-]*)\]\[([0-9_\-][\w\-]*)\]\[([a-zA-Z_\-][\w\-]*)\]$')
pprint.pprint(post)
det = []
prodtem = []
count = 0
for post_name, value in post.items():
try:
det_count = int(pattDet.match(post_name).group(2))
if pattDet.match(post_name).group(1) == 'det':
det[pattDet.match(post_name).group(3)] = value
except:
pass
try:
if pattProd.match(post_name).group(1) == 'prod':
if count == int(pattProd.match(post_name).group(3)):
prodtem.insert(count, {pattProd.match(post_name).group(4): value})
else:
count += 1
except Exception as e:
print(e)
pass
result.append({
'det': det,
'prod': prodtem
})
many month ago i have create this for django rest framwork, a parser mutli dimensional, source is here
i have adapted the parser for you
import re
class ParserMultiDimensional:
_reg_split = re.compile(r"(\[.*?\])")
REG_NAME = r"\s*[a-zA-Z_]\w*\s*"
_reg_name = re.compile(r"^" + REG_NAME + r"$")
REG_INDEX_LIST = r"\s*(\d+)?\s*"
_reg_index_list = re.compile(r"^\[(" + REG_INDEX_LIST + r")\]$") # can be number or nothing
_reg_index_object = re.compile(r"^\[(" + REG_NAME + r")\]$") # need to start with char + alpaha
_reg_list = re.compile(r"^\[" + REG_INDEX_LIST + r"]$")
_reg_object = re.compile(r"^\[" + REG_NAME + r"]$")
def __init__(self, data):
self.data = data
self._valid = None
def conv_list_index(self, key):
ret = self._reg_index_list.search(key).groups()[0]
if not ret:
return -1
return int(ret)
def conv_object_index(self, key):
return self._reg_index_object.search(key).groups()[0]
def conv_index(self, index):
if self.is_list(index):
return self.conv_list_index(index)
elif self.is_object(index):
return self.conv_object_index(index)
else:
return index
def is_list(self, key):
if not key or self._reg_list.match(key):
return True
return False
def is_object(self, key):
if self._reg_object.match(key):
return True
return False
def is_name(self, key):
if self._reg_name.match(key):
return True
return False
def split_key(self, key):
# remove space
key = key.replace(" ", "")
results = self._reg_split.split(key)
# remove empty string
return list(filter(None, results))
def valid_key(self, key):
results = self.split_key(key)
# not result or check first element
if not results or not self.is_name(results[0]):
return []
for r in results[1:]:
if not self.is_list(r) and not self.is_object(r):
return []
return results
def set_type(self, dtc, key, value):
index = self.conv_index(key)
if self.is_list(key):
if not len(dtc) or index == len(dtc):
dtc.append(value)
key = len(dtc) - 1
elif index not in dtc:
# TODO dict same as list
dtc[index] = value
return index
def construct(self, data):
dictionary = {}
for key, value in data.items():
keys = self.valid_key(key)
if not keys:
raise Exception(f"invalid key {keys}")
tmp = dictionary
for curr, nxt in zip(keys, keys[1:]):
set_type = [] if self.is_list(nxt) else {}
tmp = tmp[self.set_type(tmp, curr, set_type)]
self.set_type(tmp, keys[-1], data.get(key))
self.__validate_data = dictionary
def is_valid(self):
self._valid = False
try:
self.construct(self.data)
self._valid = True
except Exception as err:
self.errors = err
return self._valid
#property
def validate_data(self):
if self._valid is None:
raise ValueError("You need to be call is_valid() before access validate_data")
if self._valid is False:
raise ValueError("You can't get validate data")
return self.__validate_data
to use it
parser = ParserMultiDimensional(data_query) # add your post data
if parser.is_valid():
data = parser.validate_data
# do your things
else:
print(parser.errors)
the result with your data is
{
"csrfmiddlewaretoken": "AdbaFrsoWeZTnT07m3VjncmYnYHztaQ214qh8AYH2cI40veXfe0dmfSwkI1o2ma1",
"det": [
{
"CNPJ": "8768678678678",
"UF": "SP",
"dhEmi": "2021-07-13T08:26:30-03:00",
"nNF": "8267",
"xNome": "INDÚSTRIA"
}
],
"prod": [
[
{
"CFOP": "6102",
"NCM": "84384000",
"UF": "SP",
"aliquotaInterna": "18",
"counter": "1",
"mva": "34",
"tributacaoEstadual": "7",
"vICMSST": "0",
"vICMS": "25.74",
"vIPI": "0",
"vProd": "367.68",
"xProd": "FUSO"
},
{
"CFOP": "6102",
"NCM": "84384000",
"UF": "SP",
"aliquotaInterna": "18",
"counter": "2",
"mva": "23",
"tributacaoEstadual": "7",
"vICMSST": "0",
"vICMS": "15.96",
"vIPI": "0",
"vProd": "228.07",
"xProd": "PORCA"
}
]
],
"xNome": "COMERCIAL"
}
have fun with it ! ;)
What I am wondering is how do I pass the variable - element, into the second file? So that I can use this element as a parameter in a function and also a value to define the location of a variable in array later.
Also, the variable - element should have the same value as 'i' both in file 1 and 2.
file 1: This is a part of my program.
def menu():
existAccount = False
element = 0
print("Welcome to STLP Store!")
print("1.Login\n2.Sign Up\n3.Exit")
user = int(input("Enter(1-3): "))
if user == 1:
inputEmail = input("Enter Email: ")
inputPassword = input("Enter Password: ")
for i in range(len(customers)):
if inputEmail == customers[i].getEmail() and inputPassword == customers[i].getPassword():
existAccount = True
element = i
break
if existAccount == False:
print("Incorrect Email/Password")
menu()
loggedInMenu(int(element))
file 2:
Now, if I put 'element' in loggedInMenu() , it will say "unresolved reference 'element'". If I don't, it will say "Parameter 'element' unfilled'.
from STLPStoreMain import *
def AppMenu():
choose = input("Enter:")
if choose == '1':
#customers is a array which contain class objects. getEmail() is a method to access hidding information.
print ("Email:", customers[element].getEmail())
print("Password: " + "*" * len(customers[element].getPassword()))
print ("Bill Address", customers[element].getBillAdd())
print ("Credit Card Number:", customers[element].getCredNum())
AppMenu()
if choose == '6':
loggedInMenu(element)
Passing a value from one file (module) to another.
To address your question of passing a variable from one module to another, I have taken the class approach, where the variable you want file2 to access (element) is a property of file1.
The setup:
Both files are placed into the same directory, which contains an __init__.py file.
On instantiation, file2 creates an instance of file1, which runs your login script, and stores the element property into a class attribute of file2.
Next, the menu is called, and uses the self._element attribute which was created in file1.
Here's the code and it's honestly much simpler than the description seems.
Cleanup Edits:
Additionally, (discard them if you like) I've made a couple of PEP/Pythonic edits to your original code:
Changed the if statement to use the all() function, which tests for all conditions in the list to be True.
Updated code to use pure lower case - except for the class, which is camelcase.
Updated your if existAccount == False: statement to the more Pythonic if not existaccount:.
file1.py
As I don't have access to your customers, a simple _customers dictionary has been added for testing. Throw this away and uncomment your lines which access your customers object.
class StartUp():
"""Prompt user for credentials and verify."""
def __init__(self):
"""Startup class initialiser."""
self._element = 0
self._customers = [{'email': 'a#a.com', 'password': 'a'},
{'email': 'b#b.com', 'password': 'b'},
{'email': 'c#c.com', 'password': 'c'},
{'email': 'd#d.com', 'password': 'd'}]
self.menu()
#property
def element(self):
"""The customer's index."""
return self._element
def menu(self):
"""Display main menu to user and prompt for credentials."""
existaccount = False
print("\nWelcome to STLP Store!")
print("1.Login\n2.Sign Up\n3.Exit")
user = int(input("Enter(1-3): "))
if user == 1:
inputemail = input("Enter Email: ")
inputpassword = input("Enter Password: ")
# for i in range(len(customers)):
# if all([inputemail == customers[i].getemail(),
# inputpassword == customers[i].getpassword()]):
for i in range(len(self._customers)):
if all([inputemail == self._customers[i]['email'],
inputpassword == self._customers[i]['password']]):
self._element = i
existaccount = True
break
if not existaccount:
print("incorrect email/password")
self._element = 0
self.menu()
file2.py
class AppMenu():
"""Provide a menu to the app."""
def __init__(self):
"""App menu class initialiser."""
# Display the startup menu and get element on class initialisation.
self._element = StartUp().element
self._customers = [{'email': 'a#a.com', 'password': 'a', 'addr':
'1A Bob\'s Road.', 'cc': '1234'},
{'email': 'b#b.com', 'password': 'b',
'addr': '1B Bob\'s Road.', 'cc': '5678'},
{'email': 'c#c.com', 'password': 'c',
'addr': '1C Bob\'s Road.', 'cc': '9123'},
{'email': 'd#d.com', 'password': 'd',
'addr': '1D Bob\'s Road.', 'cc': '4567'}]
self.menu()
def menu(self):
"""Provide an app menu."""
choose = input("Enter: ")
if choose == '1':
# customers is a array which contain class objects. getemail() is a method
# to access hidding information.
# print ("email:", customers[element].getemail())
# print("password: " + "*" * len(customers[element].getpassword()))
# print ("bill address", customers[element].getbilladd())
# print ("credit card number:", customers[element].getcrednum())
print('-'*25)
print ("email:", self._customers[self._element].get('email'))
print("password: " + "*" * len(self._customers[self._element].get('password')))
print ("bill address:", self._customers[self._element].get('addr'))
print ("credit card number:", self._customers[self._element].get('cc'))
print('-'*25)
self.menu()
if choose == '6':
# loggedinmenu(element)
print('Not implemented.')
The output:
# Create an instance of the menu and run login.
am = AppMenu()
Welcome to STLP Store!
1.Login
2.Sign Up
3.Exit
Enter(1-3): 1
Enter Email: b#b.com
Enter Password: b
Enter: 1
-------------------------
email: b#b.com
password: *
bill address: 1B Bob's Road.
credit card number: 5678
-------------------------
Enter: 6
Not implemented.
I have 2 dict. One with local player data and one listing the players with subdictionaries:
class GameData:
def __init__(self):
self.player = {'id' : 1453339642,
'positionX' : 123,
'positionY' : 0
}
self.players = {1453339642:
{'name' : "Admin"}
}
gameData = GameData()
Then I print out just to check if everything works:
for x in gameData.player:
print (str(x),':',gameData.player[x])
print("\n\n")
for x in gameData.players:
print (str(x))
for y in gameData.players[x]:
print (' ',y,':',gameData.players[x][y])
print("\n\n")
This results in:
id : 1453339642
positionY : 0
positionX : 123
1453339642
name : Admin
When I now want to access the player's id in players for instance with
#print(str(type(gameData.player)))
#print(str(type(gameData.players)))
print(str(type(gameData.players[1453339642])))
I get KEYERROR as a result. Why?
If I put this in a file, it works:
class GameData:
def __init__(self):
self.player = {'id' : 1453339642,
'positionX' : 123,
'positionY' : 0
}
self.players = {1453339642:
{'name' : "Admin"}
}
gameData = GameData()
print(str(type(gameData.players[1453339642])))
Only indentation differs from your code. There must be something happening to gameData between instantiation and the final print.
I have a Map
[email:[hus#gmail.com, vin#gmail.com], jobTitle:[SE, SD], isLaptopRequired:[on, on], phone:[9908899876, 7765666543], name:[hus, Vin]]
for which i need to have a another Map like
[hus:[hus#gmail.com,SE,99087665343],vin:[vin#gmail.com,SE,7765666543]]
How can do it in Groovy?
You could do it like:
def map = [email:['hus#gmail.com', 'vin#gmail.com'], jobTitle:['SE', 'SD'], isLaptopRequired:['on', 'on'], phone:['9908899876', '7765666543'], name:['hus', 'Vin']]
def result = [:]
map.name.eachWithIndex { name, idx ->
result << [ (name): map.values()*.getAt( idx ) - name ]
}
assert result == [hus:['hus#gmail.com', 'SE', 'on', '9908899876'], Vin:['vin#gmail.com', 'SD', 'on', '7765666543']]
Or, you could also do:
def result = [map.name,map.findAll { it.key != 'name' }.values().toList().transpose()].transpose().collectEntries()
But this is just less code at the expense of both readability and resource usage ;-)
The most visual solution i have:
def map = [email:['hus#gmail.com', 'vin#gmail.com'], jobTitle:['SE', 'SD'], isLaptopRequired:['on', 'on'], phone:['9908899876', '7765666543'], name:['hus', 'Vin']]
def names = map.name
def emails = map.email
def jobTitles = map.jobTitle
def isLaptopRequireds = map.isLaptopRequired //sorry for the variable name
def phones = map.phone
def result = [:]
for(i in 0..names.size()-1) {
result << [(names[i]): [emails[i], jobTitles[i], isLaptopRequireds[i], phones[i]]]
}
assert result == [hus:['hus#gmail.com', 'SE', 'on', '9908899876'], Vin:['vin#gmail.com', 'SD', 'on', '7765666543']]
}