'draw1' not defined, Highly confused - python

So I'm making a lottery number drawing machine,
import random
def lottoDraw1():
draw1 = random.randint(1,49)
def lottoDraw2():
draw2 = random.randint(1,49)
if draw2 == draw1:
lottoDraw2()
And I get the error, "NameError: name 'draw1' is not defined"
If I insert:
draw1 = 0
before the code, the answer is always 0.
Even after I define for draw1 to be changed.
What am I doing wrong?

What are Python namespaces all about
This question is asking for namespaces and that is basicially the problem you are having. In lottodraw1 you are only changing the local version of draw1 and thus the global value of draw1 stays unchanged (in your case 0). For that reason you will always use draw1 = None everywhere else.
My approach would be making an array of the draws and having a general draw function:
draws = []
def draw():
new_draw = random.randint(1,49)
if new_draw not in draws:
draws.append(new_draw)
else:
draw()
draw()
draw()
print(draws)
Now you can just call draw and it will add a newly drawn number that does not exist yet.
As noted by Jean-François Fabre the better version would be using sets, which are faster, but only allow unique values:
draws = set()
def draw():
new_draw = random.randint(1,49)
if new_draw not in draws:
draws.add(new_draw)
else:
draw()
draw()
draw()
print(draws)

You need to make draw1 as global variable
draw1, draw2 = None, None
def lottoDraw1():
global draw1
draw1 = random.randint(1,49)
def lottoDraw2():
global draw1
global draw2
draw2 = random.randint(1,49)
if draw2 == draw1:
lottoDraw2()
However, it is not a good approach which is another topic.

Related

Variable not defined in If statement (Python, Ursina Module)

My problem is that when I change the content of the variable "XO" inside the if statement, the one in the condition of the If statement becomes undefined.
from ursina import *
import time
app = Ursina()
window.title = "Game"
window.borderless = False
window.exit_button_visible = False
XO = "X"
class Tile(Button):
def __init__(self, position = (-5, -5, 0), texture = "assets/tile.png"):
super().__init__(
parent = scene,
model = "quad",
color = color.lime,
position = position,
texture = texture
)
def input(self, key):
if self.hovered:
if key == "left mouse down":
if XO == "X":
Tile(position = self.position, texture = "assets/tile_x")
XO = "O"
else:
Tile(position = self.position, texture = "assets/tile_0")
XO = "X"
time.sleep(.005)
destroy(self)
for x in range(3):
for y in range(3):
block = Tile((x-1, y-1))
app.run()
The biggest issue here is that you seem to be trying to reference a global variable inside of a some inner context. In general, this is not encouraged for a lot of reasons. One of the biggest in my opinion is that global code is difficult to maintain. Instead, I would encourage you refactor your code so that all of your code resides inside of a class, and work on encapsulating your code.
That being said, sometimes it is necessary to use the global scope. In order to do that, you simply use the global keyword before the name of the variable you want global scope for. In your case, you would simple do global XO at the start of your input function.

How do I prevent python's turtle module from opening the default window?

I'm currently writing a module (myModule) that can create a tkinter canvas and attach a turtle to it.
That part of the module is done. However, for some reason, turtle still opens another window when it gets attached to the tkinter canvas. I would like to avoid this, but i don't know how, and the turtle documentation is horrible.
Here is the relevant part of what I've made so far:
#myModule
import tkinter as tk
import turtle as tr
import inspect as ins
from functools import partial
_root = None
_canvas = None
_turtle = None
d = None
def openWindow():
global _root
global d
if d == None:
myFrame = sys._getframe()
aboveFrameName = myFrame.f_back.f_back.f_back.f_globals["__name__"] #This doesnt make sense, but it works.
userModule = sys.modules[aboveFrameName]
d = userModule.__dict__
_root = tk.Tk()
def attachCanvas():
global _canvas
if _root == None:
openWindow()
_canvas = tk.Canvas(_root, bd = 0, highlightthickness = 0, width = 500, height = 500)
_canvas.pack()
def attachTurtle():
global _turtle
global _canvas
global _screen
global d
if _canvas == None:
attachCanvas()
_turtle = tr.RawTurtle(_canvas)
for key in tr.__dict__.keys():
obj = None
if key in tr.TNavigator.__dict__.keys(): #Checks if the object also exists in TNavigator
obj = getattr(tr.TNavigator, key)
if hasattr(obj, "__call__") and ("self" in ins.getargspec(obj)[0]): #Checks if the function
uses a self argument
obj = partial(obj, _turtle) #Pass in the turtle we just created automatically
else:
obj = getattr(tr, key)
d[key] = obj #Transfer object reference from myModule to userProgram
return _turtle
def mainloop():
tk.mainloop()
#userProgram
from myModule import *
attachTurtle()
forward(100)
mainloop()
Note: Lets say trM is the turtle module and trI is an instance of RawTurtle.
I have noticed for example that trM.forward(10) is applied on the default screen , and trI.forward(x) is applied on the tkinter screen. Additionally functions such as forward(x) (after having done from turtle import *) are actually calling trM.TNavigator.forward(trI, x).
Turtle has confused me enough for me to code up a recursive object inspector, but i still can't tell what needs to change.
Okay, I found where i went wrong.
The fix is to use:
if elem != "mainloop":
d[elem] = obj
Instead of just d[elem] = obj
Turns out that the default window is created when turtle's mainloop() is called.
In theory, mainloop() in userProgram is the mainloop() in myModule. Unfortunately, because of attachTurtle() (and more specifically d[elem] = obj) this definition gets overwritten with turtle's mainloop(). So the fix is just to prevent attachTurtle() from changing mainloop().
The lesson to be learned is to check what definitions you are creating, in case you're overwriting an important one.
I can't believe I went digging in the source code when the solution was this simple

