I'm a newbie in python so please bear with me. I was making a program that draws a turtle shape using OOP and I'm running into some issues. The first issue I had is in my drawShape method I am required to draw a shape with the sides and length of my argument. It can be any regular shape so I chose square but I used t.forward inserting d as the length of the shape how can I add s as the side of my shape to draw it as required. The second issue I had is in my __str__ method I wanted to return the current state of my turtle position I used turtle.pos to return the position but how do I also include the current heading of the turtle. I added comments on what I'm trying to do all over my code to make it easier to understand my code. Any help is appreciated. Thanks in advance.
import turtle
import random
class Terrapin:
#list of 5 color names
colors = ["green", "yello", "red", "blue", "black"]
def __init__(self, win, tur, x, y, dir, color, width):
#win: The turtle screen/window. In __init__, create the window
self.win = win
#tur: The turtle object itself. In __init__,
#create a turtle and store it in this attribute
self.tur = tur
#current x location of the Turtle. Initialize to 0
self.x = x
#Current y location of the Turtle. Initialize to 0
self.y = y
#Current heading of the Turtle (angle). Initialize to 0
self.dir = dir
#Current color of the Turtle. Pick a random value from colors,
#and set the Turtle to that color
self.color = color
#Current width of the Turtle. Pick a random value from 1 to 5,
#and set the Turtle's width to that value
self.width = width
x = 0
y = 0
dir = 0
color = random.choice(colors)
width = randint(1, 5)
def updateLoc(self, newX, newY, newDir):
#Without drawing a line, move the Turtle to newX,
#newY,facing newDir.
#Update self.x, self.y, and self.dir to the new values
turtle.penup()
turtle.goto(newX, newY)
setheading(newDir)
self.x = newX
self.y = newY
self.dir = newDir
def whereAmI(self):
#Return a tuple of x, y, and dir.
return ("x", "y", "dir")
def drawShape(self, s, d):
#Draw a regular shape with "s" sides of length "d", starting at x, y, dir.
#Leave the Turtle pointing in the direction it started
#(i.e. self.dir at the end must equal self.dir at that start).
#Regular means equal length sides, like a triangle, square, hexagon, etc.
startPos = turtle.setworldcoordinates(x, y, dir)
turtle.setworldcoordinates(x, y, dir)
turtle.forward(d)
t.left(90)
turtle.forward(d)
t.left(90)
turtle.forward(d)
t.left(90)
turtle.forward(d)
t.left(90)
setheading(startPos)
def setWidth(self, w):
#Set the Turtle's width to w, and save in self.width.
self.width = w
def newColor(self):
#Set the Turtle's color to a new random value, and save in self.color.
newColor = turtle.pencolor(random.choice(colors))
turtle.pencolor(random.choice(colors))
self.color = newColor
def __str__(self):
#Returns the current turtle state as "x, y # dir"
#If the Turtle is at 10, 100 with a heading of 270, this will print "10, 100 # 270"
turtle.pos()
doug = Terrapin()
doug.drawShape(4, 200) # Draws a rectangle
doug.newColor()
doug.setWidth(4)
doug.drawShape(5, 100) # Draws a pentagram
doug.updateLoc(100, 50, 0)
doug.drawShape(3, 50)
print(doug)
You need something like this
doug = Terrapin(1,2,3,4,5,6,7,8)
But more broadly...
If you aren't sure what values you want to use, you probably need to think about what you program is going to do before you make it.
You look like you're using Turtle graphics, i would try to play around with that library before you make any object oriented stuff
UPDATED
"The first issue I had is in my drawShape method I am required to draw a shape with the sides and length of my argument. It can be any regular shape so I chose square but I used t.forward inserting d as the length of the shape how can I add s as the side of my shape to draw it as required."
This sounds like homework lol
I think you are talking about Equilateral polygons.
https://i.stack.imgur.com/Hy39S.png
So the sum of interior angles is (n-2)*180
So a single interior angle is (n-2)*180/n
So and then the angle to move for a d sided polygon is
180 - (d-2)*180/d
EI 4 sided square
180-(4-2)*180/4 = 90
"The second issue I had is in my str method I wanted to return the current state of my turtle position I used turtle.pos to return the position but how do I also include the current heading of the turtle."
So decide if you want to print or return this.
I think you probably want to print.
print(x,", ",y," # ",direction)
Note that dir is highlighted differently because it means something else and you cannot use it as a variable
Related
I'm trying to change the color and # of circles shown on the screen. So far, I've figured out how to make all of them different colors in a recursive pattern, but I need help finding out how to add more. Attached is what I have versus what I need to achieve.
my code
import turtle
import colorsys
def draw_circle(x,y,r,color):
turtle.seth(0)
turtle.up()
turtle.goto(x,y-r)
turtle.down()
turtle.fillcolor(color)
turtle.begin_fill()
turtle.circle(r)
turtle.end_fill()
def draw_recursive_circles(x,y,r,color,n):
if n == 0:
return
draw_circle(x,y,r,color)
colors = ['red','orange','yellow','green','blue','purple']
i = 0
for angle in range(30,360,60):
turtle.up()
turtle.goto(x,y)
turtle.seth(angle)
turtle.fd(r*2)
draw_recursive_circles(turtle.xcor(),turtle.ycor(),r/3,colors[i],n-1)
i += 1
turtle.tracer(0)
turtle.hideturtle()
turtle.speed(0)
draw_recursive_circles(0,0,100,'red',5)
turtle.update()
What I need to achieve
What I have so far
You import colorsys but never use it -- this is a clue that you're supposed to generate colors based on angles and not a fixed list of colors. The reason for the import is that turtle's RGB-based colors are the wrong model for our needs, so we want a more appropriate model, like HSV (where we only really care about H/hue), and have it convert those values to RGB.
The number of satellites is determined by your range call:
for angle in range(30,360,60):
Which for this drawing should be more like:
for angle in range(0, 360, 30):
As there are twelve satellites and 360 / 30 is 12. Finally, we need to do proper accounting such that whenever we change a position or heading, in order to do recursive drawing, we need to restore the original values on exit. Below is my simplified example solution to this problem:
from turtle import Screen, Turtle
from colorsys import hsv_to_rgb
def draw_circle(radius):
y = turtle.ycor() # save position & heading
heading = turtle.heading()
turtle.fillcolor(hsv_to_rgb(heading / 360, 1.0, 1.0))
turtle.sety(y - radius)
turtle.setheading(0)
turtle.begin_fill()
turtle.circle(radius)
turtle.end_fill()
turtle.sety(y) # restore position & heading
turtle.setheading(heading)
def draw_recursive_circles(radius, n):
if n == 0:
return
draw_circle(radius)
if n > 1:
heading = turtle.heading() # save heading
for angle in range(0, 360, 30):
turtle.setheading(angle)
turtle.forward(radius * 2)
draw_recursive_circles(radius / 5, n - 1)
turtle.backward(radius * 2)
turtle.setheading(heading) # restore heading
screen = Screen()
screen.tracer(False)
turtle = Turtle(visible=False)
turtle.penup()
draw_recursive_circles(150, 4)
screen.update()
screen.tracer(True)
screen.exitonclick()
I've intentionally kept the pen up to simplifiy my example so only filled portions of the circles are shown. Putting back the surrounding outlines I leave as an exercise for you.
The center circle is not the right color. Fixing this is a simple matter of setting the turtle's heading prior to the initial call to draw_recursive_circles()
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 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()
I need to make a circle by adjusting conditions on the heights, this program using a lot of random circles but I am unsure where to go from here? I am trying to use the following equation d = (sqrt)((x1 –x2)^2 +(y1 – y2)^2). Right now the program draws many random circles, so adjusting the formula i should be able to manipulate it so that certain circles are red in the centre (like the japan flag).
# using the SimpleGraphics library
from SimpleGraphics import *
# use the random library to generate random numbers
import random
diameter = 15
##
# returns a valid colour based on the input coordinates
#
# #param x is an x-coordinate
# #param y is a y-coordinate
# #return a colour based on the input x,y values for the given flag
##
def define_colour(x,y):
##
if y < (((2.5 - 0)**2) + ((-0.5 - 0)**2)**(1/2)):
c = 'red'
else:
c = 'white'
return c
return None
# repeat until window is closed
while not closed():
# generate random x and y values
x = random.randint(0, getWidth())
y = random.randint(0, getHeight())
# set colour for current circle
setFill( define_colour(x,y) )
# draw the current circle
ellipse(x, y, diameter, diameter)
Here's some code that endlessly draws circles. Circles that are close to the centre of the screen will be drawn in red, all other circles will be drawn in white. Eventually, this will create an image similar to the flag of Japan, although the edge of the inner red "circle" will not be smooth.
I have not tested this code because I don't have the SimpleGraphics module, and I'm not having much success locating it via Google or pip.
from SimpleGraphics import *
import random
diameter = 15
width, height = getWidth(), getHeight()
cx, cy = width // 2, height // 2
# Adjust the multiplier (10) to control the size of the central red portion
min_dist_squared = (10 * diameter) ** 2
def define_colour(x, y):
#Calculate distance squared from screen centre
r2 = (x - cx) ** 2 + (y - cy) ** 2
if r2 <= min_dist_squared:
return 'red'
else:
return 'white'
# repeat until window is closed
while not closed():
# generate random x and y values
x = random.randrange(0, width)
y = random.randrange(0, height)
# set colour for current circle
setFill(define_colour(x, y))
# draw the current circle
ellipse(x, y, diameter, diameter)
I have this assignment for school:
Build a Snowman without turtle circle function
The snowman should be on a blue background, and should be drawn filled with white.
The outline of the snowman should be in black.
The snowman’s body should be made of 3 filled circles.
The outline of each circle should be 3 pixels wide.
The bottom circle should have a radius of 100 pixels.
The middle circle should have a radius of 70 pixels.
The top circle should have a radius of 40 pixels.
Each circle should be centered above the one below it (except the bottom circle, which can be located anywhere).
There should be no gap between the circles.
Give the snowman a mouth, eyes, and a nose (a hat is optional).
Make sure to include two stick-arms and at least two fingers on each hand.
So far I created this, but I can't seem to get the circles right before I move on.
Also, don't know how to color in circles or make dots for eyes. Help me please, first time coding.
import turtle # allows us to use turtle library
wn = turtle.Screen() # allows us to create a graphics window
wn.bgcolor("blue") # sets gtaphics windows background color to blue
import math # allows us to use math functions
quinn = turtle.Turtle() # sets up turtle quinn
quinn.setpos(0,0)
quinn.pensize(3)
quinn.up()
# drawing first circle middle
quinn.forward(70)
quinn.down()
quinn.left(90)
# calculation of cicumference of a circle
a = (math.pi*140.00/360)
#itineration for first circle
for i in range (1,361,1):
quinn.left(a)
quinn.forward (1)
# drawing second circle bottom
quinn.up()
quinn.home()
quinn.right(90)
quinn.forward(70)
quinn.left(90)
quinn.down()
b = (math.pi*200.00/360)
for i in range (1,361,1):
quinn.right(b)
quinn.forward(1)
# drawing third circle head top
quinn.up ()
quinn.goto(0,70)
quinn.right(90)
quinn.down()
c =(math.pi*80/360)
for i in range (1,361,1):
quinn.left(c)
quinn.forward(1)
wn.exitonclick()
The following is an example function to draw a circle filled in blue:
def draw_circle(radius):
turtle.up()
turtle.goto(0,radius) # go to (0, radius)
turtle.begin_fill() # start fill
turtle.down() # pen down
turtle.color('blue')
times_y_crossed = 0
x_sign = 1.0
while times_y_crossed <= 1:
turtle.forward(2*math.pi*radius/360.0) # move by 1/360
turtle.right(1.0)
x_sign_new = math.copysign(1, turtle.xcor())
if(x_sign_new != x_sign):
times_y_crossed += 1
x_sign = x_sign_new
turtle.up() # pen up
turtle.end_fill() # end fill.
return
Then you can modify the above function adding parameters for position (x,y) of the circle center:
def draw_circle(radius, x, y):
turtle.up()
turtle.goto(x,y+radius) # go to (x, y + radius)
turtle.begin_fill() # start fill
turtle.down() # pen down
turtle.color('blue')
times_y_crossed = 0
x_sign = 1.0
while times_y_crossed <= 1:
turtle.forward(2*math.pi*radius/360.0) # move by 1/360
turtle.right(1.0)
x_sign_new = math.copysign(1, turtle.xcor())
if(x_sign_new != x_sign):
times_y_crossed += 1
x_sign = x_sign_new
turtle.up() # pen up
turtle.end_fill() # end fill.
return
You can easily add dots as, for instance,:
turtle.goto(-20,10)
turtle.color('red')
turtle.dot(20)
turtle.goto(40,10)
turtle.dot(20)
Putting together:
import turtle
import math
def draw_circle(radius, x, y):
turtle.up()
turtle.goto(x,y+radius) # go to (0, radius)
turtle.begin_fill() # start fill
turtle.down() # pen down
turtle.color('blue')
times_y_crossed = 0
x_sign = 1.0
while times_y_crossed <= 1:
turtle.forward(2*math.pi*radius/360.0) # move by 1/360
turtle.right(1.0)
x_sign_new = math.copysign(1, turtle.xcor())
if(x_sign_new != x_sign):
times_y_crossed += 1
x_sign = x_sign_new
turtle.up() # pen up
turtle.end_fill() # end fill.
return
draw_circle(100, 10, 10)
turtle.goto(-20,10)
turtle.color('red')
turtle.dot(20)
turtle.goto(40,10)
turtle.dot(20)
turtle.pen(shown=False)
turtle.done()
You should attempt to do by yourself the remaining part of the assignment.. ;)
Sorry for not giving an explanation.
The first part is Ramanujan's aproximation of pi, but not a very good one because it only reaches an aproximation of pi after something like 300,000 iterations of the loop and it is only accurate to 5 decimal places. that would be this part:
r += (1 / k) * (-1)**i
pi = (4 * (1 - r))
Then I use the circumference of a circle:
t.forward(2*5*pi)
Finally I just make the turtle walk clock wise by 20.
import turtle
t = turtle.Turtle()
t.right(90)
t.penup()
t.goto(100, 0)
t.pendown()
i = 0
r = 0
k = 3
while i <= 360:
r += (1 / k) * (-1)**i
pi = (4 * (1 - r))
t.write(pi)
t.forward(2*5*pi)
t.right(20)
i += 1
k += 2
turtle.done()
From a mathematical standpoint, you can use functions sin and cos from the math to plot the circle.
Once the circle is plot, use the turtle.begin_fill() and turtle.end_fill() methods to fill in the circle (though I do agree that in programming, this method is more practical):
from turtle import Turtle
from math import sin, cos, radians
def draw_circle(radius, x, y, color="light blue", line_width=3):
c = Turtle(visible=False)
c.width(3)
c.penup()
c.goto(x + radius, y)
c.pendown()
c.color("black", color)
c.begin_fill()
# Circle drawing starts here
for i in range(1, 361):
c.goto(radius * cos(radians(i)) + x,
radius * sin(radians(i)) + y)
# Circle drawing ends here
c.end_fill()
draw_circle(100, 0, -100)
As pointed out in this answer, you can use the turtle.dot() method to draw a dot on the screen,
and the width of the pen will be the diameter of the dot.
There's another way to do that, but compared to the dot method, it is impractical.
I'll throw it out there anyway, just to show how there are many possibilities in workarounds:
from turtle import Turtle
def draw_circle(radius, x, y, color="light bue", line_width=3):
c = Turtle(visible=False)
c.penup()
c.goto(x, y)
c.pendown()
# Circle drawing starts here
c.width(radius * 2 + line_width)
c.forward(0)
c.color(color)
c.width(radius * 2 - line_width)
c.forward(0)
# Circle drawing ends here
draw_circle(100, 0, -100)
So a turtle.dot() is the equivalent of turtle.forward(0) (and turtle.backward(0), turtle.goto(turtle.pos()), turtle.setpos(turtle.pos()), etc., etc.).
Output:
Most solutions to "without turtle circle function" involve writing your own equivalent to turtle's circle function. But there are already two other ways you can draw outlined, filled circles with turtle.
One is you can use concentric dots:
turtle.color('black')
turtle.dot(200 + 3)
turtle.color('white')
turtle.dot(200 - 3)
Just remember that dot() takes a diameter whereas circle() takes a radius:
However, I prefer to use stamping to solve these sorts of problems:
''' Build a Snowman without turtle circle function '''
from turtle import Turtle, Screen
# The snowman’s body should be made of 3 filled circles.
# The bottom circle should have a radius of 100 pixels.
# The middle circle should have a radius of 70 pixels.
# The top circle should have a radius of 40 pixels.
RADII = (100, 70, 40)
STAMP_SIZE = 20
# The snowman should be on a blue background
screen = Screen()
screen.bgcolor('blue')
quinn = Turtle('circle')
quinn.setheading(90)
quinn.up()
# The outline of the snowman should be in black, and should be drawn filled with white.
quinn.color('black', 'white')
for not_first, radius in enumerate(RADII):
if not_first:
quinn.forward(radius)
# The outline of each circle should be 3 pixels wide.
quinn.shapesize((radius * 2) / STAMP_SIZE, outline=3)
quinn.stamp()
# Each circle should be centered above the one below it
# There should be no gap between the circles.
quinn.forward(radius)
# Give the snowman eyes
quinn.shapesize(15 / STAMP_SIZE)
quinn.color('black')
quinn.backward(3 * RADII[-1] / 4)
for x in (-RADII[-1] / 3, RADII[-1] / 3):
quinn.setx(x)
quinn.stamp()
# Give the snowman a mouth, and a nose (a hat is optional).
pass
# Make sure to include two stick-arms and at least two fingers on each hand.
pass
quinn.hideturtle()
screen.exitonclick()
The idea is you contort the turtle cursor itself to what you need, make a snapshot of it on the screen, and then contort it to the next thing you need to draw.
You can create a function that takes arguments fd, and left.
here is what I created.
from turtle import *
speed(100000)
for i in range(360):
fd(2)
left(1)
Here is the calculation: The iterations in range divided by the fd+left.
That is the approximation I have. SO you should be able to create a function like that.
You could try this, hope this helps!
def polygon(length, sides):
for i in range(sides):
turtle.forward(length)
turtle.left(360.0/sides)
polygon(1, 360)