Screenshot of output image
I made a random walk program using turtle and I want it show where the two turtles cross paths by changing the color.
`import turtle as T
import random as R
t = T.Turtle()
u = T.Turtle()
t.speed(0)
u.speed(0)
t.hideturtle()
u.hideturtle()
t.color("red")
u.color("blue")
def randWalk(num):
for i in range(0, num):
x = R.choice((-1,1))
X = R.choice((-1,1))
y = R.choice((-1,1))
Y = R.choice((-1,1))
t.forward(x)
u.forward(X)
if y == 1:
t.left(90)
t.forward(1)
else:
t.right(90)
t.forward(1)
if Y == 1:
u.left(90)
u.forward(1)
else:
u.right(90)
u.forward(1)
randWalk(4000)`
Turtle can't interrogate what color is currently on the screen, so one way to approach this might be to have some sort of backing store where you keep track of what color was written to what pixel. Here's a rough example using Python lists:
from turtle import Screen, Turtle
from random import choice
WIDTH, HEIGHT = 300, 300
PEN_COLORS = ['red', 'blue']
OVERLAP_COLOR = 'green'
def randWalk(number):
for _ in range(number):
for turtle in turtles:
direction = choice((-1, 1))
turtle.forward(direction)
x, y = map(round, turtle.position())
old_color = color = turtle.pencolor()
turtle.undo() # undo forward()
if grid[y][x] and grid[y][x] != color:
color = OVERLAP_COLOR
turtle.pencolor(color)
turtle.goto(x, y) # redo forward()
turtle.pencolor(old_color)
grid[y][x] = color
choice((turtle.left, turtle.right))(90)
screen.update()
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.tracer(False)
grid = [[None] * WIDTH for _ in range(HEIGHT)]
turtles = []
for color in PEN_COLORS:
turtle = Turtle()
turtle.hideturtle()
turtle.pencolor(color)
turtles.append(turtle)
randWalk(4000)
screen.tracer(True)
screen.exitonclick()
There is additional complication in the code as turtle walks a floating point plane but we need to coerce it to an integer plane to accommodate our backing store and reduce undesirable drawing artifacts.
Related
I am creating a project that loads an image and converts it to 1 and zeros it will then draw this using turtle. However, every time I run it tells me that it has stopped working after the first column has been completed. If the problem is with the processing power of my computer I would like to know if there is a way to switch to a GPU to achieve the task. Any help would be greatly appreciated. Thanks
def ShowMaze(possibleRoutes):
turtle.delay(0)
for x in range(0,len(Maze)):
for y in range(0,len(Maze[0])):
if Maze[x][y]==3:
Maze[x][y]=0
for x in range(0,len(Maze)):
turtle.forward(-5)
turtle.right(90)
turtle.forward(5/len(Maze[0]))
turtle.left(90)
for y in range(0,len(Maze[0])):
if Maze[x][y]==1:
turtle.fillcolor("black")
turtle.begin_fill()
elif Maze[x][y]==0:
turtle.fillcolor("white")
turtle.begin_fill()
elif Maze[x][y]==4:
turtle.fillcolor("green")
turtle.begin_fill()
elif Maze[x][y]==5:
turtle.fillcolor("red")
turtle.begin_fill()
for i in range(0,4):
turtle.forward(5/len(Maze[0]))
turtle.left(90)
turtle.end_fill()
turtle.forward(5/len(Maze[0]))
input()
for ii in range(1,len(possibleRoutes)-1):
turtle.pu()
turtle.home()
turtle.forward(-250)
turtle.forward((250/len(Maze))*possibleRoutes[ii][1])
turtle.right(90)
turtle.forward((250/len(Maze))*possibleRoutes[ii][0]+(250/len(Maze)))
turtle.left(90)
turtle.fillcolor("blue")
turtle.pd()
turtle.begin_fill()
for x in range(0,4):
turtle.forward(250/len(Maze[0]))
turtle.left(90)
turtle.end_fill()
im = Image.open('D:/MazeSolver/ExampleMazePicture.JPG') # Can be many different formats.
pix = im.load()
size=250
Maze=[]
length=im.size[0] # Get the width and hight of the Maze for iterating over
for x in range(0,size,8):
print("Row",x)
row=[]
for y in range(0,size,2):
pix = im.load()
if pix[x,y]>=(200,200,200):
node=0
elif pix[x,y][0]>200 and pix[x,y][2]<200 and pix[x,y][1]<200:
node=4
print("End")
elif pix[x,y][1]>200 and pix[x,y][0]<50 and pix[x,y][2]<50:
node=5
print("Start")
elif pix[x,y]<=(50,50,50):
node=1
else:
print(pix[x,y])
row.append(node)
Maze.append([row])
ShowMaze(Maze)
This code is a mess. You input a JPEG maze image, called Maze, into a two dimensional array and pass it to ShowMaze(Maze) to show that you've read it in correctly. But ShowMaze() accesses Maze globally and thinks its argument is ShowMaze(possibleRoutes) where possibleRoutes through the maze were never calculated? Also: the X and Y sense of Maze seems inverted; the rows of the maze have an extra layer of list wrapped around them for no apparent reason; there's dead code included; you're not reading it in as 1s and 0s but rather four different color codes; the drawing code seems hopeless.
I've reworked your code to simply read the maze into a list of lists and then display it with turtle using stamping instead of drawing to both simplify and speed up the code:
from turtle import Screen, Turtle
from PIL import Image
CURSOR_SIZE = 20
PIXEL_SIZE = 5
COLORS = {0: 'white', 1: 'black', 4: 'green', 5: 'red'}
def ShowMaze(maze):
height, width = len(maze), len(maze[0])
screen = Screen()
screen.setup(width * PIXEL_SIZE, height * PIXEL_SIZE)
screen.setworldcoordinates(0, height, width, 0)
turtle = Turtle('square', visible=False)
turtle.shapesize(PIXEL_SIZE / CURSOR_SIZE)
turtle.penup()
screen.tracer(False)
for y in range(height):
for x in range(width):
color = maze[y][x]
if color in COLORS:
turtle.fillcolor(COLORS[color])
else:
turtle.fillcolor("orange") # error color
turtle.stamp()
turtle.forward(1)
turtle.goto(0, turtle.ycor() + 1)
screen.tracer(True)
screen.mainloop()
image = Image.open('ExampleMazePicture.JPG') # Can be many different formats.
width, height = image.size # Get the width and height of the Maze for iterating over
pixels = image.load()
maze = []
for y in range(0, width, 4):
print("Row:", y)
row = []
for x in range(0, width, 4):
node = -1
pixel = pixels[x, y]
if pixel >= (200, 200, 200):
node = 0
elif pixel[0] > 200 and pixel[1] < 200 and pixel[2] < 200:
node = 4
print("End")
elif pixel[0] < 50 and pixel[1] > 200 and pixel[2] < 50:
node = 5
print("Start")
elif pixel <= (50, 50, 50):
node = 1
else:
print(pixel)
row.append(node)
maze.append(row)
ShowMaze(maze)
Output based on using "Figure 1.6: Picobot’s maze." from this page as input:
Hopefully this should provide you a starting point for the program you're ultimately trying to develop.
So I'm still very new to python and trying to learn through making small projects.
The game I'm making is meant to test your mouse accuracy by creating a bunch of random circles which the player is meant to click in a given amount of time. At the end of the game, it should tell the player their score, and how many misclicks they had.
I've been using turtle to try and do this, but I'm stuck:
import turtle
import random
t = turtle.Pen()
win = turtle.Screen()
win.bgcolor("lightgreen")
win.title("clicky")
def mycircle(red, green, blue):
t.color(red, green, blue)
t.begin_fill()
x = random.randint(10,50)
t.circle(x)
t.end_fill()
t.up()
y = random.randint(0,360)
t.seth(y)
if t.xcor() < -300 or t.xcor() > 300:
t.goto(0, 0)
elif t.ycor() < -300 or t.ycor() > 300:
t.goto(0, 0)
z = random.randint(0,100)
t.forward(z)
t.down()
for i in range(0, 20):
a = random.randint(0,100)/100.0
b = random.randint(0,100)/100.0
c = random.randint(0,100)/100.0
mycircle(a, b, c)
The main issues I've been trying to figure out are:
How can I make the circles spawn further from each other? They overlap
quite often and I want that to be avoided.
How can I make the circles spawn instantly rather than having to be
drawn?
How can I make the circles spawn further from each other?
We can keep track of circles already created and make sure their centers are at least a diameter away from each other. Your current circle placement logic is too complicated along with being faulty. Let's try to simplify it and make sure circles are drawn completely within the window.
How can I make the circles spawn instantly rather than having to be
drawn?
We could stamp them rather than draw them. However, since you are drawing so few circles, we can make every circle a turtle. This makes determining if you clicked on a circle, and removing that circle, simpler. I've added code, for you to expand on, that removes any circle that you click on:
from turtle import Turtle, Screen
from random import random, randint
CURSOR_SIZE = 20
def my_circle(color):
radius = randint(10, 50)
circle = Turtle('circle', visible=False)
circle.shapesize(radius / CURSOR_SIZE)
circle.color(color)
circle.penup()
while True:
nx = randint(2 * radius - width // 2, width // 2 - radius * 2)
ny = randint(2 * radius - height // 2, height // 2 - radius * 2)
circle.goto(nx, ny)
for other_radius, other_circle in circles:
if circle.distance(other_circle) < 2 * max(radius, other_radius):
break # too close, try again
else: # no break
break
circle.showturtle()
circle.onclick(lambda x, y, t=circle: t.hideturtle()) # expand this into a complete function
return radius, circle
screen = Screen()
screen.bgcolor("lightgreen")
screen.title("clicky")
width, height = screen.window_width(), screen.window_height()
circles = []
for _ in range(0, 20):
rgb = (random(), random(), random())
circles.append(my_circle(rgb))
screen.mainloop()
One issue you need to work out is making sure your circle color isn't too similar to (or the same as) your background color, otherwise you'll be hunting an invisible circle. Also, we might be able to speed up the circle drawing process even more, if needed.
I'm new to turtle graphics in Python, and I'm running into some issues with a particular problem. I'm trying to generate a star that uses a while loop to draw random jagged lines from the center of a circle.
Each line should have a distance of 250. I'm using the penup pendown and setpos commands within the loop to draw these random lines, and each line should be a random color.
Here's an idea of what I'm hoping to generate: random star
Here's the code I have so far:
# tg_random_star.py
from random import randrange
from turtle import *
MAX_ANGLE = 30
def jaggedLine(turtle, pieces, pieceLength):
for i in range(pieces):
turtle.forward(pieceLength)
r = randrange(-MAX_ANGLE, MAX_ANGLE + 1)
turtle.right(r)
def jumpToCenter(turtle):
turtle.penup()
turtle.setpos(0, 0)
turtle.pendown()
def randomColor(turtle):
turtle.colormode(255)
r = randrange(255) # red component of color
g = randrange(255) # green component
b = randrange(255) # blue component
turtle.pencolor(r, g, b)
def main():
colormode(255)
t = Turtle()
jaggedLine(t, 10, 30)
jumpToCenter(t)
jaggedLine(t, 10, 30)
if __name__ == "__main__":
main()
It currently generates 2 lines, but the turtle.pencolor(r, g, b) and the colormode(255) don't seem to be working, as both lines are black. Any idea why these lines aren't in color?
Rather than using for i in range(pieces) to draw lines that are based on the number of segments, how can I use a while loop to draw jagged lines that each have a distance of 250? In other words, I want each line to have a distance of 250 before drawing a new line from the center.
(Maybe I could use the xcor and ycor methods to find the turtle’s position, then calculate the distance using the distance formula?)
def distance(p0, p1):
return math.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)`
Any help or explanation would be appreciated, thank you.
Any idea why these lines aren't in color?
That one's easy, it's because you never actually call randomColor()
Rather than using for i in range(pieces) to draw lines that are based
on the number of segments, how can I use a while loop to draw jagged
lines that each have a distance of 250?
Here we can take advantage of the under utilized .distance() method of turtle to tell us how far we are from center. This is straight line distance, not path travelled distance, which seems to match your target illustration:
from turtle import Turtle, Screen
from random import randrange
MAX_ANGLE = 30
MAX_DISTANCE = 250
def jaggedLine(t, pieceLength):
randomColor(t)
while t.distance(0, 0) < MAX_DISTANCE:
angle = randrange(-MAX_ANGLE, MAX_ANGLE + 1)
t.right(angle)
t.forward(pieceLength)
def jumpToCenter(t):
t.penup()
t.home() # return turtle to original position
t.pendown()
def randomColor(t):
# red, green & blue components of turtle color
r, g, b = randrange(255), randrange(255), randrange(255)
t.pencolor(r, g, b)
def main():
screen = Screen()
screen.tracer(False) # because I have no patience
screen.colormode(255)
turtle = Turtle()
turtle.hideturtle()
turtle.pensize(2)
for angle in range(0, 360, 2):
jumpToCenter(turtle)
turtle.setheading(angle)
jaggedLine(turtle, 30)
screen.tracer(True) # forces an update
screen.mainloop()
if __name__ == "__main__":
main()
OUTPUT
I am trying to make a program in Turtle that draws a Christmas Tree and then some baubles, which I want to be placed randomly on the tree. However because a Christmas Tree is an irregular shape I am not able to place the baubles by randomly choosing x and y co-ordinates. Is there a way to randomly place the baubles on the tree?
I was considering an "turtle.pendown()" and then "if turtle.pen touching "green"" but I am not sure how to code this.
Any help would be greatly appreciated.
One simple, graphic, approach is to:
Find a Python module that has a routine for performing the "point
in polygon"
inclusion
test
Use turtle's begin_poly(), end_poly(), and get_poly() to capture the
vertices that your code generates when drawing the tree
Randomly generate ornaments within the bounding box of the tree but
also apply the crossing number test to see if their centers are on
the tree
Here's an example implementation using an (exceptionally) abstract tree and ornaments:
from turtle import Turtle, Screen
from random import randrange, choice
from point_in_polygon import cn_PnPoly
screen = Screen()
WINDOW_WIDTH, WINDOW_HEIGHT = screen.window_width(), screen.window_height()
COLORS = ["red", "yellow", "gold", "blue", "white", "pink"]
def draw_abstract_tree(turtle):
width = WINDOW_WIDTH//4
turtle.penup()
turtle.goto(0, -WINDOW_HEIGHT//4)
turtle.pendown()
for _ in range(8):
turtle.forward(width)
turtle.left(150)
turtle.forward(1.156 * width)
turtle.right(150)
width *= 0.9
turtle.left(210)
for _ in range(8):
turtle.forward(1.156 * width)
turtle.left(150)
turtle.forward(width)
turtle.right(150)
width /= 0.9
turtle.goto(0, -WINDOW_HEIGHT//4)
turtle.setheading(0)
def decorate_tree(turtle, polygon):
turtle.penup()
for _ in range(1000):
x = randrange(-WINDOW_WIDTH/4, WINDOW_WIDTH/4)
y = randrange(-WINDOW_HEIGHT/4, WINDOW_HEIGHT)
diameter = randrange(1, 12)
if cn_PnPoly((x, y), polygon):
turtle.goto(x, y)
turtle.color(choice(COLORS))
turtle.dot(diameter)
yertle = Turtle(visible=False)
yertle.speed("fastest")
yertle.color("darkgreen")
yertle.begin_poly()
draw_abstract_tree(yertle)
yertle.end_poly()
polygon = yertle.get_poly()
yertle.begin_fill()
draw_abstract_tree(yertle)
yertle.end_fill()
decorate_tree(yertle, polygon)
screen.exitonclick()
OUTPUT
I think turtle doesn't have method to check color.
But turtle uses Canvas from tkinter which have function find_overlaping(rectangle) to check if some objects overlaps this rectangle. Maybe it could works. Maybe you could check if there is tree in some small rectange in random place.
turtle.getcanvas()
tkinter: Canvas.find_overlapping()
I want to draw circles in 3 random colors. But in this code, used to draw the circles, the output is without color:
import turtle
window=turtle.Screen()
tess= turtle. Turtle()
import random
def getColor():
color=random.randint(1,3)
if color==1:
color="red"
elif color==2:
color=="yellow"
elif color==3:
color=="blue"
return color
print (random.randint(1,3))
def drawFace (x,y):
tess.penup()
tess.goto(x+5,y+10)
tess.circle(10)
tess.goto(x+15,y+10)
tess.circle(10)
tess.pendown()
In the getColor() function, you're not assigning to the color variable when it is yellow or blue - you're using double equal. Here's the fixed version:
def getColor():
color=random.randint(1,3)
if color==1:
color="red"
elif color==2:
color="yellow"
elif color==3:
color="blue"
return color
Secondly, you picked the pen up in the beginning of drawFace() and never put it down before finishing! Here's the fix:
def drawFace (x,y):
tess.penup()
tess.goto(x+5,y+10)
tess.pendown()
tess.circle(10)
tess.penup()
tess.goto(x+15,y+10)
tess.pendown()
tess.circle(10)
You don't need to pick random numbers to index your colors, you can randomly pick one directly with random.choice(). You need to call GetColor() and apply the color you've chosen via tess.pencolor() We also tend to think of positioning circles based on their center but Python turtle doesn't so we need to (explicitly) adjust for that as you did (implicitly) in your code:
from turtle import Turtle, Screen
import random
RADIUS = 10
def getColor(turtle):
choice = turtle.pencolor()
while choice == turtle.pencolor():
choice = random.choice(["red", "green", "blue"])
return choice
def drawFace(turtle, x, y):
turtle.pencolor(getColor(turtle))
turtle.penup()
turtle.goto(x, y - RADIUS)
turtle.pendown()
turtle.circle(RADIUS)
tess = Turtle()
drawFace(tess, 5, 0)
drawFace(tess, 15, 0)
screen = Screen()
screen.exitonclick()