Section 4.3 Exercise #5 - "Think Python" by Allen Downey - python

Link to the Exercises can be accessed here - Case Study: Interface Design, Exercise Section 4.3
Quoting the question, it seems I have to implement an arc() function:
Make a more general version of circle called arc that takes an additional parameter angle, which determines what fraction of a circle to draw. angle is in units of degrees, so when angle=360, arc should draw a complete circle.
The code I've written so far:
import turtle
import math
bob = turtle.Turtle()
def polygon(t, n, length):
for i in range(n):
t.fd(length)
t.lt(360/n)
def circle(t, r):
circumference = 2 * math.pi * r
n = int(circumference/3) + 1
length = circumference/n
polygon(t, n, length)
def arc(t, r, angle):
arc_length = 2 * math.pi * r * (angle/360)
n = (arc_length/4) + 1
arc(bob, 1000, 45)
turtle.mainloop()
I'm intending to call the circle() function within arc() just as polygon() was called within circle(), but I'm confused on how I should do that. Apart from that, the arc() function does not draw anything, rather just shows me a stationary Turtle.
I believe that the Turtle object bob isn't receiving any of the movement instructions assigned within polygon(). Thus all that it's doing is displaying the Turtle object!
I could be wrong, and this where I need clarification. Should I call circle() within arc() as well as make the Turtle object move? Are there easier alternatives? Calling functions within a function is still confusing for me, so more resources to learn about them would be great as well!

import turtle
bob=turtle.Turtle()
import math
def arc(t,radius,angle):
circumference = 2.0*math.pi*radius
frac = angle/360.0
arclength = circumference*frac
n = 50 # pick a number
len = arclength/n;
turnang = angle/n
for i in range(n):
t.fd(len)
t.lt(turnang)
arc(bob, 130,360)
turtle.done()

I'm trying to ... call the circle() function
within arc() just as polygon() was called within circle()
You've got this backward. The problem states:
Make a more general version of circle called arc
Just as you could draw a circle with the more general function polygon(), you should be able to draw a circle with the more general function arc(). Here's a skeletal program for thinking about this:
from turtle import Screen, Turtle
from math import pi
def polygon(turtle, sides, length):
outside_angle = 360 / sides
for _ in range(sides):
turtle.forward(length)
turtle.left(outside_angle)
def circle_using_polygon(turtle, radius):
circumference = 2 * pi * radius
sides = min(60, int(circumference / 3))
length = circumference / sides
polygon(turtle, sides, length)
def arc(turtle, radius, angle):
# implement arc not by calling *circle() nor by
# calling polygon() but rather by borrowing code
# from both and adding one more step to reduce
# the number of sides based on the arc angle
def circle_using_arc(turtle, radius):
arc(turtle, radius, 360)
bob = Turtle(visible=False)
# Draw overlapping circles three different ways:
bob.color("green")
circle_using_polygon(bob, 100)
for color in ['cyan', 'magenta', 'yellow', 'black']:
bob.color(color)
arc(bob, 100, 90)
bob.color("blue")
circle_using_arc(bob, 100)
screen = Screen()
screen.mainloop()

import tkinter
import swampy
from swampy.TurtleWorld import *
def polygon(n, t, length, angle):
print(t)
k= angle/360
for i in range(0,int(n*k)):
fd(t, length)
p= 360
lt(t,p/n)
t.delay
world = TurtleWorld()
bob = Turtle()
#def circle(r):
#l1= 2*3.14*r
#l= l1/60
#polygon(30, bob, l)
polygon(60, bob, 10, 180)

Related

Turning simple polygons about a point in Python Turtle

