Change my Python Turtle code for N columns and M rows - python

I have my code ready to show 3x3 equilateral triangles, but I don't know how to change it so N amount of equilateral triangles can be shown in a column (one triangle above another one) and M amount of equilateral triangles can be shown in a row (one triangle next to another one). Any help is much appreciated!
My code is:
import turtle
ara = turtle.Turtle() #name of the turtle
ara.speed(0)
ara.pensize(10)
def pile_left(t, l, n): #first column
t = l * 3 ** 0.5 / 2
for j in range(n):
if j == 0 : ara.fillcolor('red')
if j == 1 : ara.fillcolor('orange')
if j == 2 : ara.fillcolor('green')
ara.pu()
ara.shape('turtle')
ara.begin_fill()
for i in range(3):
ara.lt(120)
ara.fd(l)
ara.end_fill()
ara.sety(ara.ycor() + t)
pile_left(ara, 60, 3)
def pile_middle(t, l, n): #second column
t = l * 3 ** 0.5 / 2
ara.goto(60,0)
for j in range(n):
if j == 0 : ara.fillcolor('purple')
if j == 1 : ara.fillcolor('yellow')
if j == 2 : ara.fillcolor('peachpuff')
ara.pu()
ara.shape('turtle')
ara.begin_fill()
for i in range(3):
ara.lt(120)
ara.fd(l)
ara.end_fill()
ara.sety(ara.ycor() + t)
pile_middle(ara, 60, 3)
def pile_right(t, l, n): #third column
t = l * 3 ** 0.5 / 2
ara.goto(120,0)
for j in range(n):
if j == 0 : ara.fillcolor('grey')
if j == 1 : ara.fillcolor('brown')
if j == 2 : ara.fillcolor('blue')
ara.pu()
ara.shape('turtle')
ara.begin_fill()
for i in range(3):
ara.lt(120)
ara.fd(l)
ara.end_fill()
ara.sety(ara.ycor() + t)
pile_right(ara, 60, 3)
turtle.mainloop()
You can run it on trinket.io/python to see who it currently does.

I have my code ready to show 3x3 equilateral triangles
No, not really. You have your code ready to show 1x3 equilateral triangles, and you simply duplicated your code three times to emulate a second dimension. Your problem is that you can't duplicate your code M times to solve this problem.
The answer in this situation is less, but smarter, code. We're going to need nested loops for N and M, and the ability to move forward by length l for each M and vertically by height t for each N:
from turtle import Screen, Turtle
COLORS = ['red', 'orange', 'green', 'purple', 'yellow', 'pink', 'grey', 'brown', 'blue']
def pile(turtle, length, columns, rows):
height = length * 3 ** 0.5 / 2
x_origin = turtle.xcor()
color = 0
for _ in range(rows):
for _ in range(columns):
turtle.color(COLORS[color % len(COLORS)])
turtle.begin_fill()
for _ in range(3):
turtle.forward(length)
turtle.left(120)
turtle.end_fill()
turtle.forward(length)
color += 1
turtle.setposition(x_origin, turtle.ycor() + height)
screen = Screen()
yertle = Turtle('turtle')
yertle.speed('fastest')
yertle.penup()
pile(yertle, 60, 4, 5)
yertle.hideturtle()
screen.exitonclick()
However, this is a perfect example where stamping would be simpler than filling. We can make the turtle itself an equilateral triangle, then move it and stamp it:
from turtle import Screen, Turtle
COLORS = ['red', 'orange', 'green', 'purple', 'yellow', 'pink', 'grey', 'brown', 'blue']
CURSOR_SIZE = 20
def pile(turtle, length, columns, rows):
turtle.shapesize(length / CURSOR_SIZE)
height = length * 3 ** 0.5 / 2
y_origin = turtle.ycor()
color = 0
for _ in range(columns):
for _ in range(rows):
turtle.color(COLORS[color % len(COLORS)])
turtle.stamp()
turtle.forward(height)
color += 1
turtle.setposition(turtle.xcor() + length, y_origin)
screen = Screen()
yertle = Turtle('triangle')
yertle.speed('fastest')
yertle.setheading(90)
yertle.penup()
pile(yertle, 60, 4, 5)
yertle.hideturtle()
screen.exitonclick()
Not only simpler, but faster too!