Python UnboundLocalError: local variable referenced before assignment

I'm confused. What is different about player1_head compared to the other variables I am printing in the code below? As far as I can tell it should behave the same as the others - it's declared in the global scope, no? I don't think it's a typo.
UnboundLocalError: local variable 'player1_head' referenced before assignment
from turtle import *
from random import randint
from utils import square, vector
player1_xy = vector(-100, 0)
player1_aim = vector(4, 0)
player1_body = []
player1_head = "It looks like I'm assigning here."
def draw():
"Advance player and draw game."
print("xy: ", player1_xy)
print("head: ", player1_head)
print("body: ", player1_body)
player1_xy.move(player1_aim)
player1_head = player1_xy.copy()
player1_body.append(player1_head)
square(player1_xy.x, player1_xy.y, 3, 'red')
update()
ontimer(draw, 200)
setup(420, 420, 370, 0)
hideturtle()
tracer(False)
draw()
done()
Because you failed to declare player1_head as a global, in the draw() function it appears to that function that you're printing out local variable player1_head before it has a value:
print("head: ", player1_head)
# ...
player1_head = player1_xy.copy()
Instead do:
def draw():
""" Advance player and draw game. """
global player1_head
print("xy: ", player1_xy)
print("head: ", player1_head)
print("body: ", player1_body)
player1_xy.move(player1_aim)
player1_head = player1_xy.copy()
player1_body.append(player1_head)
square(player1_xy.x, player1_xy.y, 3, 'red')
update()
ontimer(draw, 200)
The assignment player1_head = player1_xy.copy() in the draw() function is saying to Python that the variable player1_head is a local variable to the function draw(), and since print("head: ", player1_head) is referencing a local variable before its assignment, the error is shown. You can fix this by using player1_head as a global variable (since you're modifying it, same goes for the variable player1_body, since you're doing player1_body.append(player1_head)), like so:
def draw():
"Advance player and draw game."
global player1_head
#...rest of the code
Note however that you should avoid using global variables when possible, this is one the problems that arises from using them (they can be modified by any function, which can sometimes lead to errors and confusions).

How do I assign values to a variable with a schedule function in pyglet?

With the following code
x=1.0
def update(dt):
space.step(dt)
def xprinter(self, x):
print (x)
return x+1
if __name__ == "__main__":
x=pyglet.clock.schedule(xprinter,x)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
My return is simply 1.0 over and over. I would like for the value to be updated with each call. What am I missing?
The design here is based on that your function rely on returning a result.
Which causes a problem because Pyglet's internal functions are in charge of executing that function at a interval, meaning you're not the one executing the call - and there for you're not the one getting that return value, Pyglet is.
And since there's no meaningful way for Pyglet to relay that returned value (there are ways, but they involve hooking in and overriding certain internal functions), you will never see that return value.
The quick and easy workaround would be to do:
x=1.0
def update(dt):
space.step(dt)
def xprinter(self):
global x
print(x)
x += 1
if __name__ == "__main__":
pyglet.clock.schedule(xprinter)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
This way, the schedule call will update the global variable x rather than returning the result of the math equation.
A more neat approach would be to define a class with the x attribute and pass a class instance to the pyglet.clock.schedule():
class player():
def __init__(self):
self.x = 0
def update(dt):
space.step(dt)
def xprinter(self, p):
print(p)
p.x += 1
if __name__ == "__main__":
p = player()
x = pyglet.clock.schedule(xprinter, p)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
And if I'm not completely out of the ball park, this would remember the value across clock ticks, because of the instance.
This is also usually what you'll be using the schedule for, doing player / game / animation updates.

How can I prevent my python game from reiterating and instead carry on?