I need help turning polygon shapes (triangle and square) in Python turtle to match a picture.
Below I am trying to copy the image.
I specifically need help on what to add to my code given the triangle and square to have them repeat outwards like the picture. Because as of now the triangles and squares look like this (pentagon code is correct and works) All help is appreciated. Thank you.
import turtle
def polygon(turtle, side, length):
turtle.color("Blue")
for i in range(4):
turtle.backward(length)
turtle.left(side)
def polygon1(turtle, side1, length):
turtle.color("Green")
for i in range(3):
turtle.left(side1)
turtle.forward(length)
def polygon2(turtle, side2, length):
turtle.color("Red")
for i in range(5):
turtle.forward(length)
turtle.left(side2)
def main():
my_turtle = turtle.Turtle()
wn = turtle.Screen()
Bill = turtle.Turtle()
length = 100
side = 90
side1 = 120
side2 = 72
Bill.pensize(5)
Bill.speed(0)
#Pentagons
Bill.pu()
Bill.right(180)
y = -45
for i in range(5):
Bill.pu()
Bill.goto(60, y)
Bill.pd()
polygon2(Bill, side2, length)
y -= 20
#Triangle
Bill.pu()
Bill.left(240)
x = 45
for j in range(5):
Bill.pu()
Bill.goto(10, x)
Bill.pd()
polygon1(Bill, side1, length)
x += 20
#Square
Bill.pu()
Bill.left(240)
b = 6
for b in range(5):
Bill.pu()
Bill.goto(148, b)
Bill.pd()
polygon(Bill, side, length)
b -= 20
wn.exitonclick()
if __name__ == '__main__':
main()
pentagon code is correct and works
I don't believe the pentagon code is correct nor that you're approaching this in the correct way. The inner three shapes should form an equilateral triangle -- yours don't as you're eyeballing instead of calculating. Instead of trying to get the turtle to be in the right spot, why not have the turtle move forward in the direction of the sides of this central triangle, drawing polygons as it goes.
That is, embrace the drawing as a whole rather than trying to divide and conquer.
We'd need to make sure the polygon drawing code restores the turtle's state when it's done, so it can simply move forward to the next polygon. We'll need to make explicit which numbers are arbitrary, and which are calculable. Although the original diagram appears to use at least three turtles to achieve it's result, we'll do it with one as you attempted:
from turtle import Turtle, Screen
SHAPES = [(5, "Red"), (3, "Green"), (4, "Blue")]
LENGTH = 100
DELTA = 20
REPLICATIONS = 5
THICKNESS = 5
HEIGHT = (3 ** 0.5 / 2) * LENGTH # assumes 3 shapes, should fix!
DIVISIONS = 360 / len(SHAPES)
def polygon(turtle, sides, color):
turtle.color(color)
turtle.left(90)
turtle.forward(LENGTH / 2)
for _ in range(sides):
turtle.right(360 / sides)
turtle.forward(LENGTH)
turtle.backward(LENGTH / 2) # restore turtle to original state
turtle.right(90)
wn = Screen()
bill = Turtle()
bill.speed('fastest')
bill.pensize(THICKNESS)
bill.penup()
for offset, (sides, color) in enumerate(SHAPES):
bill.setheading(-DIVISIONS * offset - 90)
bill.forward(HEIGHT / 3) # assumes 3 shapes, should fix!
for _ in range(REPLICATIONS):
bill.pendown()
polygon(bill, sides, color)
bill.penup()
bill.forward(DELTA)
bill.home()
wn.exitonclick()

Understanding turtle circle, and arc in "Think Python"

