I am building a Python-based, single-player, word-based, MMORPG game. I am a beginner and wish this to be a simple task. I have coded the moving part, in which the character moves from one site to another. It seems to not work, as Python seems to not be able to see my attributes. This is the error message:
Traceback (most recent call last):
File "C:/Users/lenovo/Desktop/Maelstrom/Maelstrom Move.py", line 51, in
place = test.place
AttributeError: 'Player' object has no attribute 'place'
This is my code:
class Player(object):
"""The player."""
def __init__(self,name="name",inv=[],equip=[],stats=[],place=int("001"),knownplaces={}):
self.name = input("What name do you want?")
knownplaces[int("001")]="Ruby City"
knownplaces[int("002")]="Ruby Inn"
knownplaces[int("003")]="Ruby Forests"
knownplaces[int("004")]="Ruby Countryside"
knownplaces[int("005")]="Witch Hideout"
def __str__():
rep = self.movepossible
def movepossible(self,position):
#001--Ruby City
#002--Ruby Inn
#003--Ruby Forests
#004--Ruby Countryside
#005--Witch Hideout
if position==int("001"):
possible=[int("002"),int("003")]
return possible
elif position==int("002"):
possible=[int("001")]
return possible
elif position==int("003"):
possible=[int("001"),int("004")]
return possible
elif position==int("004"):
possible=[int("001"),int("003"),int("005")]
return possible
elif position==int("005"):
possible=[int("004")]
return possible
else:
return null
def move(self,position):
possiblewords=[]
print('Choose between paths:'/n)
possible = movepossible(self, position)
for m in range(0,len(possible),1):
possiblewords.append(knownplaces[possible[m]])
for n in range(0,len(possiblewords),1):
print(m+':'+possiblewords[m-1] /n)
choice=input('Make your choice...')
if choice-1 <= len(possiblewords):
self.place=possible[choice-1]
def showposition(self):
print(knownplaces[self.place])
test = Player()
while True:
place = test.place
test.move(place)
test.showposition()
At the time the line place = test.place is executed, the place attribute on your Player instance has not been defined.
The first time the place attribute gets set is in the move() method. i.e. Attempting to access place before calling move() will result in the error you are observing.
You should assign a default value to self.place in the initializer for the Player class.
Related
I have a function that creates a player object but when referencing the object, I get a NameError. I think it is happening due to local scope but global should fix it...
I just started out OOP and this code is working in the python shell but it is not working in script mode.
endl = lambda a: print("\n"*a)
class Score:
_tie = 0
def __init__(self):
self._name = ""
self._wins = 0
self._loses = 0
def get_name(self):
print
self._name = input().upper()
def inc_score(self, wlt):
if wlt=="w": self._wins += 1
elif wlt=="l": self._loses += 1
elif wlt=="t": _tie += 1
else: raise ValueError("Bad Input")
def player_num(): #Gets number of players
while True:
clear()
endl(10)
print("1 player or 2 players?")
endl(5)
pnum = input('Enter 1 or 2: '.rjust(55))
try:
assert int(pnum) == 1 or int(pnum) == 2
clear()
return int(pnum)
except:
print("\n\nPlease enter 1 or 2.")
def create_player(): #Creates players
global p1
p1 = Score()
yield 0 #stops here if there is only 1 player
global p2
p2 = Score()
def pr_(): #testing object
input(p1._wins)
input(p2._wins)
for i in range(player_num()):
create_player()
input(p1)
input(p1._wins())
pr_()
wherever I reference p1 I should get the required object attributes but I'm getting this error
Traceback (most recent call last):
File "G:/Python/TicTacTwo.py", line 83, in <module>
input(p1)
NameError: name 'p1' is not defined
Your issue is not with global but with the yield in create_player(), which turns the function into a generator.
What you could do:
Actually run through the generator, by executing list(create_player()) (not nice, but works).
But I suggest you re-design your code instead, e.g. by calling the method with the number of players:
def create_player(num): #Creates players
if num >= 1:
global p1
p1 = Score()
if num >= 2:
global p2
p2 = Score()
If you fix this issue, the next issues will be
1) input(p1) will print the string representation of p1 and the input will be lost, you probably want p1.get_name() instead.
2) input(p1._wins()) will raise TypeError: 'int' object is not callable
I will redesign the app to introduce really powerful python constructs that may help you when getting into OOP.
Your objects are going to represent players, then don't call them Score, call them Player.
Using _tie like that makes it a class variable, so the value is shared for all the players. With only two participants this may be true but this will come to hurt you when you try to extend to more players. Keep it as a instance variable.
I am a fan of __slots__. It is a class special variable that tells the instance variables what attributes they can have. This will prevent to insert new attributes by mistake and also improve the memory needed for each instance, you can remove this line and it will work but I suggest you leave it. __slots__ is any kind of iterable. Using tuples as they are inmutable is my recomendation.
Properties are also a really nice feature. They will act as instance attribute but allow you to specify how they behave when you get the value (a = instance.property), assign them a value (instance.property = value), or delete the value (del instance.property). Name seems to be a really nice fit for a property. The getter will just return the value stored in _name, the setter will remove the leading and trailing spaces and will capitalize the first letter of each word, and the deletter will set the default name again.
Using a single function to compute a result is not very descriptive. Let's do it with 3 functions.
The code could look like this:
# DEFAULT_NAME is a contant so that we only have to modify it here if we want another
# default name instead of having to change it in several places
DEFAULT_NAME = "Unknown"
class Player:
# ( and ) are not needed but I'll keep them for clarity
__slots__ = ("_name", "_wins", "_loses", "_ties")
# We give a default name in case none is provided when the instance is built
def __init__(self, name=DEFAULT_NAME):
self._name = name
self._wins = 0
self._loses = 0
self._ties = 0
# This is part of the name property, more specifically the getter and the documentation
#property
def name(self):
""" The name of the player """
return self._name
# This is the setter of the name property, it removes spaces with .strip() and
# capitalizes first letters of each word with .title()
#name.setter
def name(self, name):
self._name = name.strip().title()
# This is the last part, the deleter, that assigns the default name again
#name.deleter
def name(self):
self._name = DEFAULT_NAME
def won(self):
self._wins += 1
def lost(self):
self._loses += 1
def tied(self):
self._ties += 1
Now that's all we need for the player itself. The game should have a different class where the players are created.
class Game:
_min_players = 1
_max_players = 2
def __init__(self, players):
# Check that the number of players is correct
if not(self._min_players <= players <= self._max_players):
raise ValueError("Number of players is invalid")
self._players = []
for i in range(1, players+1):
self._players.append(Player(input("Insert player {}'s name: ".format(i))))
#property
def players(self):
# We return a copy of the list to avoid mutating the inner list
return self._players.copy()
Now the game would be created as follows:
def new_game():
return Game(int(input("How many players? ")))
After that you would create new methods for the game like playing matches that will call the players won, lost or tied method, etc.
I hope that some of the concepts introduced here are useful for you, like properties, slots, delegating object creation to the owner object, etc.
I attempting to design a simple choice based video game. Essentially what I want is a recursive loop that will continue to call the new levels based off the results of the previous. For example, in level 1 based off choice made it will either trigger level 2 or 3. This is the code I have so far:
class Levels:
def __init__(self, Next = 1):
self.Next = Next
def Call(self):
VarLevel = "Level" + "{}".format(self.Next)
return ("{}".format(VarLevel))
This is the super class, it returns the VarLevel which equals Level1 to trigger the subclass Level1. This is the code I have for the levels, I've excluded the context of the game because I don't think it is necessary.
class Level1(Levels):
def __init__(self,):
# this just includes information about the level to show the user
# (objective etc.)
def Action(self):
# this will include the content of the level. based off the choices
# made I want it to return to the super with VarLevel as Level2 or
# Level3 and then to trigger the next level running and repeat
# throughout the program to run the game. For the purpose of testing
# the program the only content of Level1 is setting the return to 2 so
# that Level2 is called. I'm having trouble actually getting it to
# recognize my return and to trigger the next level. This is the
# actual method I want to do the calling with
class LevelCall():
def __init__(self, Levels = Levels):
self.Levels = Levels
def Calling(self):
result = (Levels, "{}".format(Levels()))()
it gives me the error TypeError: 'tuple' object is not callable. I have been doing a lot of different attempts to get it to work so I'm not certain that this is even the real problem with the code. Also of note I am decent in Java and am now transitioning to Python (this is my first attempt in Python other then basic tests to read/write etc.) Any help is greatly appreciated to help figure out how to format the game and I apologize in advance because I know this is a long question, I've never posted here before so if you need more info or clarification please feel free to ask.
Edit:
This is the full error message
Traceback (most recent call last):
line 54, in <module>
Tester.Calling()
line 50, in Calling
result = (Levels, "{}".format(Levels()))()
TypeError: 'tuple' object is not callable
Another Edit:
I think I am getting closer. I made the following changes
class LevelCall():
def __init__(self, Levels = Levels):
self.Levels = Levels
def Calling(self):
Hold = Levels()
result = (getattr(Levels, "{}".format(Hold.Call()))())
It now gives the following error message.
Traceback (most recent call last):
line 55, in <module>
Tester.Calling()
line 51, in Calling
result = (getattr(Levels, "{}".format(Hold.Call()))())
AttributeError: type object 'Levels' has no attribute 'Level1'
If I understand correctly it is now attempting to do what I want but isn't finding the class "Level1". Again all help is much appreciated.
Edit______________________
I would like to thank all who replied and attempted to help, I am truly grateful for the support. With the clarification you were able to help me with as well as a fresh start today and mapping it out in java first to make the transition easier I was able to solve my problem. Once again thank you all very much I will add the solution I found beneath this edit.
global Stop
class Level1 :
def __init__(self):
self
def Action(self):
print ("1")
global Stop
Stop = input("Would you like to advance to the next level?")
if (Stop == "yes"):
# Lev = Level2()
# return Lev.Action()
return Level2
if (Stop == "no"):
return "stop"
class Level2:
def __init__(self):
self
def Action(self):
print("2")
global Stop
Stop = input("Would you like to advance to the next level?")
if (Stop == "yes"):
# Lev = Level3()
# return Lev.Action()
return Level3
if (Stop == "no"):
return "stop"
class Level3 :
def __init__(self):
self
def Action(self):
print ("3")
global Stop
Stop = input ("Next level??")
if (Stop == "yes"):
# Lev = Level4()
# return Lev.Action()
return Level4
if (Stop == "no"):
return "stop"
class Level4:
def __init__(self):
self
def Action(self):
print ("Complete")
return "Done"
def Runner (Level):
if (Level == "Done"):
print ("Bye")
else :
if (Level != "stop"):
Lev = Level()
Next = Lev.Action()
Runner(Next)
if (Level == "stop"):
print ("you chose to stop")
Runner(Level1)
(a,b,c) is tuple syntax. (a,b,c)() is a tuple being called like a function. That is what the error is referring to.
If we break the offending code down you can tell. What does it look like when you replace the call to format with an arg placeholder:
(Levels, "{}".format(Levels()))() becomes...
(Levels, arg)() # this is now clearly a tuple and you're treating it like a function.
Not really sure how fixing that will help you with your levels problem tho.
If you want to call a function, do so like: func(args).
If you want to define a tuple, do so like: (a, b, ..., z).
But don't call a tuple like a function.
class Player1:
base_HP = 300
def getBHP(self):
return self.base_HP
jogador1 = Player1
jogador1_hp = jogador1.getBHP() #Functions and Class calls must end with brackets.
print(jogador1_hp)
That's the code I'm using to get the player HP and i want to save it at jogador1_hp.
How ever this is what iam getting:
C:\Users\joaol\AppData\Local\Programs\Python\Python36-32\python.exe C:/Users/joaol/PycharmProjects/FirstProgram/Main.py
<function Player1.getBHP at 0x02C131E0>
Process finished with exit code 0
Even if i do as below, I'm still getting a blank console.
class Player1:
base_HP = 300
def getBHP(self):
print(self.base_HP)
jogador1 = Player1
jogador1.getBHP
EDIT: I fix it ,i just needed to add "()" when i create the object!
jogador1 = Player1()
jogador1_hp = jogador1.getBHP()
You have to call methods for them to execute.
jogador1_hp = jogador1.getBHP()
You don't instantiate the Player1 class. In your code, jogador1 is just another name for the Player1 class. You should call the class to instantiate it, like: jogador1 = Player1()
If i use jogador1_hp = jogador1.getBHP() i get this :
C:\Users\joaol\AppData\Local\Programs\Python\Python36-32\python.exe C:/Users/joaol/PycharmProjects/FirstProgram/Main.py
Traceback (most recent call last):
File "C:/Users/joaol/PycharmProjects/FirstProgram/Main.py", line 19, in <module>
jogador1_hp = jogador1.getBHP()
TypeError: getBHP() missing 1 required positional argument: 'self'
Process finished with exit code 1
Good day..
I'm kinda struggling in my learning process in Class. Let me show my code, and what is happening.
from random import randint
print "Start"
class Simulation (object):
def __init__(self):
self.bankroll= 5000
self.bet=0
self.betLevel= 0
self.betList=[5,5,5,10,15,25,40,65,100]
self.wlist=[]
self.my_file=open("output.txt","w")
self.winningNumber=0
self.myNumber=[4,5,7,8]
self.testCase=1
self.my_file.write("Test case Bet Number Outcome Bankroll")
def gamble(self):
self.bet=self.betList[self.betLevel]
if self.bankroll < 1000 :
self.bet= 5
self.winningNumber= randint(0,36)
if self.winningNumber in self.myNumber:
win()
else:
lose()
def win(self):
self.bankroll +=(17*self.bet)
self.wlist= [self.testCase,self.bet,self.winningNumber,"WIN",self.bankroll]
self.betLevel=0
write()
def lose(self):
self.bankroll -=self.bet
self.wlist= [self.testCase,self.bet,self.winningNumber,"LOSE",self.bankroll]
self.betLevel +=1
write()
def write(self):
self.my_file.write(" ".join(self.wlist))
def startSimulation(self):
for i in range (100):
gamble()
closeFile()
def closeFile(self):
self.my_file.close()
mySimulation= Simulation()
mySimulation.startSimulation()
print "DONE"
So in this code, I'm trying to simulating a roulette game, using a weird betting system. It works like Martingale, but instead of doubling, I follows Fibonacci sequence.
So my problem is that I got this error:
Traceback (most recent call last):
File "D:\Roulette simulation\python 3.py", line 44, in <module>
mySimulation.startSimulation()
File "D:\Roulette simulation\python 3.py", line 38, in startSimulation
gamble()
NameError: global name 'gamble' is not defined
My question. Why? I mean, I'm calling a function in the same class? Why I got the global error?
Within a method, you have self as a reference to your instance. You can access methods on that instance through that reference:
self.gamble()
There is no global gamble function here; the method is part of the Simulation class. This applies to all methods; you'll have to call closeFile, lose, win and write on self as well, for example.
Try running
self.gamble()
in class functions,self means class itself(someone use 'cls' instead of 'self'), so self.gamble means gamble function of this class
if you want to run a function in the position of class attribution
>>> class P:
name = 'name'
def getage(self):
return 18
age = property(getage)
>>> p = P()
>>> p.age
18
>>>
Why am i getting this attribute error?
class GameState(object):
"""Keeps track game state variables"""
def __init__(self, convo_flag=0, characters_talked_to=0, convo_log=(None)):
self.convo_flag = convo_flag
self.characters_talked_to = characters_talked_to
self.convo_log = convo_log
def welcome_screen():
global LAST_NAME
global BULLY
global DAY
raw_input(messages.WELCOME)
LAST_NAME = raw_input(messages.LAST_NAME)
BULLY = characters.random_character(cclass='Camper', gender='m')
print 'Your name is Pickett %s' % LAST_NAME
messages.print_messages([
messages.EXPLANATION,
messages.BUS_LOADING,
messages.CRACK,
messages.GAME_KID_LOST])
return week_one(DAY)
def week_one(day):
if day == 1:
messages.print_messages(messages.WEEK_ONE[day])
campers = characters.random_character_sample(cclass='Camper', count=5)
people_outside_theater = campers + [characters.TROID]
while GameState.characters_talked_to != 3:
I dont get why im getting this attribute error, i totally declared it in that constructor, is there something i am missing were i need to declare it outside the constructor? This is really racking my brain.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pickett.py", line 44, in welcome_screen
return week_one(DAY)
File "pickett.py", line 52, in week_one
while GameState.characters_talked_to != 3:
AttributeError: type object 'GameState' has no attribute 'characters_talked_to'
You need to create an instance in order you use your class like this:
gameState = GameState()
while gameState.characters_talked_to != 3:
In your code you were trying to access class-level attribute which is not defined in your class.
Your __init__ function sets characters_talked_to on self, which is an instance of GameState.
You did not set it on GameState, which is a class.
Neither did you create any instances of GameState, so in any case __init__ is never called by your program.