How to pull tuples out of a list and make a turtle connect it as coordinates? - python-3.x

Write a function called connectTheDots that takes in a list of tuples as its input and an optional color input as well. The default color value should be black. Each tuple is a coordinate pair (x, y) for a turtle. The function will have the turtle trace out a picture by starting at the first coordinate and then moving to each coordinate in turn.
Your function should do the following:
a. Create a turtle, setting the turtle’s color and speed appropriately
b. Check if the input list is empty: if it is empty then nothing else should happen!
c. Without leaving a line behind, move the turtle to the first location given in the list. Then start leaving a line again. Note: recall how to pull values out of a list, and also know that the goto method can take a single (x, y) tuple as its input: myTurtle.goto( (25, 25) ) will move myTurtle to x = 25 and y = 25.
d. After the turtle is at the starting coordinate, move it to each coordinate in the list in turn.
This is what I have been able to do so far:
def connectTheDots(list1, color ="black"):
myTurtle = turtle.Turtle()
myTurtle.speed(1)
myTurtle.goto(list1[0])
for x,y in list1[1:]: #I'm unsure if this is correct
myTurtle.goto(x,y)

You have most of what you need but are probably making it more complicated than needed and are missing some small details.
For step "a" you need to explicitly set the color (you passed it in just fine). You are probably better off using a symbolic speed instead of a numeric one.
For step "b", if you have a proper for ... in loop, you don't need to explicitly check if the list is empty as the loop won't run if it is. Your splitting off the first item myTurtle.goto(list1[0]) works against you here as there may not be one, causing an IndexError.
For step "c" you need to add another command. Turtles start life in the center of the screen with their pens down. You need to raise the pen up after creating your turtle. But you don't need to explicitly move to the starting position, let your loop handle that.
The trick we'll use for step "c" and step "d" is to put the pen down after the goto() in the loop. The first time, this actually puts the pen down, after that, it's a harmless no-op:
import turtle
def connectTheDots(coordinates, color="black"):
myTurtle = turtle.Turtle()
myTurtle.speed("slowest")
myTurtle.color(color)
myTurtle.penup()
for coordinate in coordinates:
myTurtle.goto(coordinate)
myTurtle.pendown() # redundant after first iteration
dots = ((34, 56), (100, 240), (230, 105), (34, 56))
connectTheDots(dots, "green")
turtle.done()
If it bothers you that we're putting the pen down unnecessarily in the loop, then we can replace myTurtle.pendown() with:
if not myTurtle.isdown():
myTurtle.pendown()

Related

how can I rotate line with only changing theta?

I was making animation with manim and I tried to make line that one end is fixed, and one end moves along the arc. The way I wanted to solve this problem was to define each point with theta, and let the point move along the arc as it moves. However, even if the setta was changed, the line did not move, so the rotate was used, but the length of the line did not change, so the line deviated from the arc and failed. I wonder how to make the line move smoothly with the size of the angle when theta value is changed to an arbitrary value with theta as a parameter.
from manim import *
import numpy as np
class RotateVector(Scene):
def construct(self):
theta = 1/9*np.pi
semicircle = Arc(angle=PI, radius=4, stroke_color = GREY, arc_center=np.array([0, -1.5, 0]))
bottom_line = Line(start=np.array([-4.0,-1.5,0]), end=np.array([4.0,-1.5,0]), stroke_color = GREY)
dot_A = np.array([-4.0,-1.5,0])
dot_A_text = Text('A', font_size=35).next_to(dot_A, LEFT+DOWN, buff=0.05)
dot_P = np.array([4*np.cos(theta*2),4*np.sin(theta*2)-1.5,0])
dot_P_text = Text('P', font_size=35).next_to(dot_P, RIGHT+UP, buff=0.05)
line_AP = Line(start=np.array([-4.0,-1.5,0]), end=np.array([4*np.cos(2*theta),4*np.sin(2*theta)-1.5,0]), stroke_color = GREY)
self.play(Create(semicircle), Create(bottom_line), Create(dot_A_text))
self.play(Create(line_AP), Create(dot_P_text))
self.wait(3)
Your mobjects do not change because the dependency on Theta is not retained after initializing the mobject -- but it doesn't take too much to make it work!
The solution to your Problem is using a ValueTracker for the value of theta (to easily allow animating changing it) and updater functions for the mobjects you would like to change. In other words:
theta_vt = ValueTracker(theta)
dot_P_text.add_updater(lambda mobj: mobj.next_to([4*np.cos(theta_vt.get_value()*2),4*np.sin(theta_vt.get_value()*2)-1.5,0]))
line_AP.add_updater(lambda mobj: mobj.put_start_and_end_on([-4, 1.5, 0], [4*np.cos(theta_vt.get_value()*2),4*np.sin(theta_vt.get_value()*2)-1.5,0]))
self.play(theta_vt.animate.set_value(2*PI))
You could even avoid the value tracker and use an auxiliary (empty) mobject for positioning:
P = Mobject().move_to([4*np.cos(theta*2),4*np.sin(theta*2)-1.5,0])
and then change the updaters to use the position of P instead of theta, and make the point move along the desired arc. (That point actually is the one that becomes slightly more complicated, while the updaters simplify a bit.)