In the interface design section in "Think Python" I need help understanding the approach to the circle and arc functions, like this:
import turtle
import polygon
bob = turtle.Turtle()
print(bob)
def polygon(t, n, length):
angle = 360 / n
for i in range(n):
t.fd(length)
t.lt(angle)
And after that, the book introduces another approach to drawing a circle by using a polygon function:
def circle(t, r):
circumference = 2 * math.pi * r
n = int(circumference / 3 ) + 1
length = circumference / n
polygon(t, n, length)
What I don't understand:
I have no idea why they define circumference to draw circle and how it works to draw a circle.
If I call the function like circle(bob, 100) then it only draws a fraction of circle not the whole circle.
I don't understand why n is needed, and how that procedure can make a circle.
I have no idea why they define circumference to draw circle and how it
take a work to draw a circle
One way we can visualize a circle is by drawing a polygon with the number of sides equal to the (integer) circumference of the circle with each side being 1 in length. For a circle of radius = 100, that would be:
polygon(bob, 628, 1) # 628 = 2 * PI * 100
which draws a nice, but slow circle:
We can speed this up by using a rougher approximation. The circle() function above arbitrarily divides the number of sides the polygon will have by 3 but then increases the length of each side by 3:
polygon(bob, 209, 3)
This is just a sightly rougher circle but draws more quickly:
If I call the function like circle(bob, 100) then it only draws a
fraction of circle not the whole circle.
I believe you're mixing up the circle() function defined above with the circle() method that comes with turtle. It was confusing of the author to reuse the "circle" name this way. The second argument to the turtle circle() method is an extent:
extent - an angle - determines which part of the
circle is drawn. If extent is not given, draw the entire circle.
If extent is not a full circle, one endpoint of the arc is the
current pen position.
So the "Think Python" function call:
circle(bob, 100)
draws a circle of radius 100:
The turtle method:
bob.circle(100, 90)
draws an arc (1/4 circle) based on a radius of 100:
I don't understand why n is needed, and how that procedure can make a
circle.
The n is the number of sides on the polygon that approximates a circle:
n = int(circumference / 3 ) + 1
length = circumference / n
polygon(t, n, length)
Starting with a radius of 100, if we replace the '3' above with 1, we'd get a polygon with more (629) sides:
n = int(circumference / 1) + 1 # n = 629
length = circumference / n # length = 0.9989
or roughly:
polygon(t, 628, 1)
Illustrated above. But if we replace '3' with '27', we'd get a circle approximated by a polygon of 24 sides:
n = int(circumference / 27 ) + 1 # n = 24
length = circumference / n # length = 26.1799
The orignal '3' value should have been an additional argument -- in the turtle.circle() method, it's roughly equivalent to the steps argument:
As the circle is approximated by an inscribed regular polygon,
steps determines the number of steps to use. If not given,
it will be calculated automatically. May be used to draw regular
polygons.
bob.circle(100, steps=12)

Write a function called circle that takes a turtle, t, and radius, r, as param

import turtle
bob = turtle.Turtle()
def polygon(t,length,n):
for i in range(n):
t.fd(length)
t.lt(360/n)
print(t)
polygon(bob,30,15)
turtle.mainloop()
How can I make a circle by calling polygon function?
You already have written the correct code to produce a circle. In the view of turtle's own circle() method, a circle is just a polygon with 60 sides (fewer if the circle is small.) I.e. it's about perception and how many sides do you need before you can't tell the difference.
import turtle
def polygon(t, length, n):
for _ in range(n):
t.fd(length)
t.lt(360 / n)
bob = turtle.Turtle()
bob.penup()
bob.sety(-270)
bob.pendown()
polygon(bob, 30, 60)
turtle.mainloop()
Your problem now is to control the drawing of the polygon/circle to produce it with a specific radius. Your length parameter doesn't map to a radius as the circle is coming out way too large. Here length represents 1/60 (1/n) of the circumference and we know that:
circumference = 2 * math.pi * radius
We can calculate, in our circle(t, radius) function, what length needs to be given radius (i.e. circumference/n), and call polygon(t, length, n) with these parameters. Here's a visual comparison drawing a radius 100 circle with turtle's circle() method (red) and drawing it with the solution I just described (blue):
import turtle
bob=turtle.Turtle()
bob.color('green', 'cyan')
bob.begin_fill()
def polygon(t,length, n):
for i in range(n):
bob.forward(length)
bob.left(360/n)
import math
def circle(t, r):
circum= 2*math.pi*r
n= int(circum/10)+1
length= circum/n
polygon(t,length, n)
circle(bob, 100)
bob.end_fill()
turtle.done()

