Python recursive turtle fractal - python

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.

Related

Drawing fractal square pattern in Turtle

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()

Turtle module in Python:

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

Turtle Graphics: Repeating Squares

I am trying to create a loop that takes an input by a user and draws however many squares but it increases the size of the squares with each loop, however 2 sides are stay connected. I'll include the graphic to better explain.
import turtle
squares = 1
while squares >= 1:
squares = int(input('How many squares would you like drawn?:'))
if squares == 0:
print("You must have at-least 1 square.")
squares = int(input('How many squares would you like drawn?:'))
else:
for count in range(squares):
turtle.forward(30)
turtle.left(90)
turtle.forward(30)
turtle.left(90)
turtle.forward(30)
turtle.left(90)
turtle.forward(30)
turtle.left(90)
turtle.done()
The input request and the drawing logic ought to be separated.
Here is one approach that returns the turtle at the start at each turn, after increasing the side length.
import turtle
num_squares = 3
t = turtle.Turtle()
t.pendown()
side = side_unit = 30
while True:
try:
num_squares = int(input('input the number of squares'))
except ValueError:
print("please enter an integer")
if num_squares > 3:
break
for sq in range(1, num_squares + 1):
t.left(90)
t.forward(side)
t.left(90)
t.forward(side)
t.left(90)
t.forward(side)
t.left(90)
side = side_unit + 3 * sq # increase the size of the side
t.goto(0,0) # return to base
turtle.done()
While waiting for #ReblochonMasque's solution to finish drawing 100 squares, there's plenty of time to implement an alternate, faster solution based on stamping.
The first thing to note is in the provided instructions it says to draw 100 squares to create the design in the figure, but that figure consists of just under 50 squares. It's also been scaled in some non integral fashion which makes it appear to have different line thicknesses.
Let's focus on the spirt of the problem rather than the example. The OP had a 1 square minimum so I've preserved that. This solution also naturally tends to center the square on the window:
from turtle import Turtle, Screen
DELTA = 3
MINIMUM = DELTA * 2
CURSOR_SIZE = 20
num_squares = -1
while num_squares < 1:
try:
num_squares = int(input('Input the number of squares: '))
except ValueError:
print("please enter an integer.")
if num_squares < 1:
print("You must have at least 1 square.")
screen = Screen()
turtle = Turtle("square", visible=False)
turtle.fillcolor("white")
for size in range(((num_squares - 1) * DELTA) + MINIMUM, MINIMUM - 1, -DELTA):
turtle.goto(turtle.xcor() + DELTA/2, turtle.ycor() - DELTA/2)
turtle.shapesize(size / CURSOR_SIZE)
turtle.stamp()
screen.exitonclick()
This is clearly not the kind of solution the OP was looking for, but maybe next time a problem like this comes up, it might be one the OP will at least consider.

How to get the right output for this turtle function?

I have a logic error for this function. I need to write a function called spikes() that draw
lines radiating from a common starting point. It takes three parameters, which are
numLines for number of lines to draw, lengthIncr for the length of the first line and
increase in length of the successive lines, and angle that goes clockwise and it is the angle between successive lines. I use the latest version of Python (3.4.2). Also, the function spides must repeatedly call the function drawLine(). I think the error is the call function for drawLine in the function spikes, but I don't know how to fix it. The output I get is a very long curve line that goes downward forever. The real output I should get is spikes. Here is the code:
#Question 14 Part a-
import turtle
s = turtle.Screen()
t = turtle.Turtle()
def drawLine(t, length):
t.pendown()
t.forward(length)
t.penup()
length = 50
drawLine(t, length)
#Question 14 Part b-
def spikes(numLines, lengthIncr, angle):
for i in range(numLines):
drawLine(t, lengthIncr * i)
t.right(angle)
print(spikes(36, 25, 5))
#Output I should get: '''
I'm not an expert on turtle, but is this what you're looking for?
import turtle
s = turtle.Screen()
t = turtle.Turtle()
def drawLine(t, length):
t.pendown()
t.forward(length)
t.penup()
def there_and_back(t, length):
drawLine(t, length)
t.penup()
t.right(180)
t.forward(length)
t.right(180)
t.pendown()
length = 50
#Question 14 Part b-
def spikes(numLines, lengthIncr, angle):
for i in range(numLines):
length = lengthIncr * i
there_and_back(t, length)
t.right(angle)
print(spikes(36, 25, 5))

How Can I Fill These Squares in Turtle - Python

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()

Categories

Resources