Write a function monteCarloPi(n, radius) that takes two arguments, the number of simulations n and the radius of the circle, and returns a float, which is the estimated value for pi. This radius should be the same radius that you used to draw your inscribed circle in the previous problem. Generate a set of random points, and test to see if that value is inside the circle or outside the circle. Use turtle to draw a dot at each location. This can be done using the function turtle.dot(size, color). Find the ratio of the points inside the circle to the number of points in the simulation. The latter number is an estimate for the area of the square. Multiple the ratio by four to get your estimate for pi.
This is what I have and I have no idea why it only draws one dot. Can anybody help me? I am a beginner /:
import turtle as t
import random
def monteCarloPi(n, radius):
'''
Takes two arguments, the number of simulations n and the radius of the circle, and returns a float, which is the estimated value for pi.
'''
t.dot() # Origin (0, 0)
t.pu()
t.goto(0, -radius)
t.pd()
t.circle(radius)
t.pu()
t.goto(-radius ,-radius)
t.pd()
for square in range(4):
t.fd(radius * 2)
t.lt(90)
points_in_circle = 0
points_in_square = 0
x = random.uniform(-radius, radius)
y = random.uniform(-radius, radius)
for dots in range(n):
t.pu()
t.goto(x, y)
t.dot()
origin = x ** 2 + y ** 2
if origin <=1 :
points_in_circle += 1
else:
points_in_square +=1
pi = 4 * (points_in_circle / points_in_square)
return pi
I see a number of potential problems with your code. The last two lines shown aren't indented correctly, they should be after the loop, not in it.
This equation origin = x ** 2 + y ** 2 seems incorrect and might need to instead be origin = (x ** 2 + y ** 2) ** 0.5
These two statements:
x = random.uniform(-radius, radius)
y = random.uniform(-radius, radius)
need to be at the top of the loop, not before the loop, otherwise you're plotting the same point n times, instead of n points. This calculation seems wrong:
pi = 4 * (points_in_circle / points_in_square)
reread the instructions you provided above. You should be dividing by n not points_in_square. This doesn't seem correct:
if origin <=1 :
as we're not working with a unit circle, so I'd expect:
if origin <= radius:
The reworked code based on my above observations:
from turtle import Screen, Turtle
from random import uniform
def monteCarloPi(n, radius):
'''
Takes two arguments, the number of simulations n and the radius of the circle,
and returns a float, which is the estimated value for pi.
'''
turtle.dot() # Origin (0, 0)
turtle.penup()
turtle.sety(-radius)
turtle.pendown()
turtle.circle(radius)
turtle.penup()
turtle.setx(-radius)
turtle.pendown()
for _ in range(4):
turtle.forward(radius * 2)
turtle.left(90)
turtle.penup()
turtle.hideturtle()
points_in_circle = 0
for _ in range(n):
x = uniform(-radius, radius)
y = uniform(-radius, radius)
turtle.goto(x, y)
turtle.dot()
origin = (x ** 2 + y ** 2) ** 0.5
if origin <= radius:
points_in_circle += 1
pi = 4 * points_in_circle / n
return pi
screen = Screen()
turtle = Turtle()
turtle.speed('fastest') # because I have no patience
print(monteCarloPi(100, 100))
screen.exitonclick()
Related
I am trying to create a function that draws regular polygons inside each other as in the attached picture. The size of the polygons' side is defined by the following formula:
initial_size = initial_radius*(2*math.sin(360/(2*number_of_angles)))
I have two questions: 1. Why when I assign "initial_size" by the above formula my drawing starts in a different direction rather than when I simply assign initial_size = 100 (disregarding the formula)? 2. Can you please provide me with a hint (or any direction) on a way I can draw regular polygons as on the picture (i.e., starting from different points (moving along x-axis) and drawing each polygon inside the other?
import turtle
import math
turtle.speed(1)
def reg_polygon(number_of_angles, initial_radius):
Q = 180-(180/number_of_angles)/2
turtle.left(Q)
initial_size = initial_radius*(2*math.sin(360/(2*number_of_angles)))
if number_of_angles>=3:
sum_angle = 180*(number_of_angles-2)
angle = sum_angle/number_of_angles
for i in range(number_of_angles):
turtle.forward(initial_size)
turtle.left(180-angle)
elif number_of_angles<3:
print("Minimum number of angels should be >=3")
for i in range(3,6):
reg_polygon(i,100)
turtle.done()
Here is what the following code snippet draws; it is not an absolutely perfect reproduction of the gif you posted (some tweaks for the size progression for 3, 4, and 5-gons must be done to avoid the smaller neighbors to touch at some points - i/e the gif maker somewhat cheated!), but it follows mathematical symmetry and perfection.
The following code has some magic numbers; I may come back to it later, but not at this time. The resources I used to calculate a regular polygon can be found here, and there.
import turtle
import math
def reg_polygon(start_pos, number_of_angles, side):
interior_angle = (180 * (number_of_angles - 2)) / number_of_angles
turtle.setheading(180 - interior_angle//2)
for i in range(number_of_angles):
turtle.forward(side)
turtle.left(180 - interior_angle)
def reset_start_point():
global start_pos, startx, starty, initial_size, number_of_angles, side
startx += 8
starty -= 0
initial_size += 8
number_of_angles += 1
side = 2 * initial_size * math.sin(math.radians(180/number_of_angles))
start_pos = startx, starty
turtle.penup()
turtle.goto((startx, starty))
turtle.pendown()
start_pos = startx, starty = 0, 0
number_of_angles = 2
initial_size = 15 # radius
side = 0
while number_of_angles < 21:
reset_start_point()
reg_polygon(start_pos, number_of_angles, side)
turtle.done()
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question 8 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I got a challenge in a learning group today to draw this shape in python turtle library.
I cannot figure out a way to express the geometrical solution to find the angles to turn and the size of the line I need.
Can you please tell me how to draw the first polygon alone? I already know how to make the pattern.
I am in fifth grade. So please give me a solution that I can understand.
Here is the solution I came up with. It is based on this diagram:
Math background
My solution uses "trigonometry", which is a method for calculating the length of one side of a triangle from the length of another side and the angles of the triangle. This is advanced math which I would expect to be taught maybe in 9th or 10th grade. I do not expect someone in 5th grade to know trigonometry. Also I cannot explain every detail of trigonometry, because I would have to write a lot and I do not think I have the teaching skills to make it clear. I would recommend you to look at for example this video to learn about the method:
https://www.youtube.com/watch?v=5tp74g4N8EY
You could also ask your teacher for more information, or research about it on the internet on your own.
Step 1: Calculating the angles
We can do this without trigonometry.
First, we see there is a "pentagon" (5-sided polygon) in the middle. I want to know the inner angle of a corner in this "pentagon". I call this angle X:
How can we calculate the angle X? We first remember that the sum of the inner angles in a triangle is 180°. We see that we can divide a 5-sides polygon into 5-2 triangles like this:
The sum of the inner angle of each of these 5-2 triangles is 180°. So for the whole 5-sided polygon, the sum of the inner angles is 180° * (5-2). Since all angles have the same size, each angle is 180°*(5-2) / 5 = 108°. So we have X = 108°.
The angle on the other side is the same as X. This allows us the calculate the angle between the two X. I will call this angle Y:
Since a full circle is 360°, we know that 360° = 2*X + 2*Y. Therefore, Y = (360° - 2*X) / 2. We know that X = 108°, so we get Y = 72°.
Next, we see there is a triangle containing the Y angle. I want to know the angle Z at the other corner of the triangle:
The inner angles of a triangle sum up to 180°*(3-2) = 180°. Therefore, we know that 180° = 2*Y + Z, so Z = 180° - 2*Y. We know that Y = 72°, so we get Z = 36°.
We will use the angle Z a lot. You can see that every corner of the green star has angle Z. The blue star is the same as the green star except it is rotated, so all blue corners also have angle Z. The corners of the red star are twice as wide as the corners of the green and blue stars, so the corners of the red star have the angle 2*Z.
Step 2: Calculating the lengths
First, we observe that all outer corners are on a circle. We call the radius of this circle R. We do not have to calculate R. Instead, we can take any value we want for R. We will always get the same shape but in different sizes. We could call R a "parameter" of the shape.
Given some value for R, I want to know the following lengths:
Calculating A:
We start with A. We can see the following triangle:
The long side of the triangle is our radius R. The other side has length A/2 and we do not care about the third side. The angle in the right-most corner is Z/2 (with Z = 36° being the angle we calculated in the previous section). The angle S is a right-angle, so S = 90°. We can calculate the third angle T because we know that the inner angles of a triangle sum up to 180°. Therefore, 180° = S + Z/2 + T. Solving for T, we get T = 180° - S - Z/2 = 180° - 90° - 36°/2 = 72°.
Next, we use trigonometry to calculate A/2. Trigonometry teaches us that A/2 = R * sin(T). Putting in the formula for T, we get A/2 = R * sin(72°). Solving for A, we get A = 2*R*sin(72°).
If you pick some value for R, for example R = 100, you can now calculate A with this formula. You would need a calculator for sin(72°), because it would be extremely difficult to calculate this in your head. Putting sin(72) into my calculator gives me 0.951056516. So for our choice R = 100, we know that A = 2 * R * sin(72°) = 2 * 100 * 0.951056516 = 190.211303259.
Calculating B:
We use the same technique to find a formula for B. We see the following triangle:
So the bottom side is the length of our radius R. The right side is B/2. We do not care about the third side. The right-most angle is three times Z/2. The angle S is a right-angle, so we have S = 90°. We can calculate the remaining angle T with 180° = S + T + 3*Z/2. Solving for T, we get T = 180° - S - 3*Z/2 = 180° - 90° - 3*36°/2 = 36°. Ok so T = Z, we could have also seen this from the picture, but now we have calculated it anyways.
Using trigonometry, we know that B/2 = R * sin(T), so we get the formula B = 2 * R * sin(36°) to calculate B for some choice of R.
Calculating C:
We see the following triangle:
So the bottom side has length A/2 and the top side has length B. We already have formulas for both of these sides. The third side is C, for which we want to find a formula. The right-most angle is Z. The angle S is a right-angle, so S = 90°. The top-most angle is three times Z/2.
Using trigonometry, we get C = sin(Z) * B.
Calculating D:
We see the following triangle:
We already have a formula for C. We want to find a formula for D. The top-most angle is Z/2 (I could not fit the text into the triangle). The bottom-left angle S is a right-angle.
Using trigonometry, we know that D = tan(Z/2) * C. The tan function is similar to the sin from the previous formulas. You can again put it into your calculator to compute the value, so for Z = 36°, I can put tan(36/2) into my calculator and it gives me 0.324919696.
Calculating E:
Ok this is easy, E = 2*D.
Halfway done already!
Calculating F:
This is similar to A and B:
We want to find a formula for F. The top side has length F/2. The bottom side has the length of our radius R. The right-most corner has angle Z. S is a right-angle. We can calculate T = 180° - S - Z = 180° - 90° - Z = 90° - Z.
Using trigonometry, we get F/2 = R * sin(T). Putting in the formula for T gives us F/2 = R*sin(90° - Z). Solving for F gives us F = 2*R*sin(90°-Z).
Calculating G:
We see the following triangle:
The top side has length F, we already know a formula for it. The right side has length G, we want to find a formula for it. We do not care about the bottom side. The left-most corner has angle Z/2. The right-most corner has angle 2*Z. The bottom corner has angle S, which is a right-angle, so S = 90°. It was not immediately obvious to me that the red line and the green line are perfectly perpendicular to each other so that S really is a right-angle, but you can verify this by using the formula for the inner angles of a triangle, which gives you 180° = Z/2 + 2*Z + S. Solving for S gives us S = 180° - Z/2 - 2*Z. Using Z = 36°, we get S = 180° - 36°/2 - 2* 36° = 90°.
Using trigonometry, we get G = F * sin(Z/2).
Calculating H:
We see the following triangle:
The right side has length G, we already have formula for that. The bottom side has length H, we want to find a formula for that. We do not care about the third side. The top corner has angle Z, the bottom-right corner has angle S. We already know that S is a right-angle from the last section.
Using trigonometry, we get H = G * tan(Z).
Calculating I:
This is easy, I is on the same line as A. We can see that A can be divided into A = I + H + E + H + I. We can simplify this to A = 2*I + 2*H + E. Solving for I gives us I = (A - 2*H - E)/2.
Calculating J:
Again this is easy, J is on the same line as F. We can see that F can be divided into F = G + J + G. We can simplify that to F = 2*G + J. Solving for J gives us J = F - 2*G.
Writing the Python program
We now have formulas for all the lines we were interested in! We can now put these into a Python program to draw the picture.
Python gives you helper functions for computing sin and tan. They are contained in the math module. So you would add import math to the top of your program, and then you can use math.sin(...) and math.tan(...) in your program. However, there is one problem: These Python functions do not use degrees to measure angles. Instead they use a different unit called "radians". Fortunately, it is easy to convert between degrees and radians: In degrees a full circle is 360°. In radians, a full circle is 2*pi, where pi is a special constant that is approximately 3.14159265359.... Therefore, we can convert an angle that is measured in degrees into an angle that is measured in radians, by dividing the angle by 360° and then multiplying it by 2*pi. We can write the following helper functions in Python:
import math
def degree_to_radians(angle_in_degrees):
full_circle_in_degrees = 360
full_circle_in_radians = 2 * math.pi
angle_in_radians = angle_in_degrees / full_circle_in_degrees * full_circle_in_radians
return angle_in_radians
def sin_from_degrees(angle_in_degrees):
angle_in_radians = degree_to_radians(angle_in_degrees)
return math.sin(angle_in_radians)
def tan_from_degrees(angle_in_degrees):
angle_in_radians = degree_to_radians(angle_in_degrees)
return math.tan(angle_in_radians)
We can now use our functions sin_from_degrees and tan_from_degrees to compute sin and tan from angles measured in degrees.
Putting it all together:
from turtle import *
import math
# Functions to calculate sin and tan ###########################################
def degree_to_radians(angle_in_degrees):
full_circle_in_degrees = 360
full_circle_in_radians = 2 * math.pi
angle_in_radians = angle_in_degrees / full_circle_in_degrees * full_circle_in_radians
return angle_in_radians
def sin_from_degrees(angle_in_degrees):
angle_in_radians = degree_to_radians(angle_in_degrees)
return math.sin(angle_in_radians)
def tan_from_degrees(angle_in_degrees):
angle_in_radians = degree_to_radians(angle_in_degrees)
return math.tan(angle_in_radians)
# Functions to calculate the angles ############################################
def get_X():
num_corners = 5
return (num_corners-2)*180 / num_corners
def get_Y():
return (360 - 2*get_X()) / 2
def get_Z():
return 180 - 2*get_Y()
# Functions to calculate the lengths ###########################################
def get_A(radius):
Z = get_Z()
return 2 * radius * sin_from_degrees(90 - Z/2)
def get_B(radius):
Z = get_Z()
return 2 * radius * sin_from_degrees(90 - 3*Z/2)
def get_C(radius):
Z = get_Z()
return sin_from_degrees(Z) * get_B(radius)
def get_D(radius):
Z = get_Z()
return tan_from_degrees(Z/2) * get_C(radius)
def get_E(radius):
return 2 * get_D(radius)
def get_F(radius):
Z = get_Z()
return 2 * radius * sin_from_degrees(90 - Z)
def get_G(radius):
Z = get_Z()
return get_F(radius) * sin_from_degrees(Z/2)
def get_H(radius):
Z = get_Z()
return get_G(radius) * tan_from_degrees(Z)
def get_I(radius):
A = get_A(radius)
E = get_E(radius)
H = get_H(radius)
return (A - E - 2*H) / 2
def get_J(radius):
F = get_F(radius)
G = get_G(radius)
return F - 2*G
# Functions to draw the stars ##################################################
def back_to_center():
penup()
goto(0, 0)
setheading(0)
pendown()
def draw_small_star(radius):
penup()
forward(radius)
pendown()
Z = get_Z()
left(180)
right(Z/2)
E = get_E(radius)
H = get_H(radius)
I = get_I(radius)
for i in range(0,5):
penup()
forward(I)
pendown()
forward(H)
penup()
forward(E)
pendown()
forward(H)
penup()
forward(I)
left(180)
right(Z)
back_to_center()
def draw_green_star(radius):
pencolor('green')
draw_small_star(radius)
def draw_blue_star(radius):
pencolor('blue')
Z = get_Z()
left(Z)
draw_small_star(radius)
def draw_red_star(radius):
pencolor('red')
Z = get_Z()
penup()
forward(radius)
pendown()
left(180)
right(Z)
G = get_G(radius)
J = get_J(radius)
for i in range(0,10):
pendown()
forward(G)
penup()
forward(J)
pendown()
forward(G)
left(180)
right(2*Z)
back_to_center()
def draw_shape(radius):
draw_green_star(radius)
draw_blue_star(radius)
draw_red_star(radius)
radius = 400
draw_shape(radius)
done()
Output:
Here's a different solution. It's based on a kite polygon where the upper portion is a pair of 3-4-5 right triangles and the lower portion is a pair of 8-15-17 right triangles:
from turtle import Screen, Turtle
KITES = 10
RADIUS = 100
def kite(t):
t.right(37)
t.forward(100)
t.right(81)
t.forward(170)
t.right(124)
t.forward(170)
t.right(81)
t.forward(100)
t.right(37)
turtle = Turtle()
turtle.penup()
turtle.sety(-RADIUS)
for _ in range(KITES):
turtle.circle(RADIUS, extent=180/KITES)
turtle.pendown()
kite(turtle)
turtle.penup()
turtle.circle(RADIUS, extent=180/KITES)
turtle.hideturtle()
screen = Screen()
screen.exitonclick()
(Yes, I'm obsessed with this puzzle.) I was sufficiently impressed by the brevity of #AnnZen's solution, I decided to see if I could come up with an even shorter one. The only unique structure in this polygon is the side of the kite:
So the problem becomes drawing ten of these in a circular fashion, and then reversing the code to draw them again in the opposite direction:
from turtle import *
for _ in range(2):
for _ in range(10):
fd(105)
lt(90)
fd(76.5)
pu()
bk(153)
rt(54)
pd()
lt(72)
lt, rt = rt, lt
done()
My Short code:
from turtle import *
for f, t in [(0,-72),(71,108),(71,0)]*10+[(29,90),(73,72),(73,90),(29,72)]*10:fd(f),rt(t)
Here's the solution:
import turtle
#turtle.tracer(0)
a = turtle.Turtle()
for _ in range(10):
a.forward(100)
a.right(90)
a.forward(73)
a.right(72)
a.forward(73)
a.backward(73)
a.right(108)
a.forward(73)
a.right(90)
a.penup()
a.forward(100)
a.pendown()
a.forward(100)
a.right(108)
#turtle.update()
Let's look at a yet another approach to drawing this shape. We'll start with the same diagram as #f9c69e9781fa194211448473495534
Using a ruler (1" = 100px) and protractor on the OP's original image, we can approximate this diagram with very simple code:
from turtle import Screen, Turtle
turtle = Turtle()
turtle.hideturtle()
turtle.penup() # center on the screen
turtle.setposition(-170, -125)
turtle.pendown()
for _ in range(10):
turtle.forward(340)
turtle.left(126)
turtle.forward(400)
turtle.left(126)
screen = Screen()
screen.exitonclick()
This is equivalent to drawing with a pencil and not lifting it nor overdrawing (backing up) on any line.
To make the shape we want pop out, we divide the two lines that we draw above into segments that are thinner and thicker. The first line breaks into three segments and the second into five:
To do this, we simply break the forward() calls in our loop into wide and narrow segments:
for _ in range(10):
turtle.width(4)
turtle.forward(105)
turtle.width(1)
turtle.forward(130)
turtle.width(4)
turtle.forward(105)
turtle.left(126)
turtle.width(1)
turtle.forward(76.5)
turtle.width(4)
turtle.forward(76.5)
turtle.width(1)
turtle.forward(94)
turtle.width(4)
turtle.forward(76.5)
turtle.width(1)
turtle.forward(76.5)
turtle.left(126)
Finally, we replace the thickness changes with lifting and lowering the pen:
Which is simply a matter of replacing the width() calls with penup() and pendown():
for _ in range(10):
turtle.pendown()
turtle.forward(105)
turtle.penup()
turtle.forward(130)
turtle.pendown()
turtle.forward(105)
turtle.left(126)
turtle.penup()
turtle.forward(76.5)
turtle.pendown()
turtle.forward(76.5)
turtle.penup()
turtle.forward(94)
turtle.pendown()
turtle.forward(76.5)
turtle.penup()
turtle.forward(76.5)
turtle.left(126)
This is a question that i had to solve, but have been banging my head against a wall for the past 5 days. There must be something really simple that i am missing, or misunderstanding, as the logic seems 100% correct in my head, but it just won't work.
I need to draw "scattered" houses, that do not over lap, 100 of them.
I have to use turtle to draw them, so i have X and Y coordinates.
And X and Y list for verification purposes, to see if a house is already in that place.
What i am doing is drawing a "house" (square with a triangle on top) on the randomized coordinates,
I loop while the number of houses is less than 100.
On each loop i randomize the x and y coordinates, from where i start drawing each house with turtle.
I check if the value is already in the X and Y verification lists, and also if my new X and Y are +/- the size of the house (treating it as a square)
import turtle
import time
import random
t = turtle.Turtle()
turtle.screensize(1920,1000)
x_verif = []
y_verif = []
t.speed(0)
collision = None
def square():
for s in range(0, 4):
t.forward(90)
t.left(90)
def triangle():
for s in range(0, 2):
t.left(-60)
t.forward(52)
def house():
square()
t.left(90)
t.forward(90)
triangle()
def scatter():
print("a")
house()
x1 = random.randint(-850, 850)
y1 = random.randint(-380, 380)
count = 0
while count < 100:
print("a2")
i = 0
u = 0
collision = False
for tries in range (0, 2):
print("a3")
x_verif.append(x1)
y_verif.append(y1)
while u < 100:
print("a4")
print(x_verif, y_verif, x1, y1)
while i < len(x_verif):
x1 = random.randint(-850, 850)
y1 = random.randint(-380, 380)
print(x1, y1)
if x1 not in x_verif and (x1 > x_verif[i]+91 or x1 < x_verif[i]-91):
if y1 not in y_verif and (y1 > y_verif[i]+142 or y1 < y_verif[i]-142):
collision = False
else:
collision = True
if collision == False:
t.penup()
t.hideturtle()
t.setx(x1)
t.sety(y1)
t.pendown()
house()
x_verif.append(x1)
y_verif.append(y1)
count += 1
i+= 1
u += 1
scatter()
Sorry for the ugly code, and the simplicity behind it. I would love to use list comprehensions for this, but i do not know where my logic fails at the moment. This is like my 100th try, as of this version it only draws the initial house and i think it loops infinitely somewhere....
My problem lies in looping through the whole lists for every new value. Do i need to loop through them every time, or is there some IF condition that I can use? Edit: It keeps on looping through random values, but none of them are accepted by the two IF statements that i'm using.
On a side note: With my current code they also change direction of drawing every time... No idea why is that happening....
Edit: I am very thankful for all the solutions! I'm struggling with the note at the beginning of the question. It says that it should only take a couple more lines to do the last one, compared to the first one..... Are they joking?
This turned out to be a trickier problem than I assumed from the description. My approach was to treat, and store, a house as two polygons, a square and a triangle. I randomly test draw (pen up) a house and compare all the points in its polygons to see if they are inside existing house polygons, and vice versa. If no overlap, draw the house for real. The solution is not efficient, but it allows tight packing of houses than a simple diameter-based approach.
The point in triangle routine is based on one from GeeksForGeeks.org
I have one slight fudge factor in my code that still needs to be polished out. But overall it seems to achieve the objective:
from turtle import Screen, Turtle
from random import randint
HOUSES = 100
HOUSE_SIZE = 90
WINDOW_WIDTH, WINDOW_HEIGHT = 1920, 1000
# assumes roof is an isosceles triangle
ROOF_SIDE = HOUSE_SIZE * 3**0.5 / 3
ROOF_HEIGHT = ROOF_SIDE // 2
FONT_SIZE = HOUSE_SIZE // 3
FONT = ('Arial', FONT_SIZE, 'normal')
def square(turtle, identity=None):
turtle.begin_poly()
for _ in range(3):
turtle.forward(HOUSE_SIZE)
turtle.right(90)
turtle.end_poly()
turtle.forward(HOUSE_SIZE/2 - FONT_SIZE/2) # visually finish square
if identity: # label each house with a number
turtle.penup()
turtle.right(90)
turtle.forward(HOUSE_SIZE/2)
turtle.write(identity, align='center', font=FONT)
turtle.backward(HOUSE_SIZE/2)
turtle.left(90)
turtle.pendown()
turtle.forward(HOUSE_SIZE/2 + FONT_SIZE/2) # visually finish square
turtle.right(90) # return to original orientation
return turtle.get_poly()
def triangle(turtle):
turtle.begin_poly()
turtle.forward(HOUSE_SIZE)
turtle.left(150)
turtle.forward(ROOF_SIDE)
turtle.end_poly()
turtle.left(60)
turtle.forward(ROOF_SIDE) # visually finish triangle
turtle.right(210) # return to original orientation
return turtle.get_poly()
def house(turtle, identity=None):
return (square(turtle, identity), triangle(turtle))
def area_of_triangle(p1, p2, p3):
x1, y1 = p1
x2, y2 = p2
x3, y3 = p3
return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))) // 2
def is_inside_triangle(point, triangle):
p1, p2, p3 = triangle
a = area_of_triangle(p1, p2, p3)
b = area_of_triangle(point, p2, p3)
c = area_of_triangle(p1, point, p3)
d = area_of_triangle(p1, p2, point)
return abs(a - (b + c + d)) < 5 # 5 == fudge factor, sigh
def is_inside_square(point, square):
x, y = point
p1, p2, p3, p4 = square
_, y1 = p1
x2, _ = p2
_, y3 = p3
x4, _ = p4
return x4 <= x <= x2 and y3 <= y <= y1
def scatter(turtle):
houses = []
count = 0
while count < HOUSES:
x = randint(-WINDOW_WIDTH/2, WINDOW_WIDTH/2 - HOUSE_SIZE)
y = randint(HOUSE_SIZE - WINDOW_HEIGHT/2, WINDOW_HEIGHT/2 - ROOF_HEIGHT)
turtle.penup()
turtle.goto(x, y)
proposed_square, proposed_triangle = house(turtle) # test draw invisible house
turtle.pendown()
collision = False
for point in proposed_square + proposed_triangle: # does proposed house collide with houses?
for square, triangle in houses:
if is_inside_square(point, square) or is_inside_triangle(point, triangle):
collision = True
break
if collision:
break
for square, triangle in houses: # do houses collide with proposed house?
for point in square + triangle:
if is_inside_square(point, proposed_square) or is_inside_triangle(point, proposed_triangle):
collision = True
break
if collision:
break
if not collision:
count += 1
houses.append(house(turtle, identity=count)) # actually draw new house
print(count)
screen = Screen()
screen.screensize(WINDOW_WIDTH, WINDOW_HEIGHT)
screen.tracer(False)
turtle = Turtle()
turtle.hideturtle()
scatter(turtle)
screen.tracer(True)
screen.exitonclick()
This problem is simplified somewhat by the consistent orientation of houses. If the houses were randomly oriented, compass-wise, the square overlap calculations would be more complex.
The solution could be made more efficient by doing triangle overlap with triangle, square overlap with triangle, etc. tests instead of simply "point inside". We could also push the collision logic down into the square() and triangle() routines to throw an error as soon as there's a collsion, rather than completing a house and then testing.
Given the size of the screen area, size of a house, the number of houses, and the random scattering, I believe it may be possible for an idividual run of the program to stall trying to place a house where there may not be available space:
Defo no the best way to do it but
import turtle
import time
import random
t = turtle.Turtle()
turtle.screensize(1920,1000)
x_verif = []
y_verif = []
t.speed(0)
collision = None
def square():
for s in range(0, 4):
t.forward(90)
t.left(90)
def triangle():
for s in range(0, 2):
t.left(-60)
t.forward(52)
def house():
square()
t.left(90)
t.forward(90)
triangle()
t.left(30) #returning to 90 degrres
def scatter():
beenAt = [] #this will hold every place that there is a house
for i in range(100):
t.penup()
loop = True
while loop == True:
area = random.randint(-850, 850)
for i in range(91): #looping for the size of the house
if area+i in beenAt: #if the number chosen plus i is in beenAt stop because we cant use that place
break
if i == 90: #if at the finial part of our loop then draw house
t.goto(area, 0)
t.pendown()
for i in range(area, area + 91):
beenAt.append(i) #add to been at list every place we have drawn
house()
loop = False
scatter()
I'm using Python Turtles to draw a circle using forward() and right().
I have a for loop counting from 0 to 359, and each time it triggers, it moves the turtle forward 1 and right 1.
But the problem is I need specific diameters. I am nearly 100% sure I'll need to use trig, but I've tried to no avail.
I can't figure out the math how to do it. We're supposed to use forward() and right(), NOT circle().
Thanks!
Here is a working example:
import turtle
import math
def circle(radius):
turtle.up()
# go to (0, radius)
turtle.goto(0,radius)
turtle.down()
turtle.color("black")
# number of times the y axis has been crossed
times_crossed_y = 0
x_sign = 1.0
while times_crossed_y <= 1:
# move by 1/360 circumference
turtle.forward(2*math.pi*radius/360.0)
# rotate by one degree (there will be
# approx. 360 such rotations)
turtle.right(1.0)
# we use the copysign function to get the sign
# of turtle's x coordinate
x_sign_new = math.copysign(1, turtle.xcor())
if(x_sign_new != x_sign):
times_crossed_y += 1
x_sign = x_sign_new
return
circle(100)
print('finished')
turtle.done()
Well, a complete circle is 360°, and you are planning on turning 360 times, so each turn should be:
right( 360 ° / 360 ), or
right(1)
The distance traveled will be one circumference, or π * diameter, so your forward might be:
forward( diameter * π / 360 )
I haven't tested this yet -- give it a try and see how it works.
This is one of the exercises in "Think Python," in chapter 4. It really is a horrible exercise to have this early in the book, especially with the "hint" given. I'm using forward and left here, but you can switch left with right.
You should have the polygon function:
def polygon(t, length, n):
for i in range(n):
bob.fd(length)
bob.lt(360 / n)
Then you create a circle function:
def circle(t):
polygon(t, 1, 360)
That will draw a circle, no radius needed. The turtle goes forward 1, then left 1 (360 / 360), 360 times.
Then, if you want to make the circle bigger, you calculate the circumference of the circle. The hint says:
Hint: figure out the circumference of the circle and make sure that
length * n = circumference.
Ok, so the formula for circumference = 2 * pi * radius. And the hint says length * n = circumference. n = 360 (number of sides/degrees). We have circumference, so we need to solve for length.
So:
def circle(t, r):
circumference = 2 * 3.14 * r
length = circumference / 360
polygon(t, length, 360)
Now, call the function with whatever radius you want:
circle(bob, 200)
I'm trying to create python program that has several vertical lines which act as boundaries where randomly generated points or "dots" (as referred to in the code) which draw a straight line at a random degree. If the straight line intersects with one of the vertical "boundaries" I want to make it change colour. I have a picture of what I am trying to achieve which will probably explain my situation a bit clearer. The code I post below has drawn the "vertical boundaries" and has the points randomly generated within the region, however that is where I am stuck.
What I am aiming to achieve:
Example of program
My current Code:
setup(750,750)
screen_size = 750
max_coord = (screen_size - 30) / 2
### change the number of dots you have via that variable
num_dots = 500
bgcolor('yellow')
dot_size=5
reset() # Create an empty window
pi = Turtle()
hideturtle()
def parallel_lines(number):
pi.pensize(2)
pi.pencolor('black')
width = pi.window_width()
height = pi.window_height()
pi.setheading(90)
pi.penup()
pi.setposition(width/-2, height/-2)
for i in range(1, number +2):
pi.pendown()
pi.forward(height)
pi.penup()
pi.setposition(width/-2+i*(width/(number+1)),height/-2)
parallel_lines(7)
## centre turtle back in the middle of the page
goto(0,0)
### list to hold the dots
x_coords = []
y_coords = []
### Draw the dots via randomint
penup()
color("blue")
for dot_num in range(num_dots):
dot_pos_x = randint (-max_coord, max_coord)
dot_pos_y = randint (-max_coord, max_coord)
goto(dot_pos_x, dot_pos_y)
dot(dot_size)
x_coords.append(dot_pos_x)
y_coords.append(dot_pos_y)
done()
Thank you in advance for anyone that can help.
Here's an implementation of the program the OP describes. If there is a line intersection, it uses Python 3 turtle's undo feature to remove the line and redraw it in the alternate color:
from turtle import Turtle, Screen
from random import randint, randrange
SCREEN_SIZE = 750
PLANK_COUNT = 8
PINHEAD_SIZE = 5
FLOOR_COLOR = "yellow"
DEFAULT_COLOR = "blue"
CROSSING_COLOR = "red"
screen = Screen()
screen.setup(SCREEN_SIZE, SCREEN_SIZE)
screen.bgcolor(FLOOR_COLOR)
# configure numbers to replicate Lazzarini's setup
NUMBER_PINS = 3408
PIN_LENGTH = 78.125
PLANK_WIDTH = screen.window_width() / PLANK_COUNT
def parallel_lines(turtle, width, height):
turtle.penup()
turtle.setheading(90)
turtle.sety(height / -2)
x_coordinates = []
for i in range(PLANK_COUNT + 1):
x = i * PLANK_WIDTH - width / 2
turtle.setx(x)
turtle.pendown()
turtle.forward(height)
turtle.penup()
turtle.left(180)
x_coordinates.append(x)
return x_coordinates
pi = Turtle(visible=False)
pi.speed("fastest")
x_coordinates = parallel_lines(pi, screen.window_width(), screen.window_height())
def crosses(x0, x1, coordinates):
for coordinate in coordinates:
if x0 <= coordinate <= x1 or x1 <= coordinate <= x0:
return True
return False
previous_crossings = crossings = 0
max_coord = screen.window_width() / 2
for pin in range(NUMBER_PINS):
x0, y0 = randint(-max_coord, max_coord), randint(-max_coord, max_coord)
pi.color(DEFAULT_COLOR)
pi.goto(x0, y0)
pi.dot(PINHEAD_SIZE)
pi.setheading(randrange(360))
pi.pendown()
pi.forward(PIN_LENGTH)
if crosses(x0, pi.xcor(), x_coordinates):
pi.undo()
pi.color(CROSSING_COLOR)
pi.dot(PINHEAD_SIZE)
pi.forward(PIN_LENGTH)
crossings += 1
pi.penup()
if previous_crossings != crossings:
estimate = (2 * PIN_LENGTH * pin) / (PLANK_WIDTH * crossings)
print(estimate)
previous_crossings = crossings
screen.exitonclick()
Now for the rest of the story. What the OP didn't mention is that this is a drawing of planks in a floor, and we're dropping pins onto it, keeping track of how many cross lines in the flooring, as a means of estimating the value of PI (π)!
Read about Buffon's needle for details. The gist is the probability of a pin crossing a line is a function of PI so we can turn the equation around, drop actual (or virtual) pins, to estimate PI.
The program outputs the running estimate for PI (π), based on pins dropped so far, to the console:
...
3.121212121212121
3.1215970961887476
3.1370772946859904
3.134418324291742
3.131768953068592
3.1381381381381384
3.1384892086330933
3.1358467983243568
3.1451612903225805
3.1454979129397733
3.1458333333333335
3.1491384432560903
3.1465005931198102
3.1438721136767316
3.144208037825059
3.144542772861357
3.1419316843345113