I am a student taking my first python class and we are using Turtle to draw an image. In an effort to save time I am trying to create a mirror function that can flip one functions results over the y-axis by a given number of pixels. For the sake of simplicity I created some functions to speed up my coding. Here is how my code works:
units, north, east, south, west = desiredPixelsPerUnit, 90, 0, 270, 180
def main():
eye(30, 15)
eye(40, 15)
def left():
myTurtle.left(90)
def draw(count):
distance = units * count
myturtle.forward(distance)
def singleStep(xDirection, yDirection, stepCount):
down()
for step in range(stepCount):
if yDirection == north:
point(north)
draw(1)
if xDirection == east:
point(east)
draw(1)
etc..
def eye(xPosition, yPosition):
....
draw(3)
left()
draw(2)
left()
....
singleStep(east, north, 1)
singleStep(west, north, 2)
etc....
All of this gives me the following
Result of running eye() in main twice:
What I am trying to create is a function that is passed another function then will look at what is being executed. if it is left() or right() run the opposite. If it is point (x, y) add 180 to x. If it has a function call that inside the function then it checks that as well for lefts or rights. Something like this.
def mirror(function):
for action in function:
if action == left():
execute right()
...
elif action == singleStep():
newFunction = singleStep()
for action in newFunction:
if:
statement above
else:
statement below
else:
execute initial action
I am still very new to coding and programming. I have tried using arrays, associative arrays and lists, using eval and more. The time spent trying to figure it out has been far longer than writing a separate instruction list for the left and the right hahah but I really want to figure out how to do something like this.
You could step back from calling left() and right() directly. Just create your own functions your_left() and your_right() and use them everytime. Then use a global variable called mirror. This variable will work as a flag for you. So you just set mirror to True when you want to mirror the output.
Your functions your_right() and your_left() will be looking something like this:
def your_right():
left() if mirror else right()
def your_left():
right() if mirror else left()
And then you are free to mirror all your outputs, if you want to. I hope i could help!
Here is how you can do that using yield:
import turtle
def function(): # Your function here, with the action calls replaced with yielding the un-called action, along with the argument
for _ in range(4):
yield turtle.forward, 100
yield turtle.right, 90
def mirror(function):
actions = {turtle.right: turtle.left,
turtle.left: turtle.right,
turtle.forward: turtle.backward,
turtle.backward: turtle.forward}
for action, argument in function():
actions[action](argument)
mirror(function)
Breaking it down:
When defining the function that will be passed into the mirror function,
do not call the turtle commands. Instead, use yield to yield the functions and arguments
as tuples, so that the mirror function will be able to access which functions should be called.
In the mirror function, define a dictionary of turtle commands, actions, that would be used to mirror with.
Iterate through the yielded turtle actions from the function passed into the brackets of the mirror function, and unpack the tuples into action, argument pairs to be used to mirror.
Related
I am trying to use Shady to present a sequence of image frames. I'm controlling the flow from another machine, so that I first instruct the machine running Shady to present the first frame, and later on to run the rest of the frames.
I create a World instance, and attach to it an animation callback function. Within this callback I listen for communications from the other machine (using UDP).
First I receive a command to load a given sequence (stored as a numpy array), and I do
def loadSequence(self, fname):
yy = np.load(fname)
pages = []
sz = yy.shape[0]
for j in range(yy.shape[1]/yy.shape[0]):
pages.append(yy[:, j*sz:(j+1)*sz])
deltax, deltay = (self.screen_px[0] - sz) / 2, (self.screen_px[1] - sz) / 2
if (self.sequence is None):
self.sequence = self.wind.Stimulus(pages, 'sequence', multipage=True, anchor=Shady.LOCATION.UPPER_LEFT, position=[deltax, deltay], visible=False)
else:
self.sequence.LoadPages(pages, visible=False)
When I receive the command to show the first frame, I then do:
def showFirstFrame(self, pars):
self.sequence.page = 0 if (pars[0] == 0) else (len(self.sequence.pages) - 1)
self.sequence.visible = True
But what do I do now to get the other frames to be be displayed? In the examples I see, s.page is set as a function of time, but I need to show all frames, regardless of time. So I was thinking of doing something along these lines:
def showOtherFrames(self, pars, ackClient):
direction, ack = pars[0], pars[2]
self.sequence.page = range(1, len(self.sequence.pages)) if (direction == 0) else range(len(self.sequence.pages)-2, -1, -1)
But this won't work. Alternatively I thought of defining a function that takes t as argument, but ignores it and uses instead a counter kept in a global variable, but I'd like to understand what is the proper way of doing this.
When you make s.page a dynamic property, the function assigned to it must take one argument (t), but you can still just use any variables in the space when defining that function, and not even use the time argument at all.
So, for example, you could do something as simple as:
w = Shady.World(...)
s = w.Stimulus(...)
s.page = lambda t: w.framesCompleted
which will set the page property to the current frame count. That sounds like it could be useful for your problem.
Your global-variable idea is one perfectly valid way to do this. Or, since it looks like you're defining things as methods of an instance of your own custom class, you could use instance methods as your animation callbacks and/or dynamic property values—then, instead of truly global variables, it makes sense to use attributes of self:
import Shady
class Foo(object):
def __init__(self, stimSources):
self.wind = Shady.World()
self.stim = self.wind.Stimulus(stimSources, multipage=True)
self.stim.page = self.determinePage # dynamic property assignment
def determinePage(self, t):
# Your logic here.
# Ignore `t` if you think that's appropriate.
# Use `self.wind.framesCompleted` if it's helpful.
# And/or use custom attributes of `self` if that's
# helpful (or, similarly, global variables if you must).
# But since this is called once per frame (whenever the
# frame happens to be) it could be as simple as:
return self.stim.page + 1
# ...which is indefinitely sustainable since page lookup
# will wrap around to the number of available pages.
# Let's demo this idea:
foo = Foo(Shady.PackagePath('examples/media/alien1/*.png'))
Shady.AutoFinish(foo.wind)
Equivalent to that simple example, you could have the statement self.stim.page += 1 (and whatever other logic) inside a more-general animation callback.
Another useful tool for frame-by-frame animation is support for python's generator functions, i.e. functions that include a yield statement. Worked examples are included in python -m Shady demo precision and python -m Shady demo dithering.
It can also be done in a StateMachine which is always my preferred answer to such things:
import Shady
class Foo(object):
def __init__(self, stimSources):
self.wind = Shady.World()
self.stim = self.wind.Stimulus(stimSources, multipage=True)
foo = Foo(Shady.PackagePath('examples/media/alien1/*.png'))
sm = Shady.StateMachine()
#sm.AddState
class PresentTenFrames(sm.State):
def ongoing(self): # called on every frame while the state is active
foo.stim.page += 1
if foo.stim.page > 9:
self.ChangeState()
#sm.AddState
class SelfDestruct(sm.State):
onset = foo.wind.Close
foo.wind.SetAnimationCallback(sm)
Shady.AutoFinish(foo.wind)
I have a script for a simple turtle race and I want the race to start when the user clicks the left-mouse-button so i have this code
def tur_race():
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race())
turtle.mainloop()
Assume that I have all variables defined.
when I run this code the race starts automatically and doesn't wait for the click.
onscreenclick takes a function as its parameter. You shouldn't be calling tur_race, turtle will do that when there is a click, rather you should pass tur_race itself. This is called a callback, you provide a function or method to be called by some event listener(e.g. the mouse being clicked on the screen).
In addition to #nglazerdev excellent answer, this would be your code after you apply what he said.
from turtle import *
def tur_race():
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race)
turtle.mainloop()
You take out the () in the tur_race function. Otherwise, it will be called immediately.
Hope this helps!!
You need turtle.onscreenclick( tur_race ) without () after tur_race
Python can assign function's name (without () and arguments) to variable and use it later - like in example
show = print
show("Hello World")
It can also use function's name as parameter in other function and this function will use it later.
Offen (in different programming languages) this funcion's name is called "callback"
In turtle.onscreenclick( tur_race ) you send name to function onscreenclick and turtle will use this function later - when you click screen.
If you use () in turtle.onscreenclick( tur_race() ) then you have situation
result = tur_race()
turtle.onscreenclick( result )
which doesn't work in you code but can be useful in another situations.
In addition to everyone's answer, you need to add x and y parameters in the tur_race function. This is because turtle passes x and y parameters to the function, so your code would look like:
from turtle import *
def tur_race(x, y):
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race)
turtle.mainloop()
I have created the following function that allows the user to change the shape of the Python turtle to an image he/she selects from a file dialog file dialog that pops up when a specific button is pressed:
def TurtleShape(iop = None):
# "iop" is supposed to be an image path
try:
manipulateimage.config(state = NORMAL)
flipButton.config(state = NORMAL)
mirrorButton.config(state = NORMAL)
originalButton.config(state = NORMAL)
resetturtle.config(state = NORMAL)
rotateButton.config(state = NORMAL)
global klob
# The following "if-else" statement uses the "iop" argument's value as the value for "klob" if `iop` is NOT `None`
if iop != None:
klob = iop
print("lmcv")
else:
klob = filedialog.askopenfilename()
print("klobby")
global im
im = Image.open(klob)
pictures.append(im)
edited.clear()
print(im)
im.save(klob + '.gif', "GIF")
register_shape(klob + '.gif')
shape(klob + '.gif')
update()
except:
pass
The above function is also supposed to use the iop argument's value as the turtle's image if it is not None.
Now, consider this situation; you draw a bunch of things, set the turtle to an image, and just when you are about to stamp the image, you accidentally press the button that resets the turtle to its normal shape (yes, that button exists in my program). Oh no! How would you get it back without going through all the steps to open and edit it again? Well, that is where my undoHandler function (shown below) comes in. It just essentially undoes the last function called using many stacks, which I created as deques. It is pretty straightforward if you are proficient in Python:
def undoHandler():
if len(function) > 0 and draw.drawing == True:
undoHandler.handling = True
if not hasattr(undoHandler, "counter"):
undoHandler.counter = 0
undoHandler.counter += 1
# clear the canvas
Clear()
# Pop a point object from function deque
function.pop()
penup()
goto(-200, 100)
pendown()
try:
# Execute everything up to point before last function called
for i in function:
# Set canvas and turtle to previous state
tsd = i.recieveshape()
shape(tsd)
mndf = i.recieveheading()
setheading(mndf)
hk = i.getletterheight()
global letter_height
letter_height = hk
rk = i.getletterwidth()
global letter_width
letter_width = rk
milk = i.getspacewidth()
global space_width
space_width = milk
hw = i.getwidth()
width(hw)
op = i.getcolor()
try:
color(op)
except:
for g in colors:
cp = g.getcolor2()
colormode(255)
color(cp)
# Get function wrapped in Point object and execute it
j = i.getfunction()
j()
# Following is the code block where the issue occurs. Basically, if the function being run is equal to `TurtleShape`, then do the following...
if j.__name__ == "TurtleShape":
# `hfl` is a deque that holds all of the `pictures` deque's contents as it is cleared when the turtle is set to its default state
pictures.extend(hfl)
lmcv = pictures.pop()
pictures.append(lmcv)
try:
# Resize image to previous size if user changes it. Otherwise, skip this.
bun = picwidth.pop()
picwidth.append(bun)
mun = picheight.pop()
picheight.append(mun)
clob = lmcv.resize((int(bun), int(mun)), Image.ANTIALIAS)
except:
clob = lmcv
clob.save(klob + str(undoHandler.counter) + ".gif")
# Use the `clob.save` output from above as source image in `TurtleShape` function (this is where issue occurs)
TurtleShape(klob + str(undoHandler.counter) + ".gif")
print("Undone!")
else:
pass
except:
pass
Basically what happens here is that it takes the function (wrapped in a Point object) from a queue through which the main functions go through as they are called. The functions then get appended to the function deque, after which, when undoHandler is called by the user, the screen gets cleared, and latest value is popped from the function deque so that all the other actions except the last one will be executed again. This issue I am facing occurs specifically in the if j.__name__ == "TurtleShape": code block. Basically, for some reason, when the user chooses to undo the resetting of the turtle to its original shape, it works as it should until the TurtleShape function is executed by the undoHandler. For some reason, when the undoHandler executes the TurtleShape function, even when I give a valid argument for the iop attribute of the TurtleShape function (as you can see in the if j.__name__ == "TurtleShape": code block), the else statement is executed first (i.e. the file dialog comes up instead of continuing from the if statement). Only if the user clicks cancel in that dialog will the turtle get set to the previous image.
What is wrong in my code that is leading to this occurrence, and how would I stop this from happening? I have tried changing the klob attribute in the function where the output is saved in the undoHandler function to, for example, "SaveImage", but still no luck. I have also tried to add an if-elif statement in the TurtleShape when it is supposed to choose between iop or a file dialog as the value for klob, but still the issue occurs. Apparently, it executes the elif statement even when it is not necessarily true. Therefore, any help is very much appreciated in remedying this issue! :)
It's happening here:
j = i.getfunction()
j()
If the function you've just gotten is the TurtleShape() function, then you're calling it once with its default arguments (i.e., iop = None). Then you go into your big if j.__name__ == "TurtleShape": statement and call it again inside the if block.
Move that j() call into the else: block of your big if j.__name__ == "TurtleShape": statement, and your problem should go away.
Does that brief explanation make enough sense for you to understand why the problem is happening? Or do you need me to explain a bit more in-depth how calling j() is calling TurtleShape with the parameter iop = None?
I'm drawing my name using turtles and I have a bunch of different functions for each of the letters
like so (for letter r)
def letter_r(t):
def letter_r_top(t):
turtle.lt(90)
turtle.fd(150)
turtle.rt(90)
turtle.circle(-37.5,180)
turtle.lt(130)
def letter_r_leg(t):
csquare = ((75**2) + (37.5**2))
sidec = math.sqrt(csquare)
turtle.fd(sidec)
letter_r_top(rob)
letter_r_leg(rob)
After each letter, i need to move the turtle into the right place to setup for the next letter. Because each of the letters are different sizes I need to make custom movements depending on what the previous letter is but I dont want to make separate functions for each of those movements.
At the end of my code I have the list of functions to be called in the correct order to spell my name
letter_t(rob)
letter_setup(rob)
letter_r(rob)
letter_setup(rob)
.....
Is there a way that I can do something like this so that I will only need 1 setup function.(Not real code, just a conceptualization of what I'm thinking
def letter_setup(t):
if previously executed function A
turtle.fd(75)
if previously executed function B
turtle.fd(75)
turtle.lt(90)
if previously executed function C
turtle.fd(75)
turtle.lt(90)
Why not the movement to the right place for the next letter at the end of the previous letter?
Perhaps there is a better way to do this but you could make a variable last_function_called and in each function you give it a different value then you'll know wich one was the last called :
last_function_called = NONE;
def function1():
last_function_called = FUNCTION1
blablabla
...
if (last_function_called == FUNCTION1):
call another one
and before of course something like :
NONE = 0
FUNCTION1 = 1
FUNCTION2 = 2
ect...
I'm writing my first program in python and it has to simulate the mixing of particles (two gases). I don't know what am I doing wrong with this function.
I don't want the particles to leave certain area, that is the walls of container.
I use VPython.
def poruszanie(lista,pozycja,numCell):
flaga = 0
pozycjaTmp = (pozycja[0]+choice([-1,0,1]),pozycja[1]+choice([-1,0,1]),0)
for i in range( 0, len(lista) ):
if pozycjaTmp==lista[i].pos:
flaga=1
if flaga==1:
return poruszanie(lista,(pozycja[0]+choice([-1,0,1]),pozycja[1]+choice([-1,0,1]),0),numCell)
elif pozycjaTmp[0]==0 or pozycjaTmp[0]==numCell or pozycjaTmp[0]==-numCell or pozycjaTmp[1]==numCell or pozycjaTmp[1]==-numCell:
return poruszanie(lista,(pozycja[0]+choice([-1,0,1]),pozycja[1]+choice([-1,0,1]),0),numCell)
return pozycjaTmp
poruszanie - name of function
pozycja - position of the sphere
0,numCell,-numCell - the borders of container (0 is the wall in the middle that separate the gasses in the beggining)
All of this is in the x,y plane and z is always 0
That's where I start to use this function:
while 1:
rate(20)
for i in range(0,len(self.listBalls)):
self.listBalls[i].pos=poruszanie(self.listBalls,self.listBalls[i].pos,self.numCell)
I think you're calling it exactly the same each time and not returning properly:
if flaga==1:
return poruszanie(lista,(pozycja[0]+choice([-1,0,1]),pozycja[1]+choice([-1,0,1]),0),numCell)
else:
if pozycjaTmp[0]==0 or pozycjaTmp[0]==numCell or pozycjaTmp[0]==-numCell:
poruszanie(lista,(pozycja[0]+choice([-1,0,1]),pozycja[1]+choice([-1,0,1]),0),numCell)
elif pozycjaTmp[1]==numCell or pozycjaTmp[1]==-numCell:
poruszanie(lista,(pozycja[0]+choice([-1,0,1]),pozycja[1]+choice([-1,0,1]),0),numCell)
From the first call you return, but from the next two, you don't. Also, the parameters you're passing look to be exactly the same.
Edit
Considering the edit and your new error (maximum depth reached).
That error means that your function is recursing farther than python allows.
I'm still not sure what you're doing but you need a base condition at which point no matter what the recursion will stop. If you're satisfying either branch of the if ... elif ... statement each time you call the function, your recursion will never stop. You need something that will always break, and preferably you should place it before the if .. elif ... block.