How to initialize multiple turtles in Python with classes - python

I am a beginner at Python and I'm new to Stack Exchange. I'm trying to write a program that has 5 turtles moving within a square. I've got code that does what I want, but it's tedious and I'd like to initialize all my turtles using classes instead of doing it one by one. I just want them to start out at random coordinates and with a random heading.
The problems with my code:
Only one turtle is shown on screen. Two are defined in the code below.
The turtle's heading and coordinates aren't being initialized.
Here's the code that I've tried:
import numpy as np
from turtle import *
# setting up screen
reset()
screensize(550)
Screen().bgcolor('black')
tracer(0)
# drawing box
t0 = Turtle()
t0.penup()
t0.goto(-256,-256)
t0.color('cyan')
t0.pendown()
for i in range(4):
t0.forward(512)
t0.left(90)
t0.ht()
# parameters
velocity = 5
iterations = 200
boxsize = 512
ranheader = np.random.random()*360
ranx = np.random.random()*boxsize
rany = np.random.random()*boxsize
class turtle_agents(Turtle):
def _init_(self):
self.up()
self.seth(ranheader)
self.setpos(ranx,rany)
self.velocity = velocity
self.down()
# turtle
t1 = turtle_agents()
t1.color('green')
t2 = turtle_agents()
t2.color('blue')
# turtle movement
for turtle in turtles():
for i in range(iterations):
turtle.forward(velocity)
if turtle.xcor() >= 256:
turtle.goto(-256,t0.ycor())
elif turtle.xcor() <= -256:
turtle.goto(256,t0.ycor())
elif turtle.ycor() >= 256:
turtle.goto(t0.xcor(),-256)
elif turtle.ycor() <= -256:
turtle.goto(t0.xcor(),256)
update()
exitonclick()

only one turtle shown on screen. Two are defined in the code below.
the turtle's heading and coordinates aren't being initialized.
I believe the problem is that you defined the random position and heading once, outside the turtle creation loop so they all start in the same place, move in the same direction at the same speed. I.e. they're right on top of each other.
We don't need #BlivetWidget's explicit List to fix the problem since, as you discovered, turtles are already maintained in a list which we can get via the screen's turtles() method. Below is my rework of your code to fix various issues:
from turtle import Screen, Turtle
from random import randrange, randint
# parameters
COLORS = ['green', 'blue', 'red', 'orange', 'white']
ITERATIONS = 500
VELOCITY = 5
BOX_SIZE = 512
# setting up screen
screen = Screen()
screen.setup(BOX_SIZE + 50, BOX_SIZE + 50)
screen.bgcolor('black')
screen.tracer(False)
# drawing box
turtle = Turtle()
turtle.hideturtle()
turtle.color('cyan')
turtle.penup()
turtle.goto(-BOX_SIZE/2, -BOX_SIZE/2)
turtle.pendown()
for _ in range(4):
turtle.forward(BOX_SIZE)
turtle.left(90)
# turtle
for color in COLORS:
angle = randrange(360)
x = randint(-BOX_SIZE/2, BOX_SIZE/2)
y = randint(-BOX_SIZE/2, BOX_SIZE/2)
turtle = Turtle()
turtle.color(color)
turtle.setheading(angle)
turtle.penup()
turtle.setposition(x, y)
turtle.pendown()
# turtle movement
for _ in range(ITERATIONS):
for turtle in screen.turtles():
turtle.forward(VELOCITY)
x, y = turtle.position()
if x >= BOX_SIZE/2:
turtle.penup()
turtle.setx(-BOX_SIZE/2)
turtle.pendown()
elif x <= -BOX_SIZE/2:
turtle.penup()
turtle.setx(BOX_SIZE/2)
turtle.pendown()
elif y >= BOX_SIZE/2:
turtle.penup()
turtle.sety(-BOX_SIZE/2)
turtle.pendown()
elif y <= -BOX_SIZE/2:
turtle.penup()
turtle.sety(BOX_SIZE/2)
turtle.pendown()
screen.update()
screen.exitonclick()
I agree with #BlivetWidget that "you don't need to create a class just to move them to your starting positions". I use a simple loop above.

