We were assigned to make a pizza using user-inputted amount of slices, but I can't figure out how to tilt the slice.
import turtle
window = turtle.Screen()
window.bgcolor("lightgreen")
slice = turtle.Turtle()
slice.color("orange")
slice_amount = int(input("How many slices do you want to make? "))
if slice_amount == slice_amount:
slice.tilt(360/slice_amount)
def pizza(angle, radius, t):
t.begin_fill()
t.setheading((180 - angle) / 2)
t.forward(radius)
t.setheading(-0.5 * angle + 180)
t.circle(radius, angle)
t.goto(0, 0)
t.end_fill()
for i in range(slice_amount -1):
t.begin_fill()
t.setheading((180 - angle) / 2)
t.forward(radius)
t.setheading(-0.5 * angle + 180)
t.circle(radius, angle)
t.goto(0, 0)
t.end_fill()
pizza(360/slice_amount, 100, slice)
turtle.done()
I tried to put the whole function in an if statement but that didn't help.
When you're drawing shapes around a circle, the typical approach is to:
draw a shape
move back to the origin
point the turtle in the direction of the next shape
go back to step 1
You're missing step 3, positioning the turtle so it's ready to draw the next thing. Without this step, it winds up repeatedly drawing the same shape over and over.
One approach is to set the heading to point at the origin before goto(0, 0), then rotate 180 degrees to point directly at the line the turtle has just drawn to close the last pie slice.
import turtle
n = 6
radius = 100
angle = 360 / n
t = turtle.Turtle()
for i in range(n):
t.color(i / n, 0, 0)
t.begin_fill()
t.forward(radius)
t.left(90)
t.circle(radius, angle)
t.setheading(t.towards(0, 0))
t.goto(0, 0)
t.left(180)
t.end_fill()
turtle.exitonclick()
Another option is to use your i to set the heading for each slice:
# ...
for i in range(n):
t.setheading(i * angle)
t.color(i / n, 0, 0)
t.begin_fill()
t.forward(radius)
t.left(90)
t.circle(radius, angle)
t.goto(0, 0)
t.end_fill()
# ...
When you're working on getting your logic correct, try to avoid functions and input(). Adding those things too soon adds complexity that gets in the way of your logic and slows down experimentation. Once you've ensured correctness, then you can split logic into functions and add extra features like user interaction.
Additionally, slice() is a builtin function in Python, so pick a different name for your variable to avoid overwriting it.
if slice_amount == slice_amount: does nothing so you can remove that.
Related
import turtle
def main():
t=turtle
s=int(input("Enter the length of each square: "))
t.screensize(2000,2000,"lightblue")
for row in range(0,5):
for column in range(0,5):
if (row+column)%2==0:
t.pendown()
t.fillcolor("black")
t.begin_fill()
square(s,row,column)
else:
t.pendown()
t.fillcolor("white")
t.begin_fill()
square(s,row,column)
t.goto(s+row*s,s+column*s)
def square(s,row,column):
t=turtle
t.penup()
n=0
for count in range(4):
t.pendown()
t.forward(s)
t.left(90)
t.end_fill()
t.penup()
main()
So today I was given an assignment that asked me to create a 5 by 5 checkerboard. So far, I have this code which manages to create most of the checkerboard. However, I still have a mistake somewhere or I am missing some key information.
The attached picture shows what the program looks like with the error.
The program started by creating the black square, which can be seen on the bottom left corner. Then it worked up until the top right corner, where the empty space can be seen.
Please help.
Let's try stamping instead of drawing. This gains us speed while simplifying our logic. We stamp one large black square to represent the board, then stamp the white squares onto it:
from turtle import Turtle, Screen
SQUARES_PER_SIDE = 5
CURSOR_SIZE = 20
def main():
length = int(input("Enter the length of each square: "))
screen = Screen()
screen.bgcolor("lightblue")
turtle = Turtle('square', visible=False)
turtle.shapesize(SQUARES_PER_SIDE * length / CURSOR_SIZE)
turtle.speed('fastest')
turtle.stamp() # black background
turtle.shapesize(length / CURSOR_SIZE)
turtle.fillcolor("white")
turtle.penup()
edge = (1 - SQUARES_PER_SIDE) / 2 * length # center of left or bottom square
turtle.goto(edge, edge)
for row in range(SQUARES_PER_SIDE):
for column in range(SQUARES_PER_SIDE):
if (row + column) % 2 == 0:
turtle.stamp() # white square
turtle.forward(length)
turtle.goto(edge, edge + (row + 1) * length)
screen.exitonclick()
main()
OUTPUT
Moving t.goto(s+row*s,s+column*s) to beginning of inner for loop does the trick.
Basically we need to move turtle to starting position first and then start drawing.
I also cleaned up the code to put redundant lines inside square function.
Also, added t.penup() so that turtle doesn't show draw until it has reached starting position and start drawing.
import turtle
def main():
t=turtle
t.penup()
s=int(input("Enter the length of each square: "))
t.screensize(2000,2000,"lightblue")
for row in range(0,5):
for column in range(0,5):
t.goto(s+row*s,s+column*s)
if (row+column)%2==0:
square(s,row,column,"black")
else:
square(s,row,column,"white")
def square(s,row,column,color):
t=turtle
t.pendown()
t.fillcolor(color)
t.begin_fill()
t.penup()
n=0
for count in range(4):
t.pendown()
t.forward(s)
t.left(90)
t.end_fill()
t.penup()
main()
Anil_M beat me to it by a few minutes; but I wanted to offer some additional code clean-up, as you've got too many needless penups, pendowns and unnecessary parameter passing going on.
Try this:
import turtle
t = turtle.Turtle()
t.speed(0)
def main():
s=int(input("Enter the length of each square: "))
for row in range(5):
for column in range(5):
if (row+column)%2==0:
color = "black"
else:
color = "white"
t.penup()
t.goto(row*s,column*s)
t.pendown()
filled_square(s, color)
def filled_square(s, color):
t.fillcolor(color)
t.begin_fill()
for count in range(4):
t.forward(s)
t.left(90)
t.end_fill()
main()
My task is to write a function, drawCircle(radius,fillColor), that asks a user for the specific radius of the circle and which color they'd like the circle to be filled.
I have the circle-drawing down, but I'm struggling with getting the circle to fill with the user-defined color. Any help would be greatly appreciated.
import turtle
def drawCircle(radius, fillColor):
x=360/300 #This gives the angle
r=radius#This is the radius of the circle.
c=fillColor
c=str("")
z=1 #Placeholder for the while loop.
win=turtle.Screen()
tom=turtle.Turtle()
fillColor=tom.color()
tom.begin_fill()
while (z<=300):
tom.forward(r)
tom.right(x)
tom.forward(r)
z=z+1
win.exitonclick()
tom.end_fill()
This is my function call: drawCircle(1,"red")
There are several problems with your code:
You call win.exitonclick before tom.end_fill, so programm exits before filling (as it happens on end_fill)
You do "fillColor=tom.color()" with gets you current color. Instead use "tom.fillcolor(fillColor)"
Unnecessary copying of variables radius->r and fillColor->c
This is python. Use for whenever possible. Instead of counting using z use:
for _ in range(300):
My final code:
import turtle
def drawCircle(radius, fillColor):
x = 360/300 # This gives the angle
win = turtle.Screen()
tom = turtle.Turtle()
tom.fillcolor(fillColor)
tom.begin_fill()
for _ in range(300):
tom.forward(radius)
tom.right(x)
tom.forward(radius)
tom.end_fill()
win.exitonclick()
drawCircle(1, "red")
I have the circle-drawing down
Before addressing your fill issue, I'd argue that your premise isn't true, you don't have circle-drawing down. As #Mysak0CZ shows, your circle of radius 1 is huge -- 1 what? You're drawing a circle but have no real control over its size.
As a professional turtle wrangler, I'd go about the problem as follows. Not only your angle needs to be divided by the number of segments you plan to draw, but you need to compute a circumference based on the requested radius and chop that up as well. I do so below and include a call to turtle's own .circle() method to show that we're in the right ballpark. And I fix your minor fill issue:
import math
from turtle import Turtle, Screen # force object-oriented turtles
SEGMENTS = 60 # how many lines make up the circle
def drawCircle(radius, fillColor):
distance = math.pi * radius * 2 / SEGMENTS # circumference / SEGMENTS
angle = 360 / SEGMENTS
turtle.fillcolor(fillColor)
turtle.begin_fill()
for _ in range(SEGMENTS):
turtle.forward(distance)
turtle.left(angle) # left for .circle() compatibility
turtle.end_fill()
screen = Screen()
turtle = Turtle()
drawCircle(100, 'red')
turtle.circle(100) # for comparison
screen.exitonclick()
Here is my code for a pink circle if you are going through the same Python learning resource. I think the original code was missing an argument.
import turtle
def drawPolygon(t, sideLength, numSides):
t.goto(0, 0)
turnAngle = 360 / numSides
for i in range(numSides):
t.forward(sideLength)
t.right(turnAngle)
def drawCircle(anyTurtle, radius):
circumference = 2 * 3.1415 * radius
sideLength = circumference / 360
drawPolygon(anyTurtle, sideLength, 360)
def drawFilledCircle(anyTurtle, radius, color):
anyTurtle.fillcolor(color)
anyTurtle.begin_fill()
drawCircle(anyTurtle, radius)
anyTurtle.end_fill()
anyTurtle.hideturtle()
wn = turtle.Screen()
wheel = turtle.Turtle()
drawFilledCircle(wheel, 80, "pink")
wn.exitonclick()
I'm being really bugged by a task:
User inputs radius r and then turtle draws the circle then proceeds to draw another circle with the same center but 10 px smaller until the radius is 0
First let us approximate a circle as a regular polygon with 36 sides/segments.
To draw this shape given a radius r we need to know;
The length of each segment
The angle to turn between each segment
To calculate the length, we first need the circumference, which is 2πr (we will approximate pi as 3.1415), giving us
circumference = 2 * 3.1415 * radius
Next we divide this by the number of segments we are approximating, giving
circumference = 2 * 3.1415 * radius
seg_lenght = circumferece/36
Now we need the angle difference between the segments, or the external angle. This is simply 360/n for a regular n-gon(polygon with n sides), so we do 360/36 = 10
We can now define a function to generate the segment length and draw the circle:
def circle_around_point(radius):
circumference = 2 * 3.1415 * radius
seg_length = circumference/36
penup()
fd(radius) #Move from the centre to the circumference
right(90) #Face ready to start drawing the circle
pendown()
for i in range(36): #Draw each segment
fd(seg_length)
right(10)
penup()
right(90) #Face towards the centre of the circle
fd(radius) #Go back to the centre of the circle
right(180) #Restore original rotation
pendown()
Now for the concentric circles:
def concentric_circles(radius):
while radius > 0:
circle_around_point(radius)
radius -= 10
It's not clear why #IbraheemRodrigues felt the need to recode turtle's circle() function based on your problem description, but we can simplify his solution by not reinventing the wheel:
def circle_around_point(turtle, radius):
is_down = turtle.isdown()
if is_down:
turtle.penup()
turtle.forward(radius) # move from the center to the circumference
turtle.left(90) # face ready to start drawing the circle
turtle.pendown()
turtle.circle(radius)
turtle.penup()
turtle.right(90) # face awary from the center of the circle
turtle.backward(radius) # go back to the center of the circle
if is_down:
turtle.pendown() # restore original pen state
def concentric_circles(turtle, radius):
for r in range(radius, 0, -10):
circle_around_point(turtle, r)
The key to circle() is that the current position is on the edge of the circle so you need to shift your position by the radius to make a specific point the center of the circle.
However, to solve this problem, I might switch from drawing to stamping and do it this way to speed it up and simplify the code:
import turtle
STAMP_SIZE = 20
radius = int(input("Please input a radius: "))
turtle.shape('circle')
turtle.fillcolor('white')
for r in range(radius, 0, -10):
turtle.shapesize(r * 2 / STAMP_SIZE)
turtle.stamp()
turtle.mainloop()
However, this draws crude circles as it's blowing up a small one:
To fix that, I might compromise between the two solutions above and do:
import turtle
radius = int(input("Please input a radius: "))
turtle.penup()
turtle.forward(radius)
turtle.left(90)
turtle.pendown()
turtle.begin_poly()
turtle.circle(radius)
turtle.penup()
turtle.end_poly()
turtle.addshape('round', turtle.get_poly()) # 'circle' is already taken
turtle.right(90)
turtle.backward(radius)
turtle.shape('round')
turtle.fillcolor('white')
for r in range(radius - 10, 0, -10):
turtle.shapesize(r / radius)
turtle.stamp()
turtle.mainloop()
This improves circle quality by shrinking a large one instead of enlarging a small one:
Where quality of the circle can be controlled using the steps= argument to the call to circle().
But, if I really wanted to minimize code while keeping quality high and speed fast, I might do:
import turtle
radius = int(input("Please input a radius: "))
for diameter in range(radius * 2, 0, -20):
turtle.dot(diameter, 'black')
turtle.dot(diameter - 2, 'white')
turtle.hideturtle()
turtle.mainloop()
The dot() method draws from the center instead of the edge, uses diameters instead of radii, draws only filled circles, and seems our best solution to this particular exercise:
import turtle
#### ##### #### Below class draws concentric circles.
class Circle:
def __init__(self, pen, cx, cy, radius):
self.pen = pen
self.cx = cx
self.cy = cy
self.radius = radius
def drawCircle(self):
self.pen.up()
self.pen.setposition( self.cx, self.cy - self.radius )
self.pen.down()
self.pen.circle(self.radius)
def drawConCircle(self, minRadius = 10, delta = 10):
if( self.radius > minRadius ) :
self.drawCircle()
self.radius -= delta # reduce radius of next circle
self.drawConCircle()
#### End class circle #######
win = turtle.Screen()
win.bgcolor("white")
s = Circle( turtle.Turtle(), 0, 0, 200 )
s.drawConCircle()
win.exitonclick()
I'm looking for best way to automatically find starting position for new turtle drawing so that it would be centered in graphics window regardless of its size and shape.
So far I've developed a function that checks with each drawn element turtle position to find extreme values for left, right, top and bottom and that way I find picture size and can use it to adjust starting position before releasing my code. This is example of simple shape drawing with my picture size detection added:
from turtle import *
Lt=0
Rt=0
Top=0
Bottom=0
def chkPosition():
global Lt
global Rt
global Top
global Bottom
pos = position()
if(Lt>pos[0]):
Lt = pos[0]
if(Rt<pos[0]):
Rt= pos[0]
if(Top<pos[1]):
Top = pos[1]
if(Bottom>pos[1]):
Bottom = pos[1]
def drawShape(len,angles):
for i in range(angles):
chkPosition()
forward(len)
left(360/angles)
drawShape(80,12)
print(Lt,Rt,Top,Bottom)
print(Rt-Lt,Top-Bottom)
This method does work however it seems very clumsy to me so I would like to ask more experiences turtle programmers is there a better way to find starting position for turtle drawings to make them centered?
Regards
There is no universal method to center every shape (before you draw it and find all your max, min points).
For your shape ("almost" circle) you can calculate start point using geometry.
alpha + alpha + 360/repeat = 180
so
alpha = (180 - 360/repeat)/2
but I need 180-alpha to move right (and later to move left)
beta = 180 - aplha = 180 - (180 - 360/repeat)/2
Now width
cos(alpha) = (lengt/2) / width
so
width = (lengt/2) / cos(alpha)
Because Python use radians in cos() so I need
width = (length/2) / math.cos(math.radians(alpha))
Now I have beta and width so I can move start point and shape will be centered.
from turtle import *
import math
# --- functions ---
def draw_shape(length, repeat):
angle = 360/repeat
# move start point
alpha = (180-angle)/2
beta = 180 - alpha
width = (length/2) / math.cos(math.radians(alpha))
#color('red')
penup()
right(beta)
forward(width)
left(beta)
pendown()
#color('black')
# draw "almost" circle
for i in range(repeat):
forward(length)
left(angle)
# --- main ---
draw_shape(80, 12)
penup()
goto(0,0)
pendown()
draw_shape(50, 36)
penup()
goto(0,0)
pendown()
draw_shape(70, 5)
penup()
goto(0,0)
pendown()
exitonclick()
I left red width on image.
I admire #furas' explanation and code, but I avoid math. To illustrate that there's always another way to go about a problem here's a math-free solution that produces the same concentric polygons:
from turtle import Turtle, Screen
def draw_shape(turtle, radius, sides):
# move start point
turtle.penup()
turtle.sety(-radius)
turtle.pendown()
# draw "almost" circle
turtle.circle(radius, steps=sides)
turtle = Turtle()
shapes = [(155, 12), (275, 36), (50, 5)]
for shape in shapes:
draw_shape(turtle, *shape)
turtle.penup()
turtle.home()
turtle.pendown()
screen = Screen()
screen.exitonclick()
I need to draw a square given a center point using the turtle module.
def drawCentSq(t,center,side):
xPt=center[0]
yPt=center[1]
xPt-=int(side/side)
yPt+=int(side/side)
t.up()
t.goto(xPt,yPt)
t.down()
for i in range(4):
t.forward(side)
t.right(90)
def main():
import turtle
mad=turtle.Turtle()
wn=mad.getscreen()
print(drawCentSq(mad,(0,0),50))
main()
I'm having a hard time making my turtle go to the right starting point.
You need:
xPt-=int(side/2.0)
yPt+=int(side/2.0)
As it was you were just += and -= 1.
I need to draw a square given a center point using the turtle module.
As #seth notes, you can do this by fixing the center calculation in your code:
from turtle import Turtle, Screen
def drawCentSq(turtle, center, side):
""" A square is a series of perpendicular sides """
xPt, yPt = center
xPt -= side / 2
yPt += side / 2
turtle.up()
turtle.goto(xPt, yPt)
turtle.down()
for _ in range(4):
turtle.forward(side)
turtle.right(90)
yertle = Turtle()
drawCentSq(yertle, (0, 0), 50)
screen = Screen()
screen.exitonclick()
But let's step back and consider how else we can draw a square at a given point of a given size. Here's a completely different solution:
def drawCentSq(turtle, center, side):
""" A square is a circle drawn at a rough approximation """
xPt, yPt = center
xPt -= side / 2
yPt -= side / 2
turtle.up()
turtle.goto(xPt, yPt)
turtle.right(45)
turtle.down()
turtle.circle(2**0.5 * side / 2, steps=4)
turtle.left(45) # return cursor to original orientation
And here's yet another:
STAMP_UNIT = 20
def drawCentSq(turtle, center, side):
""" A square can be stamped directly from a square cursor """
mock = turtle.clone() # clone turtle to avoid cleaning up changes
mock.hideturtle()
mock.shape("square")
mock.fillcolor("white")
mock.shapesize(side / STAMP_UNIT)
mock.up()
mock.goto(center)
return mock.stamp()
Note that this solution returns a stamp ID that you can pass to yertle's clearstamp() method to remove the square from the screen if/when you wish.