Function inconsistent in requirements

I am just learning to code using the book "Think Python" and I'm so confused. The problem I ran into was in creating the flowers in TurtleWorld. The functions I am creating are not consistent in their requirements. First let me post the finished product, that actually works:
from swampy.TurtleWorld import*
world=TurtleWorld()
bob=Turtle()
print bob
bob.delay=.001
def polyline(t,n,length,angle):
t=Turtle
print t
for i in range(n):
fd(bob,length)
lt(bob,angle)
def arc(t, r, angle):
t=Turtle
arc_length=2*math.pi*r*angle/360
n=int(arc_length/3)+1
step_length=arc_length/n
step_angle=float(angle)/n
polyline(t,n,step_length,step_angle)
def petal(t,r,angle):
for i in range(2):
arc(t,r,angle)
lt(t,180-angle)
def flower(t, n, r, angle):
t=Turtle
for i in range(n):
petal(bob,r,angle)
lt(bob,360/n)
flower(bob,5,77,99)
wait_for_user
On the function definition of arc and petal, t suffices for turtle, though when I began, using t in the definitions of flower and polyline returned an error unbound method(fd and lt). turtle instance required, got type instance instead.
The t=Turtle and print turtle added to half the function definitions were added after the fact to try and fix this error. This is the working version, I just want to know why it didn't work before. I'm not even sure why this worked, as I mainly put bob in as t out of frustration, I didn't actually expect it to work.
Although I use Python's supplied turtle library below, instead of swampy.TurtleWorld, I don't think it makes a difference with respect to the issue you're having. You seem to have a basic misunderstanding of formal parameters in function calls and the distinction between function calls and method invocations. Consider this sequence of events:
flower(bob,5,77,99)
def flower(t, n, r, angle):
t=Turtle
...
Here a perfectly good turtle, bob, gets passed in as the turtle argument t only to be immediately replaced with something else. Or consider polyline which has a turtle argument t but instead the global bob gets used when a turtle is required. Here's how I picture your program should come together:
from turtle import Turtle, Screen
from math import pi
def polyline(turtle, n, length, angle):
for _ in range(n):
turtle.fd(length)
turtle.lt(angle)
def arc(turtle, radius, angle):
arc_length = 2 * pi * radius * angle / 360
n = int(arc_length / 3) + 1
step_length = arc_length / n
step_angle = float(angle) / n
polyline(turtle, n, step_length, step_angle)
def petal(turtle, radius, angle):
for _ in range(2):
arc(turtle, radius, angle)
turtle.lt(180 - angle)
def flower(turtle, n, radius, angle):
for _ in range(n):
petal(turtle, radius, angle)
turtle.lt(360 / n)
screen = Screen()
bob = Turtle()
flower(bob, 5, 77, 99)
screen.exitonclick()
OUTPUT

Spirograph Turtle Python