I've made a simple game using pygame and livewires, where a sprite has to avoid falling mushrooms. The number of mushrooms falling at a certain time is meant to increase as the score increases. Here is what I mean:
from livewires import games,color
import random
games.init(screen_width=633,screen_height=479,fps=50)
class Stick_Man(games.Sprite):
def update(self):
self.x=games.mouse.x
if self.left<0:
self.left=0
if self.right>games.screen.width:
self.right=games.screen.width
self.check_collision()
def check_collision(self):
if self.overlapping_sprites:
self.over_message()
def over_message(self):
b=games.Message(value="Game Over", size=100, color=color.red,x=games.screen.width/2,y=games.screen.height/2,lifetime=250,after_death=games.screen.quit)
games.screen.add(b)
class Mushroom(games.Sprite):
score=0
start=200
score_required=100
level=1
total_score=0
speed=1
mushroom=games.load_image("mushroom.jpg")
x_position=random.randrange(640)
#staticmethod
def next_level():
indicate='Level ', + Mushroom.level, ' cleared'
message=games.Message(value=indicate,size=50,color=color.red,x=games.screen.width/2,y=games.screen.height/2, lifetime=150)
games.screen.add(message)
Mushroom().score_required+=50
Mushroom().score-=Mushroom.score_required
Mushroom().start-=150
Mushroom().speed+=5
Mushroom().level+=1
if Mushroom().start==20:
Mushroom().start+=10
def __init__(self):
super(Mushroom,self).__init__(image=Mushroom.mushroom,x=games.mouse.x,y=0)
def update(self):
self.dy=Mushroom.speed
self.check()
self.check2()
def check(self):
if self.bottom==games.screen.height:
self.destroy()
Mushroom.score+=50
Mushroom.total_score+=Mushroom.score
if Mushroom().score==Mushroom.score_required:
self.next_level()
def check2(self):
if self.top==Mushroom.start:
self.duplicate()
def duplicate(self):
new_mush=Mushroom()
games.screen.add(new_mush)
background_image=games.load_image("background.jpg", transparent=False)
games.screen.background=background_image
stickman_image=games.load_image("stickman.png", transparent=True)
stickman=Stick_Man(image=stickman_image,left=1,bottom=480)
games.screen.add(stickman)
games.mouse.is_visible=False
b=Mushroom()
c=Mushroom()
a=Mushroom()
games.screen.add(b)
games.screen.add(a)
games.screen.add(c)
games.screen.event_brab=True
games.screen.mainloop()
The code is pretty self explanatory and whenever one of the mushrooms is equal to start, then a new object is created thus meaning a new mushroom comes in. However, what happens is that code doesn't function properly a second time and the mushrooms don't get faster spawn much faster either. Also, when the game first starts, the minute the first mushroom hits the bottom it says level one cleared, when it should be after two mushrooms. The sprite is just a red mushroom and also a stickman which can be found on g images if you want to simulate.
So my question is how do i make the object's STATS carry on from where it left off whenever another mushroom appears and also display the message at the right time
Your problem is in all of the lines that look like this:
Mushroom().score_required+=50
There are a number of problems here, which all together add up to make this have no useful effect:
Mushroom() creates a new Mushroom instance (which goes away as soon as this line is done).
Assigning (including update-assigning) to an attribute through an instance always creates or updates an instance attribute, even if there was a class attribute of the same name.
The += operator doesn't mutate immutable values like integers in-place (because that would be impossible); a += b is effectively the same as a = a + b.*
So, when you put that together, what you're doing is creating a new value equal to Mushroom.score_required + 50, then assigning that value to a new instance attribute of a temporary instance (which immediately goes away). This has no effect on the class attribute, or on any of the other instances.
You have a related, but different, problem in the lines like this:
x_position=random.randrange(640)
Unless you want all of the mushrooms to have the same x_position, this should not be a class attribute, but an instance attribute, and you're going to run into all kinds of strange problems.
Storing game stats as class attributes of a random class is a strange thing to do. There are ways you could make that work, but there's no good reason to even try. Class attributes are useful for constants that all instances of the class might as well share, but they're not useful as a substitute for global variables.
A better design would be something like this:
class Game(object):
def __init__(self):
self.score = 0
self.start = 200
self.score_required = 100
self.level = 1
self.total_score = 0
def next_level(self):
indicate = 'Level ', + Mushroom.level, ' cleared'
message = games.Message(value=indicate, size=50, color=color.red,
x=games.screen.width/2, y=games.screen.height/2,
lifetime=150)
games.screen.add(message)
self.score_required += 50
self.score -= self.score_required
self.start -= 150
self.speed += 5
self.level += 1
if self.start == 20:
self.start += 10
def update_score(self, n):
game.score += n
game.total_score += game.score
if self.score == self.score_required:
self.next_level()
class Mushroom(games.Sprite):
mushroom=games.load_image("mushroom.jpg")
def __init__(self, game):
self.x_position=random.randrange(640)
self.game = game
super(Mushroom,self).__init__(image=Mushroom.mushroom,x=games.mouse.x,y=0)
def update(self):
self.dy=Mushroom.speed
self.check()
self.check2()
def check(self):
if self.bottom == games.screen.height:
self.destroy()
game.update_score(50)
def check2(self):
if self.top == Mushroom.start:
self.duplicate()
def duplicate(self):
games.screen.add(Mushroom(self.game))
game = Game()
games.screen.add(Mushroom(game))
games.screen.add(Mushroom(game))
games.screen.add(Mushroom(game))
games.screen.event_brab=True
* That's not completely true. In fact, a = a + b is equivalent to a = a.__add__(b), while a += b is equivalent to a = a.__iadd__(b) if such a method exists, falling back to __add__ only if it doesn't. For mutable objects like lists, this makes a big difference, because __iadd__ can change self in-place and then return it, meaning you end up assigning the same object back to a that was already there. But for immutable objects, there's no difference.

Categories

Resources