You should consider storing your turtles in a list, as the turtles are already objects and you don't need to create a class just to move them to your starting positions. Lists in Python are incredibly powerful because they can store arbitrary data types. Here, I will create 5 turtles and move them so you can tell them apart:
import turtle
num_turtles = 5
my_turtles = [turtle.Turtle() for i in range(num_turtles)]
for i, turt in enumerate(my_turtles):
turt.forward(50 * i)
You want to do the same thing, just replace my turt.forward() line with whatever you want the turtles to do. In your case, go to a random position within your square.

Related

Drawing a triangle using only a grid of circles, python

I have to make a change to this specific code, which produces a square grid of circles, I have to change the code to make a triangle grid of circles.
import turtle
window = turtle.Screen()
my_boi = turtle.Turtle()
my_boi.speed(0)
for y in range(-200,200,50):
for x in range(-200,200,50):
my_boi.penup()
my_boi.setposition(x,y)
my_boi.pendown()
my_boi.circle(20)
window.exitonclick()
I'm sure there is a smarter approach, but this is one way to do it:
import turtle
window = turtle.Screen()
my_boi = turtle.Turtle()
my_boi.speed(0)
for (i,y) in enumerate(range(-200,200,50)):
for x in range(-200+(25*i),200-(25*i),50):
my_boi.penup()
my_boi.setposition(x,y)
my_boi.pendown()
my_boi.circle(20)
window.exitonclick()
turtle.done()
In the second for-loop the range is iteratively decreased by 1/2 of the circle diameter in each side.
I'd simplify things somewhat:
from turtle import Screen, Turtle
window = Screen()
my_boi = Turtle()
my_boi.speed('fastest')
my_boi.penup()
for y in range(1, 9):
my_boi.setposition(-25 * y + 25, 50 * y - 250)
for x in range(y):
my_boi.pendown()
my_boi.circle(20)
my_boi.penup()
my_boi.forward(50)
my_boi.hideturtle()
window.exitonclick()
Only the starting position of each row has to be calculated and placed via setposition(). The column positions can be a simple forward() statement.
I know this is an old post, but I was looking for the answer and managed to figure it out, so to help everyone else out, All you need to do is change the stop range in the nested loop to be y. I switched the x and y variables because I wanted the triangle to be flat, but if you need it the other way that also works.
import turtle
window = turtle.Screen()
my_boi = turtle.Turtle()
my_boi.speed(0)
for x in range(-200,200,50):
for y in range(-200,x,50):
my_boi.penup()
my_boi.setposition(x,y)
my_boi.pendown()
my_boi.circle(20)
window.exitonclick()

How to create a tessellation with turtles in Python