Pygame for loop iterates once, and then does not iterate again

Essentially, what I'm doing is taking the enemies list (on line 1), which is holding a list of coordinates and iterate through each pair in the enemies list at the bottom.
I want to go through each enemy in the list, get the y coordinate, add 10 and then go to the next enemy and add 10, so on and so forth. For some reason, it adds 10 ONCE and then stops, and the enemies do not fall down the screen. I don't know why this is happening. Why is it not running through the for loop anymore? Thank you so much for any help.
NOTE: I removed some code at the top for the sake of being less confusing. The update() function is just the pygame flip function.
enemies = [[100,0], [150,0]]
while True:
for enemy in enemies:
x = enemy[0]
y = enemy[1]
y += 10
pygame.draw.rect(screen, (255,0,0), (x, y,10,10))
# uses flip to update the screen
update()
# FPS
clock.tick(20)
You're trying to modify a local variable, not the value in the list. You need to write:
enemy[1] += 10
Since integers are immutable (they cannot be changed), the line y = enemy[1] can be thought of as "copy the value from enemy[1] into y".

Get just the x or y pos with pygame.mouse.get_pos

I want to know how to get the x-coordinate position or the y-coordinate position of the mouse individually on pygame.
Like just the x and just the y. I think It would use
pygame.mouse.get_pos
Pygame doesn't have an API that will get you only one coordinate, you always get both. But it returns them in a 2-tuple, so you can index to get just one value if you want to:
x = pygame.mouse.get_pos()[0]
If there's any chance you might need the y coordinate as well, it might make sense to unpack as normal anyway, and just ignore the y value in the part of the code where you don't need it:
x, y = pygame.mouse.get_pos()
# do stuff with x, ignore y
if something_rare_happens():
# do stuff with y too
It might even be clearer to do the unpacking even if you'll never use y, but that's really up to you.

How can I append Turtle clones to a list without cloning indefinitely?

