H Tree using recursion python - python

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

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

How to create a tessellation with turtles in Python

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

Turtle draw progam with user input: window vanishes. What am I doing wrong? [closed]

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 4 years ago.
Improve this question
I am trying to make a shape that requires user input for one of my variables and I am confused on how to get size1 to equal x and make my user input work. Am I doing something wrong?
import turtle
import math
def drawSquareFromCenter(turtle, x): ...
turtle.penup()
turtle.forward(-x / 2)
turtle.right(90)
turtle.forward(x / 2)
turtle.left(90)
turtle.pendown()
turtle.forward(x)
turtle.left(90)
turtle.forward(x)
turtle.left(90)
turtle.forward(x)
turtle.left(90)
turtle.forward(x)
turtle.left(90)
turtle.penup()
turtle.forward(x / 2)
turtle.left(90)
turtle.forward(x / 2)
turtle.right(90)
def main():
# Create turtle
bob = turtle.Turtle()
# Get user input
size1 = int(input('Enter size fore top square'))
size2 = size1 * 2
size3 = size1 * 3
size4 = size1 * 4
# Draw graphics
bob.forward(size4 / 2)
bob.right(90)
bob.forward(-1 * (size4 + size3 + size2 + (size1 / 2)))
drawSquareFromCenter(bob, size1)
bob.forward((size1 + size2) / 2)
drawSquareFromCenter(bob, size2)
bob.forward((size2 + size3) / 2)
drawSquareFromCenter(bob, size3)
bob.forward((size3 + size4) / 2)
drawSquareFromCenter(bob, size4)
bob.right(45)
bob.forward(math.sqrt(size4 / 2) ** 2 + (size4 / 2) ** 2)
# Press any key to exit
input()
main()
Your console input window is probably hiding behind the turtle-draw window.
Ask for size first, then do the plotting to avoid the turtle-surface hiding your console window.
When plotting:
penup + walk half the sides length in your facing direction + pendown
rotate 90, draw half side,
3 times:
rotate 90, draw a side
rotate 90, draw the missing half side
rotate 90 + walk half a sides length back into center
rotate 180 to face as when started
could be done like this:
import math
import turtle
def squareFromCurrPosAndRotationAsCenter(bob, s):
"""Starting from current position and rotation, draw a square of sidelength s.
End on same position and rotation you began with."""
# goto first side
bob.penup()
bob.forward(s/2)
bob.pendown()
# draw a half side
bob.right(90)
bob.forward(s/2)
# draw three full sides
for k in range(3):
bob.right(90)
bob.forward(s)
# draw last half side
bob.right(90)
bob.forward(s/2)
# goto back to origin
bob.penup()
bob.right(90)
bob.forward(s/2)
# turn back in original direction
bob.right(180)
def getInt(text, default):
"""Try to parse input to int, return default if not possible"""
try:
return int(input(text))
except:
return default
Main function:
def main():
# Get user input or (when error) use default
size = getInt('Enter size for top square: ', 50)
num_squares = getInt('Enter the amount of squares: ', 4)
angle = getInt('Enter increase of starting angle: ', 60)
# Create turtle
bob = turtle.Turtle()
# adjust speed based on workload
bob.speed(max(5,(num_squares * 360/angle)//10))
# outer loop changes starting angle
for startAngle in range(0,360-angle+1,angle):
bob.setheading(startAngle)
# we use a list comp to create the desired square sizes
# you could also do [size, size*2, size*3, size*4] if
# you want always 4 circles
for s in [size*(n+1) for n in range(num_squares)]:
squareFromCurrPosAndRotationAsCenter(bob, s)
turtle.mainloop()
main()

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

Drawing a checkered flag to the turtle screen

QUESTION: Implement the following pseudo-code to draw a checkered flag to the screen.
1. Ask the user for the size of the checkered flag (n).
2. Draw an n x n grid to the screen.
3. For i = 0,2,4,...,62:
4. row = i // n
5. offset = row % 2
6. col = (i % n) + offset
Please copy and paste the link see the output:
I implemented the pseudocode, but I need some help. I can able to draw the n*n grid; moreover, I am keep getting this error: NameError: name 'row' is not defined
My program:
from turtle import*
def size():
size = eval(input("Please enter the size of the checkered flag: "))
return size
def draw(n):
wn = Screen()
wn.setworldcoordinates(-1,-1,10,10)
pen = Turtle()
for i in range(0,n+1):
pen.up()
pen.goto(0,i)
pen.down()
pen.forward(n)
pen.left(90)
for i in range(0,n+1):
pen.up()
pen.goto(i,0)
pen.down()
pen.forward(n)
def findGrid(n):
for i in range(0,63):
row = i // n
offset = row % 2
col = (i % n) + offset
return row, col
def fillSquare(x,y):
pen = Turtle()
pen.hideturtle()
pen.speed(10)
pen.up()
pen.goto(x,y)
pen.fillcolor("black")
pen.begin_fill()
def main():
x = size()
y = draw(x)
row, col = findGrid(x) #I think the problem is here.
f = fillSquare(row, col)
main()
The code you posted in your question doesn't draw squares because you don't have any turtle operations after pen.begin_fill().
You can draw a filled square like so:
turtle.begin_fill()
for i in range(4):
turtle.forward(1)
turtle.right(90)
turtle.end_fill()
There's actually a mistake in the pseudocode. The offset calculation offset = row % 2 is only valid when n, the number of rows, is an even number. The pseudocode fails to calculate checkered square locations when n is odd.
To make the code work for even and odd values of n, you can evaluate the offset as follows:
offset = ~(n % 2) & (row % 2)
I have implemented these changes in the code below. I have also modified the structure of your program by defining the turtle outside the drawing functions and passing it in as an argument. This lets us set the turtle's speed and visibility settings just once instead of having to do so within each drawing function.
from turtle import*
# Ask the user for the size of the checkered flag (n).
def getSize():
size = eval(input('Please enter the size of the checkered flag: '))
return size
# Draw an n x n grid to the screen.
def drawGrid(turtle, n):
for i in range(0, n+1):
turtle.up()
turtle.goto(0, i)
turtle.down()
turtle.forward(n)
turtle.left(90)
for i in range(0, n+1):
turtle.up()
turtle.goto(i, 0)
turtle.down()
turtle.forward(n)
# Fill the square in the given row and column.
def fillSquare(turtle, row, col):
turtle.up()
turtle.goto(col, row)
turtle.begin_fill()
for i in range(4):
turtle.forward(1)
turtle.right(90)
turtle.end_fill()
def main():
# Get the user's input.
n = getSize()
# Set up the drawing coordinates.
screen = Screen()
screen.setworldcoordinates(-1, -1, 10, 10)
# Make a turtle object for use in drawing. Maximize its speed.
turtle = Turtle()
turtle.speed('fastest')
turtle.hideturtle()
# Draw the checkered flag.
drawGrid(turtle, n)
for i in range(0, n*n, 2):
row = i // n
offset = ~(n % 2) & (row % 2)
col = i % n + offset
fillSquare(turtle, row, col)
print('Hit Enter to quit.')
input()
main()
This is a situation where I believe stamping makes things simpler than drawing in Python turtle:
from turtle import Turtle, Screen
CURSOR_SIZE = 20
def getSize():
""" Ask user for the size of the checkered flag. """
return int(input('Please enter the size of the checkered flag: '))
cells = getSize()
screen = Screen()
size = min(screen.window_width() - 10, screen.window_height() - 30) / cells
offset = (cells % 2) * size/2 + size/2 # properly center odd & even cells
turtle = Turtle('square', visible=False)
turtle.shapesize(size / CURSOR_SIZE)
turtle.speed('fastest')
turtle.color('black')
turtle.penup()
for row in range(-cells // 2, cells // 2):
parity = row % 2 # properly color cells
turtle.goto(-cells // 2 * size + offset, row * size + offset)
for column in range(cells):
turtle.fillcolor(['white', 'black'][parity == column % 2])
turtle.stamp()
turtle.forward(size)
screen.exitonclick()
Stamping also makes the program faster as we're working with larger chunks of the drawing.

Categories

Resources