I'm trying to create a rhombus tessellation pattern with the turtle graphics on python that looks like this image:
http://www.supercoloring.com/sites/default/files/styles/coloring_medium/public/cif/2015/01/tessellation-with-rhombus-coloring-pages.png
I thought about creating a hexagon pattern first and then dividing the hexagons into thirds. I'm not sure how I can create the hexagon pattern recursively. So far, I'm only alternating the angles of the turtles as I run the program and I don't have a definite strategy. Any advice on how to approach this?
So far, I created 3 hexagons in the center with 3 turtles and used for loops to draw the hexagons around the 3 hexagons. However, when I loop the program, the turtles trace back the same path as before and it takes a while for it to draw the others.
Here is my code so far:
import turtle
t = turtle.Turtle()
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t1.left(120)
t2.left(240)
for i in (t, t1, t2):
i.speed(0)
def hex():
for b in (t, t1, t2):
for i in range(6):
b.forward(100)
b.right(60)
for i in range(3):
t.left(120)
hex()
def rep():
for i in range(3):
for a in (t, t1, t2):
a.forward(100)
a.right(60)
for i in range(6):
a.forward(100)
a.left(60)
rep()
def rep2():
for a in (t, t1, t2):
for i in range(3):
a.left(120)
a.forward(100)
a.right(60)
rep()
a.right(120)
a.forward(100)
a.right(60)
rep()
rep2()
There are many of drawing this. I would draw based the rhombus shape because it will allow you to fill them with different colors. To be able to fill each rhombus, it needs to be drawn individually. The figure contains three different rhombus shapes (they are the same rhombus in different orientation).
I will draw first row and second row. After that it is repetition of the first and second row. Here is code:
def draw_rhombus(x,y,degree,size,tilt,color):
turtle.up()
turtle.goto(x,y)
turtle.seth(tilt)
turtle.down()
turtle.pencolor('dark gray')
turtle.fillcolor(color)
turtle.begin_fill()
turtle.fd(size)
turtle.left(degree)
turtle.fd(size)
turtle.left(180-degree)
turtle.fd(size)
turtle.left(degree)
turtle.fd(size)
turtle.left(180-degree)
turtle.end_fill()
def draw_rhombus_1(x,y,size):
draw_rhombus(x,y,120,size,0,'red')
def draw_rhombus_2(x,y,size):
draw_rhombus(x,y,60,size,0,'green')
def draw_rhombus_3(x,y,size):
draw_rhombus(x,y,60,size,60,'blue')
def rt_row_1(startx,starty,size,n):
x = startx
y = starty
for i in range(n):
draw_rhombus_1(x,y,size)
x += size
draw_rhombus_3(x,y,size)
draw_rhombus_2(x,y,size)
x += 2*size
def rt_row_2(startx,starty,size,n):
x = startx
y = starty
for i in range(n):
draw_rhombus_2(x,y,size)
x += 2*size
draw_rhombus_1(x,y,size)
x += size
draw_rhombus_3(x,y,size)
size = 80
x = -400
y = -400
for i in range(800//int(round(size*math.sqrt(3)))):
rt_row_1(x,y,size,800//(size*3))
rt_row_2(x-size/2,y+size*math.sqrt(3)/2,size,800//(size*3))
y += size*math.sqrt(3)
First, let's simplify your three turtle, three function hexagonal tessellation to a single turtle, single recursive function solution:
from turtle import Screen, Turtle
OUTER_RADIUS = 100
INNER_RADIUS = 3**0.5 * OUTER_RADIUS / 2
SIDES = 6
EXTENT = 360 / SIDES
def tessellation(depth):
turtle.right(EXTENT/2)
for _ in range(SIDES):
turtle.circle(OUTER_RADIUS, EXTENT, 1)
if depth:
heading = turtle.heading()
turtle.right(90)
tessellation(depth - 1)
turtle.setheading(heading)
screen = Screen()
turtle = Turtle(visible=False)
screen.tracer(False) # because I have no patience
turtle.penup()
turtle.goto(-OUTER_RADIUS / 2, -INNER_RADIUS)
turtle.pendown()
tessellation(2)
screen.tracer(True)
screen.exitonclick()
(Increase the depth argument to fill the window.) The tessellation you really want is four (not thirds) of these patterns overlaid atop each other. Keeping our initial code the same:
screen = Screen()
turtle = Turtle(visible=False)
screen.tracer(False) # because I have no patience
turtle.penup()
turtle.color('blue')
turtle.goto(OUTER_RADIUS / 4, -1 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
turtle.penup()
turtle.color('red')
turtle.goto(-OUTER_RADIUS / 2, -2 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
turtle.penup()
turtle.color('yellow')
turtle.goto(OUTER_RADIUS / 4, -3 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
turtle.penup()
turtle.color('green')
turtle.goto(-OUTER_RADIUS / 2, -4 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
screen.tracer(True)
screen.exitonclick()

New to Python: Turtle 25 squares checkerboard using loops

def main():
square(0,0,50,'red')
def square(x,y,width,color):
turtle.penup()
turtle.goto(0,0)
turtle.fillcolor(color)
turtle.pendown()
turtle.begin_fill()
for number in range(5):
for count in range(4):
turtle.forward(width)
turtle.left(90)
turtle.end_fill()
x = x+50
turtle.goto(x,y)
turtle.showturtle()
Call the main function
main()
This gives me one row of 5 squares. How do i code an outer loop to draw 4 more
of rows of such 5 squares - a 5 by 5 checkerboard?
I simplified your "square" function to only draw a single square. Then I added a separate function which included a nested loop that calls the square function.
Trying to keep it simple and have only one responsibility for each function:
import turtle
def main():
board(5, 5, 50)
input("Hit enter to close")
def square(x,y,width,color):
turtle.penup()
turtle.fillcolor(color)
turtle.goto(x, y)
turtle.pendown()
turtle.begin_fill()
for side in range(4):
turtle.forward(width)
turtle.left(90)
turtle.end_fill()
def board(rows, columns, square_width):
turtle.showturtle()
for row in range(rows):
for column in range(columns):
color = "red" if (row + column)%2 == 1 else "white"
square(row*square_width, column*square_width, square_width, color)
turtle.hideturtle()
You already have code to draw a row of squares, that's the loop you have right now.
You want that code to be run 5 times, so just wrap it in another loop, making sure to modify variables as necessary. Something along the lines of this:
for i in range(5):
for number in range(5):
for count in range(4):
turtle.forward(width)
turtle.left(90)
turtle.end_fill()
x += width
turtle.goto(x,y)
x -= 5*width
y += width
Also a note on style, square() is ignoring most of its parameters. You hardcode your turtle to go to (0,0), regardless of the values of x and y. Because your later gotos use these values, your code will break if you set them to anything other than 0. Your line x = x+50 also ignores the value of width, even though the line the turtle draws uses it. Again, if you set it to anything other than 50, this will break.

How do I make a dot disappear after being eaten?

I am attempting to program a python game using turtle-graphics, and I've run into some obstacles. When I run my code it allows me to direct the turtle around, then a whole bunch of dots start appearing, and then it has recursion depth error.
The section of code that I am having issues with is this:
def move():
colormode(255)
global turtle
global moving
x = randomColor()
if moving:
for i in range(1):
turtle.penup()
turtle.shape('turtle')
turtle.shapesize(.5, .5, .5)
turtle.color(x)
turtle.forward(5)
ontimer(move, 10 // FRAMES_PER_SECOND)
x = randrange(-250, 250)
y = randrange(-250, 250)
pen1 = Pen()
pen1.hideturtle()
pen1.penup()
pen1.goto(x, y)
pen1.dot(10, "red")
if turtle.pos() == pen1.pos():
pen1.clear()
pen1.goto(x, y)
How can I fix this? I want the dot to disappear when the turtle goes over it, and then a new random dot to generate, only one dot at a time.
you should:
Draw red point once on start and save the coordination.
After each move check the turtle position with your last_point (x,y).
If same, draw a dot in the same position with color of background(white I think).
3.1. Then create new random x,y and redraw the red dot.
The way I'd go about this is to define a second turtle with the shape and color of the food. Then stamp that turtle to generate food, keeping the result of the stamp() call so you can call clearstamp(stamp) on it later. I've set such up below with lots of food which the turtle chases down until they're all gone:
from turtle import Turtle, Screen
from random import randrange
WIDTH, HEIGHT = 500, 500
FRAMES_PER_SECOND = 24
TARGET_SIZE = 10
POSITION, STAMP = 0, 1
def move():
global meal
x, y = meal[POSITION]
tx, ty = turtle.position()
if x - TARGET_SIZE // 2 < tx < x + TARGET_SIZE // 2 and y - TARGET_SIZE // 2 < ty < y + TARGET_SIZE // 2:
food.clearstamp(meal[STAMP])
if meals:
meal = meals.pop()
else:
meal = None
if meal:
turtle.setheading(turtle.towards(meal[POSITION]))
turtle.forward(turtle.speed())
screen.ontimer(move, 1000 // FRAMES_PER_SECOND)
screen = Screen()
screen.setup(int(WIDTH * 1.1), int(HEIGHT * 1.1)) # size window but leave a border
turtle = Turtle(shape='turtle')
turtle.speed("fast")
turtle.penup()
food = Turtle(shape="circle", visible=False)
food.shapesize(0.5, 0.5)
food.color("red")
food.penup()
meals = []
for _ in range(10):
x = randrange(-WIDTH // 2, WIDTH // 2)
y = randrange(-HEIGHT // 2, HEIGHT // 2)
food.goto(x, y)
meals.append(((x, y), food.stamp()))
meal = meals.pop()
screen.ontimer(move, 1000 // FRAMES_PER_SECOND)
screen.exitonclick()
This turtle just chase a random bit of food, you can modify the code to make him go after the nearest food (as you have the list of meals with their positions) or take control of the turtle yourself.
Do:
(name).up()
(name).forward(10000)

How Can I Fill These Squares in Turtle - Python

I am trying to fill the color in these squares:
Right now the turtle only fills the corners of theses squares, not the entire square.
Here is my code:
import turtle
import time
import random
print ("This program draws shapes based on the number you enter in a uniform pattern.")
num_str = input("Enter the side number of the shape you want to draw: ")
if num_str.isdigit():
squares = int(num_str)
angle = 180 - 180*(squares-2)/squares
turtle.up
x = 0
y = 0
turtle.setpos(x,y)
numshapes = 8
for x in range(numshapes):
turtle.color(random.random(),random.random(), random.random())
x += 5
y += 5
turtle.forward(x)
turtle.left(y)
for i in range(squares):
turtle.begin_fill()
turtle.down()
turtle.forward(40)
turtle.left(angle)
turtle.forward(40)
print (turtle.pos())
turtle.up()
turtle.end_fill()
time.sleep(11)
turtle.bye()
I've tried moving around turtle.begin_fill() and end_fill() in numerous locations with no luckā€¦ Using Python 3.2.3, thanks.
I haven't really used turtle, but it looks like this may be what you want to do. Correct me if I've assumed the wrong functionality for these calls:
turtle.begin_fill() # Begin the fill process.
turtle.down() # "Pen" down?
for i in range(squares): # For each edge of the shape
turtle.forward(40) # Move forward 40 units
turtle.left(angle) # Turn ready for the next edge
turtle.up() # Pen up
turtle.end_fill() # End fill.
You're drawing a series of triangles, using begin_fill() and end_fill() for each one. What you can probably do is move your calls to begin_fill() and end_fill() outside the inner loop, so you draw a full square and then ask for it to be filled.
Use fill
t.begin_fill()
t.color("red")
for x in range(4):
t.fd(100)
t.rt(90)
t.end_fill()
Along with moving begin_fill() and end_fill() outside the loop, as several folks have mentioned, you've other issues with your code. For example, this is a no-op:
turtle.up
I.e. it doesn't do anything. (Missing parentheses.) This test:
if num_str.isdigit():
Doesn't do much for you as there is no else clause to handle the error. (I.e. when it isn't a number, the next statement simply uses the string as a number and fails.) This calculation seems a bit too complicated:
angle = 180 - 180*(squares-2)/squares
And finally there should be a cleaner way to exit the program. Let's address all these issues:
from turtle import Screen, Turtle
from random import random
NUMBER_SHAPES = 8
print("This program draws shapes based on the number you enter in a uniform pattern.")
num_str = ""
while not num_str.isdigit():
num_str = input("Enter the side number of the shape you want to draw: ")
sides = int(num_str)
angle = 360 / sides
delta_distance = 0
delta_angle = 0
screen = Screen()
turtle = Turtle()
for x in range(NUMBER_SHAPES):
turtle.color(random(), random(), random())
turtle.penup()
delta_distance += 5
turtle.forward(delta_distance)
delta_angle += 5
turtle.left(delta_angle)
turtle.pendown()
turtle.begin_fill()
for _ in range(sides):
turtle.forward(40)
turtle.left(angle)
turtle.forward(40)
turtle.end_fill()
screen.exitonclick()

Categories

Resources