Related

Drawing radiating circular trapezoid pattern with Turtle

I was just wondering how to draw some trapezoids in my turtle code.
I want my output to be like this:
What my output is right now:
Here's the code I've written so far:
import turtle as trtl
num_sides = 6
side_length = 15
circumradius = side_length
trtl.pencolor((245, 176, 66))
trtl.pensize(8)
for move_turtle in range(1):
trtl.penup()
trtl.sety(-circumradius)
trtl.pendown()
trtl.circle(circumradius, steps = num_sides)
circumradius *= 2
side_length = side_length + 8
trtl.pensize(12)
for move_turtle in range(1):
trtl.pencolor((255, 83, 71))
trtl.penup()
trtl.sety(-circumradius)
trtl.pendown()
trtl.circle(circumradius, steps = num_sides)
circumradius *= 2
for move_turtle in range(1):
trtl.pencolor((247, 220, 67))
trtl.penup()
trtl.sety(-circumradius)
trtl.pendown()
trtl.circle(circumradius, steps = num_sides)
circumradius *= 2
trtl.hideturtle()
What techniques can I use to get the desired output?
The approach I often take when given patterns like this is to think about a slight-of-hand trick that can produce the result with less trouble than figuring out how to draw something potentially fussy like a trapezoid.
In this case, if you remove the white spaces, we have a "pie"-shaped circle of different solid colors radiating from the middle. If we can manage to solve that simpler problem, then we can draw white lines on top and wind up with the desired result.
The only trig we need is the angle-to-coordinates formula:
x = cos(radians(angle)) * radius
y = sin(radians(angle)) * radius
Using this, we can iterate over n points (with some rotational offset) along the circumference of a circle with a loop and fill in the colors to make a pie:
import math
import turtle
def draw_pie(t, r, n, colors, rot_offset=0.5):
for i in range(n + 1):
a = 360 / n * (i + rot_offset)
t.color(colors[i%len(colors)])
t.begin_fill()
t.goto(0, 0)
x = math.cos(math.radians(a)) * r
y = math.sin(math.radians(a)) * r
t.goto(x, y)
t.end_fill()
if __name__ == "__main__":
t = turtle.Turtle()
t.screen.setup(540, 540)
t.penup()
t.speed("fastest")
sides = 6
draw_pie(t, 450, sides, ["#dd2", "orange", "#d02"])
t.ht()
turtle.exitonclick()
Next, we need to draw a bunch of thick white lines with square corners. Unfortunately, turtle draws rounded edges by default which aren't suitable for our needs. There are many tricks for making square edges (stamping is a reasonable method). The approach I used here was writing a custom rectangle drawing function that takes advantage of turtle.distance and turtle.setheading(turtle.towards(x, y)) which lets me point to the next point along the circumference of the circle. The rest is just loops to compute angles and picking the right values.
Here's the code:
import math
import turtle
def draw_rect(t, x, y, xx, yy, width):
t.goto(x, y)
t.setheading(t.towards(xx, yy))
t.begin_fill()
for d in [t.distance(xx, yy), width] * 2:
t.forward(d)
t.left(90)
t.end_fill()
def draw_pie(t, r, n, colors, rot_offset=0.5):
for i in range(n + 1):
a = 360 / n * (i + rot_offset)
t.color(colors[i%len(colors)])
t.begin_fill()
t.goto(0, 0)
x = math.cos(math.radians(a)) * r
y = math.sin(math.radians(a)) * r
t.goto(x, y)
t.end_fill()
def draw_reg_polygon(t, r, n, thickness, rot_offset=0.5):
for i in range(n):
a = 360 / n * (i + rot_offset)
x = math.cos(math.radians(a)) * r
y = math.sin(math.radians(a)) * r
a = 360 / n * (1 + i + rot_offset)
xx = math.cos(math.radians(a)) * r
yy = math.sin(math.radians(a)) * r
draw_rect(t, x, y, xx, yy, thickness)
if __name__ == "__main__":
t = turtle.Turtle()
t.screen.setup(540, 540)
t.penup()
t.speed("fastest")
sides = 6
draw_pie(t, 450, sides, ["#dd2", "orange", "#d02"])
t.color("white")
for r in range(50, 500, 100):
draw_reg_polygon(t, r, sides, 45)
t.ht()
turtle.exitonclick()