I have to write a program in Python using Turtle that reads a list of instructions from a file and draws a Turtle diagram based on the inputs. The possible inputs are forward, left, right, and split. If the input is split, I have to clone all of the turtles in a list and append the new Turtles to the list. All new clones should be turned right by x degrees. The problem is, the turtles clone indefinitely.
def navigate(directions):
turtles = []
commands = []
first = turtle.Turtle()
turtles.append(first)
turtle.width(10)
for turt in turtles:
turt.speed('fastest')
for step in directions:
if step[0] == 'forward':
turt.forward(step[1])
elif step[0] == 'left':
turt.left(step[1])
elif step[0] == 'right':
turt.right(step[1])
elif step[0] == 'split':
new = turt.clone()
turtles.append(new)
turt.right(step[1])
Directions is a list of tuples where the first value of each tuple is the command (e.g. forward, left, right, or split) and the second is the degree (How far forward to go, how many degrees to turn). But the turtle continue to clone forever. How can I adjust this code so that it only clones a given number of times? Here is my sample input file:
forward 50
left 20
split 40
forward 50
left 20
split 40
forward 50
left 20
split 40
forward 50
left 20
split 40
forward 50
left 20
Firstly, you have a logic error. Your outer loop iterates over the turtles, and then inside the loop, it processes all the steps for each turtle separately. This is incorrect; even if it worked, it would apply instructions from before the split to turtles created after it. (That would effectively apply those preceding instructions twice to the same turtle, as well as execute the split again.) You need to process a single step at a time on all turtles. So the loop needs to be over the directions, not the turtles:
for step in directions:
# Process the step
Now that we have the loops swapped, a solution becomes more obvious. We can check the step and have special handling for the 'split' case:
for step in directions:
if step[0] == 'split':
# Clone all the turtles here
else:
for turt in turtles:
if step[0] == 'forward':
turt.forward(step[1])
elif step[0] == 'left':
...
I chose to use a single loop for the movement cases, but it would be equally valid to have a loop for each case if you prefer.
We still have the issue of creating the clones and adding them to the list. You already saw this won't work:
for turt in turtles:
turtles.append(turt.clone())
So we need to store all these new clones without modifying the list we're looping over. We can do that with a temporary list:
turtle_clones = []
for turt in turtles:
turtle_clones.append(turt.clone())
And then we just need to put turtle_clones onto the end of turtles. I'll leave combining the two lists as an exercise for you.
Bonus Material
Here are some suggestions to make your code cleaner:
Use unpacking so you don't have to have indexes everywhere.
You actually don't need to access the two pieces of data in step using an index. You can use unpacking to put each element in its own variable:
for action, value in directions:
if action == 'split':
...
else:
...
turt.forward(value)
This makes you code much simpler and easy to read, although you can probably think of a better name for value.
You actually don't have to use an explicit temporary list and for loop to make the clones. You can use a list comprehension:
turtle_clones = [t.clone() for t in turtles]
Again, much simpler and easy to read.
The first variable appears unnecessary. You can initialize the list containing the first turtle directly:
turtles = [turtle.Turtle()]

Pygame blitting only updated surfaces

Right now I have an x by y array to hold integers that decide which tile to draw to the screen. (The integers choose which tile in my tile_arr to blit)
For better performance, I only want the ints that changed to be blit'ed again.
EXAMPLE 1:
For example right now I have something like:
tile_arr = [image1,image2,image3,image4]
arr = [[2,2,2],[2,2,2],[2,2,2]]
Then depending on what the user does, some values in arr might change, so lets say:
arr[0][0]=1
arr[2][1]=1
Which would give us the array:
arr=[[1,2,2],[2,2,2],[2,1,2]]
now when blitting to the screen, I would blit images from the tile_arr: image numbers 1,2,2 to the top row, 2,2,2, to the middle row, and 2,1,2 to the bottom row. When I blit the array, I use a screen.blit for each value or arr, that's nine blits. I would rather only do two blits. (Use screen.blit only twice)
EXAMPLE 2:
tile_arr = [green.bmp, red.bemp, blue.bmp]
feild_arr = [[0,0,0], [0,0,0], [0,0,0]]
Output:
G G G
G G G
G G G
User changes feild_arr to [[1,0,1], [0,2,0], [0,1,2]]
Output:
R G R
G B G
G R B
Now I only want to call sceen.blit() 5 times, leaving the 4 Green sqaures green, because nothing changed.
I thought of making another array, which would be just a copy of the first. Then run through it and compare to the new array to see what changed, but I think there is a better and faster way to this. Now the example is only 3x3 so making a duplicate array isn't too bad, but I'm working with a lot bigger arrays, and when you're blitting a 30x20 array, I need all the shortcuts I can get.
How do I only blit when the interger values in an array have been changed, and skip (don't blit) the values that have not changed?
You can use screen.blit only once, calling with a list of the rectangles that changed.
I think the best aproach is to create you own class deriving from DirtySprite:
class Cell: pygame.sprite.DirtySprite
which already has attributes for holding an image and a rectangle and you can add an attributes to hold the number and a method to change de number that will set it as dirty.
Then you can use LayeredDirty class to render the dirty sprites on the screen.

Resources