I'm trying to get the squares to look like:
but instead my code is drawing:
I dont know what I'm doing wrong or if my entire approach is wrong.
Here's the code:
import turtle as tt
def recurse(depth, size):
if depth==0:
pass
else:
if depth%2==0:
tt.pencolor('blue')
else:
tt.color('orange')
tt.fd(size)
tt.left(90)
tt.fd(size)
tt.left(90)
tt.fd(size)
tt.left(90)
tt.fd(size)
tt.left(90)
tt.fd(size)
tt.left(90)
tt.fd(size)
tt.right(90)
recurse(depth - 1, size / 3)
tt.penup()
tt.bk(size)
tt.pendown()
recurse(depth-1, size/3)
tt.penup()
tt.left(90)
tt.back(size)
tt.right(90)
tt.back(size)
tt.pendown()
recurse( 4, 100 )
tt.done()
At the top right, the small squares end up not being the correct size, and over on the left, turtle moves forward way too much.
How can I write the recursion to produce the correct top-left square?
Good attempt! I will suggest a slightly different approach, adding x and y coordinates for your square-drawing function and using t.goto(x, y) to reposition the turtle. These coordinates represent the bottom-left corner for where the square should be drawn, and save you the trouble of shuffling the turtle around by hand (although technically possible, it's less clean-cut).
After a square is drawn, the turtle will always be facing rightward and ready to draw the next square, so movement commands are kept to a minimum. All that remains is figuring out the origin coordinates for each corner.
For the top-right corner, it's easy: x + size, y + size. For the top-left corner, it's similar: still y + size, but use x - size_of_smaller_square to offset the x-axis by the correct amount. I've also included the bottom-left and bottom-right corners if you're curious.
import turtle as t
def draw_square(depth, size, x=0, y=0, shrink_by=3):
if depth <= 0:
return
t.penup()
t.goto(x, y)
t.color(("blue", "orange")[depth%2])
t.pendown()
for _ in range(4):
t.forward(size)
t.left(90)
smaller_size = size / shrink_by
draw_square(depth - 1, smaller_size, x + size, y + size)
draw_square(depth - 1, smaller_size, x - smaller_size, y + size)
#draw_square(depth - 1, smaller_size, x - smaller_size, y - smaller_size)
#draw_square(depth - 1, smaller_size, x + size, y - smaller_size)
if __name__ == "__main__":
t.speed("fastest")
draw_square(depth=4, size=100)
t.exitonclick()
You mentioned goto is prohibited. You can follow a mechanical strategy that is guaranteed to work: always put the turtle exactly back where it started (same position and direction) at the end of each recursive call. This respects the self-similar structure of recursion. The high-level approach per frame is:
draw the current box
for each child box:
move the turtle to the correct position and direction to draw the child box
spawn a recursive call
undo all of the moves you just made in step 3
Here's a correct but verbose and sloppy implementation of this strategy:
import turtle as t
def draw_square(depth, size, shrink_by=3):
if depth <= 0:
return
# draw this box
t.color(("blue", "orange")[depth%2])
t.pendown()
for _ in range(4):
t.forward(size)
t.left(90)
t.penup()
smaller_size = size / shrink_by
# put the turtle in the top-right facing east and spawn a child
t.forward(size)
t.left(90)
t.forward(size)
t.right(90)
draw_square(depth - 1, smaller_size)
# undo the moves
t.right(90)
t.forward(size)
t.left(90)
t.backward(size)
# put the turtle in the top-left facing east and spawn a child
t.left(90)
t.forward(size)
t.right(90)
t.backward(smaller_size)
draw_square(depth - 1, smaller_size)
# undo the moves
t.forward(smaller_size)
t.right(90)
t.forward(size)
t.left(90)
if __name__ == "__main__":
t.speed("fastest")
draw_square(depth=4, size=100)
t.exitonclick()
While this works, you can see there's some redundant movement that can be eliminated, while still preserving the property that the turtle will always wind up in the same position and direction they started from at the beginning of the recursive function. A rewrite:
import turtle as t
def draw_square(depth, size, shrink_by=3):
if depth <= 0:
return
# draw this box
t.color(("blue", "orange")[depth%2])
t.pendown()
for _ in range(4):
t.forward(size)
t.left(90)
t.penup()
smaller_size = size / shrink_by
# top-right
t.forward(size)
t.left(90)
t.forward(size)
t.right(90)
draw_square(depth - 1, smaller_size)
# top-left
t.backward(size + smaller_size)
draw_square(depth - 1, smaller_size)
# undo all of the moves to reset the turtle state
t.forward(smaller_size)
t.right(90)
t.forward(size)
t.left(90)
if __name__ == "__main__":
t.speed("fastest")
draw_square(depth=4, size=100)
t.exitonclick()
This can be made cleaner by attempting to find patterns and turn them into loops; for example, if you don't mind drawing children while you're in the process of drawing the parent box, you can skip the intermediate movements. This code draws all 4 corners, but you might try adapting it to the top 2 only:
import turtle as t
def draw_square(depth, size, shrink_by=3):
if depth <= 0:
return
for _ in range(4):
t.color(("blue", "orange")[depth%2])
t.forward(size)
t.right(90)
draw_square(depth - 1, size / shrink_by)
t.right(180)
if __name__ == "__main__":
t.speed("fastest")
t.pendown()
draw_square(depth=4, size=100)
t.exitonclick()
You're not allowd to use goto(), but are you allowed to use stamp()?
My rework of the excellent final solution of #ggorlen (+1) that uses stamping instead of drawing, also without goto:
import turtle
COLORS = ['blue', 'orange']
CURSOR_SIZE = 20
def draw_square(depth, size, shrink_by=3):
if depth:
turtle.pencolor(COLORS[depth % len(COLORS)])
turtle.shapesize(size / CURSOR_SIZE)
turtle.stamp()
offset = (size + (shrinkage := size / shrink_by)) * 2**0.5 / 2
for _ in range(4):
turtle.right(45)
turtle.forward(offset)
turtle.left(45)
draw_square(depth - 1, shrinkage)
turtle.right(45)
turtle.backward(offset)
turtle.left(135) # undo right and advance corners
if __name__ == "__main__":
turtle.shape('square')
turtle.speed('fastest')
turtle.fillcolor(turtle.bgcolor())
turtle.penup()
draw_square(depth=4, size=100)
turtle.hideturtle()
turtle.exitonclick()
Related
Here is the question : Write a non-fruitful function called barChart, that takes the numeric list of data as a parameter, and draws the bar chart. Write a full program calling this function. The current version of the drawBar function unfortuately draws the top of the bar through the bottom of the label. A nice elaboration is to make the label appear completely above the top line. To keep the spacing consistent you might pass an extra parameter to drawBar for the distance to move up. For the barChart function make that parameter be some small fraction of maxheight+border. The fill action makes this modification particularly tricky: You will want to move past the top of the bar and write b efore or after drawing and filling the bar..
What should I change?
Here is my code :
import turtle
def drawBar(t, height):
""" Get turtle t to draw one bar, of height. """
t.begin_fill() # start filling this shape
t.left(90)
t.forward(height)
t.write(str(height))
t.right(90)
t.forward(40)
t.right(90)
t.forward(height)
t.left(90)
t.end_fill() # stop filling this shape
You can pass the maximum value of the number list then draw the text and bar separately.
Try this code:
import turtle
def drawBar(t, height, mx):
# draw text
t.penup()
t.left(90)
t.forward(mx*10+10)
t.write(str(height).center(12))
t.right(180)
t.forward(mx*10+10)
t.left(90)
t.pendown()
""" Get turtle t to draw one bar, of height. """
t.fillcolor(.1, 1-1*height/mx/2, .1) # darker is higher value
t.begin_fill() # start filling this shape
t.left(90)
t.forward(height*10)
#t.write(" " + str(height))
t.right(90)
t.forward(40)
t.right(90)
t.forward(height*10)
t.left(90)
t.end_fill()
# bottom line
t.right(180)
t.forward(40)
t.right(180)
t.forward(40)
t = turtle.Turtle()
nums = [3,1,4,1,5,9,2]
t.speed(0) # fastest
for n in nums:
drawBar(t, n, max(nums))
t.hideturtle()
input('Enter to exit')
Output
I'm trying to create a rhombus tessellation pattern with the turtle graphics on python that looks like this image:
http://www.supercoloring.com/sites/default/files/styles/coloring_medium/public/cif/2015/01/tessellation-with-rhombus-coloring-pages.png
I thought about creating a hexagon pattern first and then dividing the hexagons into thirds. I'm not sure how I can create the hexagon pattern recursively. So far, I'm only alternating the angles of the turtles as I run the program and I don't have a definite strategy. Any advice on how to approach this?
So far, I created 3 hexagons in the center with 3 turtles and used for loops to draw the hexagons around the 3 hexagons. However, when I loop the program, the turtles trace back the same path as before and it takes a while for it to draw the others.
Here is my code so far:
import turtle
t = turtle.Turtle()
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t1.left(120)
t2.left(240)
for i in (t, t1, t2):
i.speed(0)
def hex():
for b in (t, t1, t2):
for i in range(6):
b.forward(100)
b.right(60)
for i in range(3):
t.left(120)
hex()
def rep():
for i in range(3):
for a in (t, t1, t2):
a.forward(100)
a.right(60)
for i in range(6):
a.forward(100)
a.left(60)
rep()
def rep2():
for a in (t, t1, t2):
for i in range(3):
a.left(120)
a.forward(100)
a.right(60)
rep()
a.right(120)
a.forward(100)
a.right(60)
rep()
rep2()
There are many of drawing this. I would draw based the rhombus shape because it will allow you to fill them with different colors. To be able to fill each rhombus, it needs to be drawn individually. The figure contains three different rhombus shapes (they are the same rhombus in different orientation).
I will draw first row and second row. After that it is repetition of the first and second row. Here is code:
def draw_rhombus(x,y,degree,size,tilt,color):
turtle.up()
turtle.goto(x,y)
turtle.seth(tilt)
turtle.down()
turtle.pencolor('dark gray')
turtle.fillcolor(color)
turtle.begin_fill()
turtle.fd(size)
turtle.left(degree)
turtle.fd(size)
turtle.left(180-degree)
turtle.fd(size)
turtle.left(degree)
turtle.fd(size)
turtle.left(180-degree)
turtle.end_fill()
def draw_rhombus_1(x,y,size):
draw_rhombus(x,y,120,size,0,'red')
def draw_rhombus_2(x,y,size):
draw_rhombus(x,y,60,size,0,'green')
def draw_rhombus_3(x,y,size):
draw_rhombus(x,y,60,size,60,'blue')
def rt_row_1(startx,starty,size,n):
x = startx
y = starty
for i in range(n):
draw_rhombus_1(x,y,size)
x += size
draw_rhombus_3(x,y,size)
draw_rhombus_2(x,y,size)
x += 2*size
def rt_row_2(startx,starty,size,n):
x = startx
y = starty
for i in range(n):
draw_rhombus_2(x,y,size)
x += 2*size
draw_rhombus_1(x,y,size)
x += size
draw_rhombus_3(x,y,size)
size = 80
x = -400
y = -400
for i in range(800//int(round(size*math.sqrt(3)))):
rt_row_1(x,y,size,800//(size*3))
rt_row_2(x-size/2,y+size*math.sqrt(3)/2,size,800//(size*3))
y += size*math.sqrt(3)
First, let's simplify your three turtle, three function hexagonal tessellation to a single turtle, single recursive function solution:
from turtle import Screen, Turtle
OUTER_RADIUS = 100
INNER_RADIUS = 3**0.5 * OUTER_RADIUS / 2
SIDES = 6
EXTENT = 360 / SIDES
def tessellation(depth):
turtle.right(EXTENT/2)
for _ in range(SIDES):
turtle.circle(OUTER_RADIUS, EXTENT, 1)
if depth:
heading = turtle.heading()
turtle.right(90)
tessellation(depth - 1)
turtle.setheading(heading)
screen = Screen()
turtle = Turtle(visible=False)
screen.tracer(False) # because I have no patience
turtle.penup()
turtle.goto(-OUTER_RADIUS / 2, -INNER_RADIUS)
turtle.pendown()
tessellation(2)
screen.tracer(True)
screen.exitonclick()
(Increase the depth argument to fill the window.) The tessellation you really want is four (not thirds) of these patterns overlaid atop each other. Keeping our initial code the same:
screen = Screen()
turtle = Turtle(visible=False)
screen.tracer(False) # because I have no patience
turtle.penup()
turtle.color('blue')
turtle.goto(OUTER_RADIUS / 4, -1 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
turtle.penup()
turtle.color('red')
turtle.goto(-OUTER_RADIUS / 2, -2 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
turtle.penup()
turtle.color('yellow')
turtle.goto(OUTER_RADIUS / 4, -3 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
turtle.penup()
turtle.color('green')
turtle.goto(-OUTER_RADIUS / 2, -4 * INNER_RADIUS / 2)
turtle.pendown()
turtle.setheading(0)
tessellation(2)
screen.tracer(True)
screen.exitonclick()
I've been trying to code this, but it's not working and I'm confused.
Use recursion to draw the “H-Tree” fractal.
The H-Tree fractal is defined as follows:
Begin with the letter H. The Three lines of the H are all of the same length, as shown in the first image. This is an H-Tree of order 0.
The letter H has four endpoints. Draw an H centered at each of the four endpoints, as shown in the second image. These H’s are half the size of the previous H. This is an
H-Tree of order 1.
Repeat step 2 to create an H-Tree fractal of higher orders, as shown in images 3 and 4.
Your function definition MUST have this format:
def h_tree(order, center, size):
Where:
order is is the order of the fractal, as described above
center is the center point of the H-Tree, in the format [x, y]
size is the length of each of the lines in the H
Here's my code:
import turtle
#reverse method
def reverse_string(string):
if len(string) == 0:
return string
else:
return reverse_string(string[1:]) + string[0]
#fractal method
def h_tree(order, center, size):
if order == 0:
draw_turtle([0,0], 300)
else:
get_endpoints(center, size)
h_tree(order-1, ep1, size)
h_tree(order-1, ep2, size)
h_tree(order-1, ep3, size)
h_tree(order-1, ep4, size)
def draw_turtle(center, size):
turtle.showturtle()
turtle.penup()
turtle.goto(center)
turtle.pendown()
turtle.forward(size/2)
turtle.left(90)
turtle.forward(size/2)
turtle.right(180)
turtle.forward(size)
turtle.penup()
turtle.goto(center)
turtle.right(90)
turtle.pendown()
turtle.forward(size/2)
turtle.right(90)
turtle.forward(size/2)
turtle.right(180)
turtle.forward(size)
turtle.done()
def get_endpoints(center, size):
ep1 = center[0] + size/2
ep2 = center[1] + size/2
ep3 = center[0] + size/2
ep4 = center[1] + size/2
return [ep1, ep2, ep3, ep4]
'''
The animate function needs to take in an x and y as arguments
because of how we are calling it from the main function.
Since it is being called when the mouse is clicked, it is
required to take the x,y location of the mouse at the time
of the click. You do not need to use the x,y for anything, so
just leave them there as parameters but you do not need to use
them inside your function.
'''
'''
def animate(x, y):
return
'''
def main():
# Q1 - call the recursive reverse_string() function
print(reverse_string("desserts"))
print(reverse_string("flow"))
print(reverse_string("abcdefg"))
# Q2 - call the recursive H-Tree fractal function
turtle.speed(0)
turtle.hideturtle()
h_tree(2, [0, 0], 300)
turtle.done()
'''
# Q3 - when the mouse is clicked in the turtle window,
# call the animate() function to display a spinning star
turtle.onscreenclick(animate)
'''
main()
You have a logic that's basically sound, though not the way I'd do it, but needs some patching. Mostly because you didn't follow through on your own logic. You know that h_tree() takes a position (pair of numbers) as its second argument but you only passed a single number (if even that, as #SRTHellKitty notes, you forgot to save the result of get_endpoints()). You also forgot to reduce size by half on the recursive call. You miscalculated two of the end points. And you didn't leave the turtle in its original orientation at the end of draw_turtle() which would have left you with half the H figures rotated, should you get it working.
Below is the repaired code -- I've pulled out your code for Q1 since it wasn't related to the problems you are asking about:
import turtle
def h_tree(order, center, size):
draw_turtle(center, size)
if order > 0:
ep1, ep2, ep3, ep4 = get_endpoints(center, size)
h_tree(order - 1, (ep1, ep2), size / 2)
h_tree(order - 1, (ep1, ep4), size / 2)
h_tree(order - 1, (ep3, ep2), size / 2)
h_tree(order - 1, (ep3, ep4), size / 2)
def draw_turtle(center, size):
turtle.penup()
turtle.goto(center)
turtle.pendown()
turtle.forward(size / 2) # right side of H
turtle.left(90)
turtle.forward(size / 2)
turtle.right(180)
turtle.forward(size)
turtle.penup()
turtle.goto(center)
turtle.pendown()
turtle.right(90) # left side of H
turtle.forward(size / 2)
turtle.right(90)
turtle.forward(size / 2)
turtle.right(180)
turtle.forward(size)
turtle.right(90) # return turtle to original orientation
def get_endpoints(center, size):
ep1 = center[0] + size / 2
ep2 = center[1] + size / 2
ep3 = center[0] - size / 2
ep4 = center[1] - size / 2
return ep1, ep2, ep3, ep4
def main():
turtle.speed('fastest')
h_tree(2, (0, 0), 300)
turtle.hideturtle()
turtle.done()
main()
I am trying to write a recursive turtle program that will draw a fractal tree recreating the shape below:
Turtle Fractal
This should be done with depth = 3, so three different levels of squares. My issue is that with the code I have already, the turtle on screen still doesn't move. Here is my code so far, any help is appreciated:
import turtle
def main():
turtle.speed(0)
turtle.screensize(1000,1000)
turtle.exitonclick()
turt = turtle.Turtle()
squares(turt, length, depth)
def squares(t,length, depth):
length = 200
depth = 3
amt = 1
if depth == 0:
return
elif depth == 3:
t.penup()
t.goto(-1000,-1000)
t.forward(length)
t.left(90)
t.forward(length)
t.left(90)
t.forward(length)
t.left(90)
t.forward(length)
squares(t, length/2, depth - 1)
elif depth == 2:
This incomplete elif will keep the code from even running:
elif depth == 2:
You define main(), but fail to call it:
def main():
You need to add an explicit call to main() at the end:
main()
Should you actually call main(), this premature exitionclick() will turn control over to tkinter before you ever invoke squares():
turtle.exitonclick()
turt = turtle.Turtle()
squares(turt, length, depthc)
the exitonclick() should be the last statement of main(), or happen after main outside the function. Your recursion will never happen as you overwrite two of your arguments:
def squares(t,length, depth):
length = 200
depth = 3
so length and depth will never change despite this test:
if depth == 0:
return
Fixing all of these won't get you a program that draws the fractal you desire, but fixing them is likely a necessary first step.
To make the code draw a fractal, you need to interlace the call to squares() with each forward motion of the turtle. Not do it just at the end:
t.forward(length)
t.left(90)
t.forward(length)
t.left(90)
t.forward(length)
t.left(90)
t.forward(length)
squares(t, length/2, depth - 1)
But something more like:
for _ in range(4):
t.forward(length / 4)
if depth > 1:
t.right(90)
squares(t, length / 2, depth - 1)
t.left(90)
t.forward(3 * length / 4)
...
An absolute value like this is to be avoided in a recursive fractal:
t.goto(-1000,-1000)
And of course, keep your pendown() calls properly matched to your penup() calls.
I am trying to fill the color in these squares:
Right now the turtle only fills the corners of theses squares, not the entire square.
Here is my code:
import turtle
import time
import random
print ("This program draws shapes based on the number you enter in a uniform pattern.")
num_str = input("Enter the side number of the shape you want to draw: ")
if num_str.isdigit():
squares = int(num_str)
angle = 180 - 180*(squares-2)/squares
turtle.up
x = 0
y = 0
turtle.setpos(x,y)
numshapes = 8
for x in range(numshapes):
turtle.color(random.random(),random.random(), random.random())
x += 5
y += 5
turtle.forward(x)
turtle.left(y)
for i in range(squares):
turtle.begin_fill()
turtle.down()
turtle.forward(40)
turtle.left(angle)
turtle.forward(40)
print (turtle.pos())
turtle.up()
turtle.end_fill()
time.sleep(11)
turtle.bye()
I've tried moving around turtle.begin_fill() and end_fill() in numerous locations with no luck… Using Python 3.2.3, thanks.
I haven't really used turtle, but it looks like this may be what you want to do. Correct me if I've assumed the wrong functionality for these calls:
turtle.begin_fill() # Begin the fill process.
turtle.down() # "Pen" down?
for i in range(squares): # For each edge of the shape
turtle.forward(40) # Move forward 40 units
turtle.left(angle) # Turn ready for the next edge
turtle.up() # Pen up
turtle.end_fill() # End fill.
You're drawing a series of triangles, using begin_fill() and end_fill() for each one. What you can probably do is move your calls to begin_fill() and end_fill() outside the inner loop, so you draw a full square and then ask for it to be filled.
Use fill
t.begin_fill()
t.color("red")
for x in range(4):
t.fd(100)
t.rt(90)
t.end_fill()
Along with moving begin_fill() and end_fill() outside the loop, as several folks have mentioned, you've other issues with your code. For example, this is a no-op:
turtle.up
I.e. it doesn't do anything. (Missing parentheses.) This test:
if num_str.isdigit():
Doesn't do much for you as there is no else clause to handle the error. (I.e. when it isn't a number, the next statement simply uses the string as a number and fails.) This calculation seems a bit too complicated:
angle = 180 - 180*(squares-2)/squares
And finally there should be a cleaner way to exit the program. Let's address all these issues:
from turtle import Screen, Turtle
from random import random
NUMBER_SHAPES = 8
print("This program draws shapes based on the number you enter in a uniform pattern.")
num_str = ""
while not num_str.isdigit():
num_str = input("Enter the side number of the shape you want to draw: ")
sides = int(num_str)
angle = 360 / sides
delta_distance = 0
delta_angle = 0
screen = Screen()
turtle = Turtle()
for x in range(NUMBER_SHAPES):
turtle.color(random(), random(), random())
turtle.penup()
delta_distance += 5
turtle.forward(delta_distance)
delta_angle += 5
turtle.left(delta_angle)
turtle.pendown()
turtle.begin_fill()
for _ in range(sides):
turtle.forward(40)
turtle.left(angle)
turtle.forward(40)
turtle.end_fill()
screen.exitonclick()