How can I play with a turtle and how can I use a turtle?
I have trouble getting the thing to work as in the picture shown below (ignore the colors).
from turtle import *
from math import *
def formulaX(R, r, p, t):
x = (R-r)*cos(t) - (r + p)*cos((R-r)/r*t)
def formulaY(R, r, p, t):
y = (R-r)*sin(t) - (r + p)*sin((R-r)/r*t)
def t_iterating(R, r, p):
t = 2*pi
up()
goto(formulaX, formulaY)
down()
while (True):
t = t + 0.01
formulaX(R, r, p, t)
formulaY(R, r, p, t)
def main():
R = int(input("The radius of the fixed circle: "))
r = int(input("The radius of the moving circle: "))
p = int(input("The offset of the pen point, between <10 - 100>: "))
if p < 10 or p > 100:
input("Incorrect value for p!")
t_iterating(R, r, p)
input("Hit enter to close...")
main()'
I am trying to make that kind of shape. Here is the coding I have done so far.
Try changing your t_iterating function to this:
def t_iterating(R, r, p):
t = 2*pi # It seems odd to me to start from 2*pi rather than 0.
down()
while t < 20*pi: # This loops while t goes from 2*pi to 20*pi.
t = t+0.01
goto(formulaX(R, r, p, t), formulaY(R, r, p, t))
up()
No! You're missing the point of the turtle! You should try to do it all with relative movements of the turtle. Think about how you would draw the shape if you were the turtle, crawling on a large floor, dragging a paintbrush from your butt.
At each small fragment of time, the turtle will perform one small iteration of a differential equation which governs the whole behavior. It is not generally wise to precompute the x y coordinates and use the turtle's GOTO function.
The turtle itself should have only relative knowledge of its surroundings. It has a direction, and a position. And these two pieces of state are modified by turning and moving.
So, think about how you would draw the spiral. Particularly, think about drawing the very first circle. As the circle appears to close, something interesting happens: it misses. It misses by a tiny little amount, which turns out to be a fraction of a circle. It is this missing curvature that closes the large pattern of circles in a circle, as they add up to one complete turn.
When the whole figure is drawn, the turtle is back to its original position and orientation.
This is my code. The color may not be exact, but here it is:
from turtle import *
from random import randint
speed(10000)
for i in range(20):
col = randint(1, 5)
if col == 1:
pencolor("orange")
elif col == 2:
pencolor("blue")
elif col == 3:
pencolor("green")
elif col == 4:
pencolor("purple")
elif col == 5:
pencolor("dark blue")
circle(50)
left(20)
This is the output:
My code is here and the function was built for automatically choosing the random colour.
from turtle import Turtle, Screen
import random
timmy = Turtle()
screen = Screen()
screen.colormode(255)
timmy.shape("turtle")
timmy.speed("fastest")
angle = [0, 90, 180, 270]
def random_color():
red = random.randint(0, 255)
green = random.randint(0, 255)
blue = random.randint(0, 255)
colour = (red, green, blue)
return colour
def draw_circles(num_of_gap):
for _ in range(int(360 / num_of_gap)):
timmy.color(random_color())
timmy.circle(100)
timmy.right(num_of_gap)
draw_circles(20)
screen.exitonclick()
Spirograph using Python Turtle with random colours
Code:
import random
from turtle import Turtle, Screen
tim = Turtle()
tim.shape("classic")
def turtle_color():
R = random.random()
G = random.random()
B = random.random()
return tim.pencolor(R, G, B)
tim.speed("fastest")
for _ in range(72):
turtle_color()
tim.circle(100)
tim.left(5)
screen = Screen()
screen.exitonclick()
Output:
You basically get the turtle to loop through the 360 degrees and you can choose two pen colours.
from turtle import Turtle, Screen
tim = Turtle()
tim.shape("turtle")
tim.color("green")
### total degrees in circle = 360
### turn left must be a divisor of 360 (1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, 24, 30, 36, 40, 45, 60, 72, 90) NOTE: some divisors do not work as well
degrees = 360
turn_left = 12
total_circles = int(degrees / turn_left)
tim.pensize(3)
tim.speed(0)
def circle_colour1():
### choose your colour here:
tim.pencolor("pink")
tim.circle(-100)
tim.left(turn_left)
def circle_colour2():
### choose your colour here:
tim.pencolor("grey")
tim.circle(-100)
tim.left(turn_left)
for _ in range(0, int(total_circles / 2)):
circle_colour1()
circle_colour2()
screen = Screen()
screen.exitonclick()
Real basic (360°/10) is:
from turtle import Turtle as d
draw = d()
draw.speed(0)
draw.pensize(3)
for _ in range(0, 36):
draw.circle(-100)
draw.left(10)

Categories

Resources