How to add colours to different areas

So I created a recurring pattern using two different designs. The problem now is making the colours, so I have to ask the user to pick 3 different colours and use them to make certain areas of the designs that colour. For example what I mean is, if I were to choose the 5x5 patch layout then the first 2 boxes of patterns across and below should be one colour (so that's four boxes) and so on.
EDIT: to clear up the confusion.
So if you look at the 500x500 one. type '5' when it asks for what patch size you want.
you should see two different pattern designs.
all I want is the x = 0 to x = 200 and y = 0 to y = 200 to be blue colour. Meaning that everything in that area (by area, I mean all the pattern designs that are in there) should be a blue colour. The same colour should be used for x = 300 to x = 500 and y = 300 to y = 500.
the x = 300 to x = 500 and y = 0 to y = 200 should be red colour and the x = 0 to x = 200 and y = 300 to y = 500 should also be red.
and all that is left is the '+' part in the middle which should have the third colour, green.
https://prntscr.com/m48xxd this is what I mean by the colours. so the top left and bottom right are the same colours. the top right and bottom left are te same colours and the '+' is another colour.
7.https://prntscr.com/m48xzm here is the 7x7 version
I just put colours, for now, to make it easier to look at.
I have already tried doing the 'getX' and 'getY' but I can't seem to get it right.
from graphics import *
def main():
global patchWorkSize
patchWorkSize = int(input("What patchwork size would you like?"))
if patchWorkSize == 5:
patchWork5()
elif patchWorkSize == 7:
patchWork7()
elif patchWorkSize == 9:
patchWork9()
else:
print('Only patchwork sizes 5, 7 and 9 are avaliable')
def patchWork5():
layout()
for y in range(0,500,100):
for x in range(0,500,200):
for l1 in range(0,100,20):
line = Line(Point(l1+x,0+y), Point(100+x,100-l1+y))
line.draw(win)
for l2 in range(100,0,-20):
line3 = Line(Point(l2+x,100+y), Point(0+x,100-l2+y))
line3.draw(win)
for l3 in range(100,0,-20):
line2 = Line(Point(100+x,0+l3+y), Point(0+l3+x,100+y))
line2.setFill('red')
line2.draw(win)
for l4 in range(0,100,20):
line4 = Line(Point(0+x,100-l4+y), Point(100-l4+x,0+y))
line4.setFill('red')
line4.draw(win)
for e in range(0,500,100):
for t in range(100,500,200):
for o in range(0,500,10):
for c in range(5,100,10):
circle1 = Circle(Point(c+t,5+o+e), 5)
circle1.setFill('blue')
circle1.draw(win)
def patchWork7():
layout()
for y in range(0,700,100):
for x in range(0,700,200):
for l1 in range(0,100,20):
line = Line(Point(l1+x,0+y), Point(100+x,100-l1+y))
line.draw(win)
for l2 in range(100,0,-20):
line3 = Line(Point(l2+x,100+y), Point(0+x,100-l2+y))
line3.draw(win)
for l3 in range(100,0,-20):
line2 = Line(Point(100+x,0+l3+y), Point(0+l3+x,100+y))
line2.setFill('red')
line2.draw(win)
for l4 in range(0,100,20):
line4 = Line(Point(0+x,100-l4+y), Point(100-l4+x,0+y))
line4.setFill('red')
line4.draw(win)
for e in range(0,700,100):
for t in range(100,700,200):
for o in range(0,700,10):
for c in range(5,100,10):
circle1 = Circle(Point(c+t,5+o+e), 5)
circle1.setFill('blue')
circle1.draw(win)
def patchWork9():
layout()
for y in range(0,900,100):
for x in range(0,900,200):
for l1 in range(0,100,20):
line = Line(Point(l1+x,0+y), Point(100+x,100-l1+y))
line.draw(win)
for l2 in range(100,0,-20):
line3 = Line(Point(l2+x,100+y), Point(0+x,100-l2+y))
line3.draw(win)
for l3 in range(100,0,-20):
line2 = Line(Point(100+x,0+l3+y), Point(0+l3+x,100+y))
line2.setFill('red')
line2.draw(win)
for l4 in range(0,100,20):
line4 = Line(Point(0+x,100-l4+y), Point(100-l4+x,0+y))
line4.setFill('red')
line4.draw(win)
for e in range(0,900,100):
for t in range(100,900,200):
for o in range(0,900,10):
for c in range(5,100,10):
circle1 = Circle(Point(c+t,5+o+e), 5)
circle1.setFill('blue')
circle1.draw(win)
def layout():
global win
win = GraphWin('Patchwork',patchWorkSize*100, patchWorkSize*100)
for i in range(0, patchWorkSize*100,100):
line = Line(Point(i,0), Point(i, patchWorkSize*100))
line2 = Line(Point(0,i), Point(patchWorkSize*100, i))
line.draw(win)
line2.draw(win)
main()
The key is to paramertize everything into cubes of a convenient size, and then turn the filling code into subroutines that can be called to fill those cubes. Below is a rework of your code along these lines that can handle any odd number 3 or greater as an input:
from graphics import *
UNIT = 100
def patchWork(win, size):
blocks = size // 2
def hatch_box(x, y):
for n in range(0, UNIT, UNIT//5):
line = Line(Point(n + x * UNIT, y * UNIT), Point((x + 1) * UNIT, UNIT - n + y * UNIT))
line.draw(win)
for n in range(UNIT, 0, -UNIT//5):
line = Line(Point(n + x * UNIT, (y + 1) * UNIT), Point(x * UNIT, UNIT - n + y * UNIT))
line.draw(win)
for n in range(UNIT, 0, -UNIT//5):
line = Line(Point((x + 1) * UNIT, n + y * UNIT), Point(n + x * UNIT, (y + 1) * UNIT))
line.setFill('red')
line.draw(win)
for n in range(0, UNIT, UNIT//5):
line = Line(Point(x * UNIT, UNIT - n + y * UNIT), Point(UNIT - n + x * UNIT, y * UNIT))
line.setFill('red')
line.draw(win)
for y in range(blocks):
for x in range(blocks):
hatch_box(x, y)
for y in range(blocks + 1, 2 * blocks + 1):
for x in range(blocks + 1, 2 * blocks + 1):
hatch_box(x, y)
def draw_circles(x, y):
for o in range(0, UNIT, UNIT // 10):
for c in range(0, UNIT, UNIT // 10):
circle = Circle(Point(c + UNIT // 20 + x * UNIT, o + UNIT // 20 + y * UNIT), UNIT // 20)
circle.setFill('blue')
circle.draw(win)
for y in range(blocks):
for x in range(blocks + 1, 2 * blocks + 1):
draw_circles(x, y)
draw_circles(y, x)
def draw_cube(x, y):
cube = Rectangle(Point(x * UNIT, y * UNIT), Point((x + 1) * UNIT, (y + 1) * UNIT))
cube.setFill('yellow')
cube.draw(win)
x = blocks
for y in range(0, 2 * blocks + 1):
draw_cube(x, y)
draw_cube(y, x)
def layout(size):
win = GraphWin('Patchwork', size * UNIT, size * UNIT)
for i in range(0, size * UNIT, UNIT):
Line(Point(i, 0), Point(i, size * UNIT)).draw(win)
Line(Point(0, i), Point(size * UNIT, i)).draw(win)
return win
def main():
patchWorkSize = int(input("What patchwork size would you like? "))
if patchWorkSize % 2 == 1 and patchWorkSize > 2:
win = layout(patchWorkSize)
patchWork(win, patchWorkSize)
win.getMouse() # pause for click in window
win.close()
else:
print('Only odd sizes 3 or greater are available')
main()
You should be able to change UNIT, within reason.
I'm not going to write everything for you, but the code below shows how to choose the color for each area based on its position within the patchwork grid (i and j). The color is determined in color_func().
Hopefully this will be enough for you to figure out how to apply the relatively simple coding pattern shown to draw the desired graphics.
Hint: Compute the coordinates of each graphics element based on (or relative to) these same position values (i.e. don't write a separate function for every possible patchwork size).
This code still seems overly repetitive to me, and could probably be made more concise, but I'll leave that to you, too... ;¬)
def main():
# size = int(input("What patchwork size would you like?"))
# Hardcoded for testing.
#
# if size % 2 == 0:
# raise RuntimeError('patchwork size must be odd')
patch_work(5)
print()
patch_work(7)
def patch_work(n):
colors = '0', '1', '2'
mid = n // 2
# Call color_func() for every possible position in patchwork and
# prints the results in rows.
for i in range(n):
row = []
for j in range(n):
row.append(color_func(n, i, j, colors))
print(''.join(row))
def color_func(n, i, j, colors):
mid = n // 2
if i == mid:
index = 2
elif i < mid:
if j < mid:
index = 0
elif j == mid:
index = 2
elif j > mid:
index = 1
elif i > mid:
if j < mid:
index = 1
elif j == mid:
index = 2
elif j > mid:
index = 0
return colors[index]
if __name__ == '__main__':
main()
Output:
00211
00211
22222
11200
11200
0002111
0002111
0002111
2222222
1112000
1112000
1112000

Turtle Gradient Color (review code)

I am trying to use Turtle to print 30 hexagons that are spiralling and have a gradient color change from red to black.
I am multiplying my for loop i in order to change the set values in (r, b, g) so, at some point, it will exceed r=255. I include an if statement to have it not exceed this, but it's giving me the error:
File "<ipython-input-4-35d45ac44fdd>", line 20
if r > '255'
^
SyntaxError: invalid syntax
What is causing this error?
FYI I am using Anaconda and a Jupyter notebook.
Here is my code:
import turtle
def draw_hexagon (t, size):
n=6
angle= 360/n
for i in range(n):
t.forward(size)
t.left(angle)
turtle.colormode(255)
mega=turtle.Turtle()
mega.speed(1000)
leng = 100
for i in range(30):
r = 5+(i*10)
g = 0
b = 0
color = (r, b, g)
if r > 255
print color(r,b,g)
mega.fillcolor(color)
mega.begin_fill()
draw_hexagon(mega, leng)
mega.end_fill()
leng = leng + 5
mega.left(5)
turtle.exitonclick()
My advice is to not use the if statement to get around the error but rather fix your math to avoid it in the first place. Plus some code cleanup:
from turtle import Turtle, Screen
MIN_COLOR = 5
MAX_COLOR = 255
COUNT = 30
ANGLE = 5
STARTING_LENGTH = 100
LENGTH_INCREMENT = 5
N = 6
def draw_polygon(turtle, size):
angle = 360 / N
for _ in range(N):
turtle.forward(size)
turtle.left(angle)
screen = Screen()
screen.colormode(255)
mega = Turtle()
mega.speed('fastest')
length = STARTING_LENGTH
for r in range(COUNT):
red = round(r * ((MAX_COLOR - MIN_COLOR) / (COUNT - 1))) + MIN_COLOR
color = (red, 0, 0)
mega.fillcolor(color)
mega.begin_fill()
draw_polygon(mega, length)
mega.end_fill()
length += LENGTH_INCREMENT
mega.left(ANGLE)
mega.hideturtle()
screen.exitonclick()

Draw Checkerboard on Python

I want to draw a checkerboard on Python, but I only get one black square.
Can you help me fix this program?
import turtle
def filled_square(size, color, x, y):
turtle.setpos(x, y)
turtle.color(color)
turtle.begin_fill()
for i in range(4):
angle = 90
turtle.fd(size)
turtle.lt(angle)
turtle.end_fill()
turtle.up()
import sys
n = int(sys.argv[1])
s = int(sys.argv[2])
square_size = s//n
y=0
for i in range(n):
x = 0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
x+=square_size
turtle.down()
turtle.done()
y=0
for i in range(n):
x = 0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
x+=square_size
Couple problems here.
There's not much point in increasing the value of x when you reset it right back to zero in the next iteration, so the initial assignment should be above the for loop.
you never update the value of y.
x = 0
for i in range(n):
y=0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
y+=square_size
x+=square_size
Now you should get the checkerboard shape you want.
Alternate solution: you can avoid the problem of bookkeeping the values of x and y by not having those values at all. You can derive the coordinates of the squares straight from i and j.
for i in range(n):
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", i*square_size, j*square_size)
else:
filled_square(square_size, "black", i*square_size, j*square_size)
It might also be nice to consolidate the common logic in your if and else blocks, and only differentiate the values that actually change (namely, the color)
for i in range(n):
for j in range(n):
if (i+j)%2==0:
color = "red"
else:
color = "black"
filled_square(square_size, color, i*square_size, j*square_size)
You need to increment both x and y. Also note that x should be incremented in the inner loop. Here is the working code,
import turtle
def filled_square(size, color, x, y):
turtle.setpos(x, y)
turtle.color(color)
turtle.begin_fill()
for i in range(4):
angle = 90
turtle.fd(size)
turtle.lt(angle)
turtle.end_fill()
turtle.up()
import sys
n = int(sys.argv[1])
s = int(sys.argv[2])
square_size = s//n
y=0
for i in range(n):
x = 0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
x+=square_size
y+=square_size
turtle.down()
turtle.done()
I recommend using functional programming like this for board/game work. It'll make everything easier to maintain and make implementing new features easier.
import turtle
def filled_square(size, color, x, y):
turtle.up()
turtle.setpos(x, y)
turtle.color(color)
turtle.begin_fill()
for i in range(4):
angle = 90
turtle.fd(size)
turtle.lt(angle)
turtle.end_fill()
def board(length, size, x_pos=0, y_pos=0):
for y in range(length):
for x in range(length):
if (x+y)%2==0:
filled_square(
size, "red", (x * square_size) - x_pos, (y * square_size) - y_pos)
else:
filled_square(
size, "black", (x * square_size) - x_pos, (y * square_size) - y_pos)
turtle.done()
Keyword arguments are great too. If you decided you wanted to add more colors, it is as easy as adding an two parameters,
def board(length, size, x_pos=0, y_pos=0, color1="red", color2="black"):
for y in range(length):
for x in range(length):
if (x+y)%2==0:
filled_square(
size, color1, (x * square_size) - x_pos, (y * square_size) - y_pos)
else:
filled_square(
size, color2, (x * square_size) - x_pos, (y * square_size) - y_pos)

How can I fill each petal separately using begin_fill()?

I have the following code that generates a petal pattern for a flower I'm trying to build. However, the problem is the fill part.
What should happen is each petal to be filled individually:
Instead, what happens is this:
import turtle
import math
wn = turtle.Screen()
wn.bgcolor("white")
def draw_leaf(turtle, side, theta = 0):
angle = 2
turtle.color("#67bd3c")
for x in range(-180,180):
y = math.sin(math.radians(angle))
angle += 1
y = y * side
x_axis = (x % 180) * math.cos(math.radians(theta)) + y * math.sin(math.radians(theta))
y_axis = (x % 180) * (-1 * (math.sin(math.radians(theta)))) + y * math.cos(math.radians(theta))
turtle.goto(-1 * x_axis, -1 * y_axis)
return
def draw_flower(turtle, petals):
for x in range(petals):
theta = 180/(petals - 1)
turtle.pendown()
turtle.begin_fill()
draw_leaf(turtle, 35, theta * x)
turtle.end_fill()
turtle.penup()
turtle.left(theta)
return
draw_flower(turtle,4)
wn.exitonclick()
It looks like each draw_leaf call begins when the turtle is at the far end of the leaf that it just previously drew. So the polygon that is filled during the current draw_leaf includes that end point. This is more apparent if you draw each leaf with a different color.
One possible solution is to goto the center of the flower after your penup, before you draw the next leaf.
def draw_flower(turtle, petals):
start = turtle.pos()
for x in range(petals):
theta = 180/(petals - 1)
turtle.pendown()
turtle.begin_fill()
draw_leaf(turtle, 35, theta * x)
turtle.end_fill()
turtle.penup()
turtle.goto(*start)
turtle.left(theta)
return

Categories