Turtle begin_fill and end_fill with multiple shapes and loops - python

I need help capping off my for loops. (They can go on forever, yet I need them to be in range of 12 and 10.) My thinking is instead of this
for i in range(sides):
to do:
for sides in range(12):
#and for repeat do
for repeat in range(10):
This, in theory, should stop the possibly infinite process of looping, right? The second problem is my end_fill() doesn't fill in each shape with a different color. The outline and inside should be the same, and on a new shape, should be a random color (using randint function).
from turtle import *
import math
import random
#Continue being lazy and not creating turtles, also using a .cfg file to make the window.
colormode(255)
sides = int(input("Enter a number of sides (1-12): "))
repeat = int(input("How many times to repeat? (1-10): "))
#Turtle stuff.
penup()
goto(0,0)
size = 100
angle1 = 360 / sides
angle2 = 360 / repeat
#Here is where I am having issues, I am not sure how much to turn the turtle by do to the needed input
#Also I need to cap this off to only 12 sides and 10 repeats
#As it stands it can go for infinitum.
begin_fill()
for count in range(repeat):
for i in range(sides):
pendown() #Puts the pen down.
pensize(5) #Sets the pen to something more visible
colors1 = random.randint(0, 255) #Random red
colors2 = random.randint(0, 255) #Random blue
colors3 = random.randint(0, 255) #Random green
forward(size) #Goes forward 10 pixels
left(angle1)
penup()
#Goes left 360 / sides degrees. So 360 / 10 = 36 degrees.
pencolor(colors1, colors2, colors3) #Sets pencolor to a random RGB code
fillcolor(colors1, colors2, colors3) #Sets fillcolor to a random RGB code.
left(angle2) #Move left 90 degrees afterwards.
forward(5) #Moves forward 5 times.
end_fill() #Fills in the shape.
Code also available here: https://gist.github.com/anonymous/3984f7a1a04e9957ea55

Your first problem can be solved using Python 3 turtle's graphic numinput() instead of console input():
numinput(title, prompt, default=None, minval=None, maxval=None)
This will limit the range of the user's input. Your second issue is due to having begin_fill and end_fill at two different indentation levels. Usually, they should be at the same level. Here's a rework of your code with the above changes:
from turtle import Screen, Turtle
import random
screen = Screen()
screen.colormode(255)
sides = screen.numinput("Color Polygons", "Enter a number of sides (1-12)", default=6, minval=1, maxval=12)
if sides is None: # user cancelled operation
sides = 6
repeat = screen.numinput("Color Polygons", "How many times to repeat? (1-10)", default=5, minval=1, maxval=10)
if repeat is None:
repeat = 5
turtle = Turtle()
turtle.speed('fastest')
turtle.pensize(5)
turtle.penup()
size = 100
angle1 = 360 / sides
angle2 = 360 / repeat
for count in range(int(repeat)):
red = random.randint(0, 255)
green = random.randint(0, 255)
blue = random.randint(0, 255)
turtle.color(red, green, blue)
turtle.begin_fill()
for i in range(int(sides)):
turtle.pendown()
turtle.forward(size)
turtle.left(angle1)
turtle.penup()
turtle.end_fill()
turtle.left(angle2)
turtle.forward(5)
turtle.hideturtle()
screen.exitonclick()

Related

How to create multiple 50 pence coins

How can I create separate coins in a page that are not overlapping or not touching each other. The code below shows overlapping coins if the number is greater than 2.
import turtle
tegan = turtle.Turtle()
turtle.fillcolor('grey')
turtle.begin_fill()
numbers = int(input("How many 50 pence coins you have: "))
print(numbers)
length = 100
degrees = 51.42857
angle = 40
def draw_heptagon(tegan, length, numbers, angle):
for i in range(numbers):
for x in range(7):
turtle.forward(length)
turtle.left(degrees)
turtle.right(angle)
draw_heptagon(tegan, length, numbers, angle)
turtle.end_fill()
turtle.done()
Here's an approximate approach that you can refine. We'll keep track of the centers of the randomly placed heptagons we draw. We'll treat them as circles for purposes of drawing and checking the distances between them:
from turtle import Screen, Turtle
from random import randint
RADIUS = 100
ANGLE = 40
number = int(input("How many 50 pence coins you have: "))
def draw_heptagons(t, number):
coins = []
for _ in range(number):
while True:
x = randint(RADIUS - width/2, width/2 - RADIUS)
y = randint(RADIUS - height/2, height/2 - RADIUS)
t.goto(x, y)
t.right(ANGLE)
if coins and any(t.distance(position) < RADIUS * 2 for position in coins):
continue
break
t.right(90)
t.forward(RADIUS) # draw heptagon centered at x, y
t.left(90)
turtle.begin_fill()
t.circle(RADIUS, steps=7)
turtle.end_fill()
coins.append((x, y))
screen = Screen()
width, height = screen.window_width(), screen.window_height()
turtle = Turtle()
turtle.speed('fastest') # because I have no patience
turtle.penup()
draw_heptagons(turtle, number)
turtle.hideturtle()
screen.exitonclick()
This does what you describe but the heptagons could actually be closer (fit more of them in the window) than circles, so you need to modify the test, and what information you store in positions, if you want to pack them tighter:

Drawing polygon with turtle graphics

I am trying to draw a polygon in python using the turtle library.
I want to set the size to fit the screen size but I don't know how.
For now I tried two ways and it does work but I want that no matter the size the polygon fits in the screen. For example if I put size = 50 and n = 100 it will not show in the screen.
from turtle import *
def main():
sides = int(input('Enter the number of sides of a polygon: '))
angle = 360/sides
size = 500/sides
# =============================================================================
# if sides <= 20:
# size = 50
# else:
# size= 10
# =============================================================================
for i in range(sides):
forward(size)
left(angle)
i += 1
hideturtle()
done()
main()
If I understand correctly, you are asking how to choose a size (side length) such that the shape fills but does not exceed the screen. First, we need to check the height or width of the screen (whichever is smaller):
min_dimension = min([tr.window_width(), tr.window_height()]) - 20
(I'm not sure why it is necessary to reduce the dimension by about 20 pixels, but if I don't do this then the shape is drawn slightly outside the visible area.)
The circumradius is the radius of the circle that passes through all the points of the polygon and the apothem is the distance from the center to the midpoint of a side. For a polygon with odd numbers of sides to just fit the screen, the circumradius needs to be half the height of the screen; for a polygon with even numbers of sides to just fit the screen, the apothem + circumradius should equal the height of the screen.
Reversing the formulae for the circumradius and apothem, we can determine the maximum side length given the height. Also note that to fill the screen we should start drawing near the bottom of the screen rather than in the center.
def main():
sides = int(input('Enter the number of sides of a polygon: '))
angle = 360/sides
min_dimension = min([tr.window_width(), tr.window_height()]) - 20
# Determine max side length
a = math.pi / sides
if sides % 2: # odd number of sides
size = min_dimension * 2 * math.sin(a) / (1 + math.cos(a))
else: # even number
size = min_dimension * math.tan(a)
# Start near the bottom of the screen
penup()
right(90)
forward(min_dimension / 2)
right(90)
forward(size / 2)
left(180)
pendown()
# Draw polygon
for _ in range(sides):
forward(size)
left(angle)
done()

Python turtle color changing and fill

This code draws a shape when the user inputs the number of squares to draw and the size of those squares. I want the color to change for every square that is drawn, and for it to get filled in. But the code gets stuck:
import turtle
t = turtle.Turtle()
size = int(input("How long do you want the side lengths to be?"))
number = int(input("How many squares do you want in the image?"))
red = 40.0
blue = 30.0
green = 10.0
def square (size):
count = 0
while count < 4:
t.forward(size)
t.right(90)
count = count + 1
def drawing(number):
times = 0
while times < number:
t.pencolor(red, blue, green)
t.fillcolor(red, blue, green)
t.begin_fill()
square(size)
t.right(360/number)
if t.filling():
t.pensize(5)
else:
t.pensize(3)
t.color()
(red + 1, blue + 1, green + 1)
times = times + 1
drawing(number)
There are several problems with your code -- the primary one is you're using the wrong color model. By default, turtle colors are specified as floating point values between 0.0 and 1.0. However, you want to use values like those in your code, we can switch this via colormode(255) which allows values from 0 to 255.
Next, a begin_fill() has to have a matching end_fill() which you are missing. Colors are specified in the order (red, green, blue), not (red, blue, green). Also, if you set both pencolor() and fillcolor() to the same color, you can simply use the one call color().
Finally, these two statements don't do anything:
t.color()
(red + 1, blue + 1, green + 1)
as far as your code is concerned. You need to rethink them. Below is my rework of your code which addresses the above issues and some other details:
from turtle import Screen, Turtle
def square(size):
count = 0
if turtle.filling():
turtle.pensize(5)
else:
turtle.pensize(3)
while count < 4:
turtle.forward(size)
turtle.right(90)
count += 1
def drawing(number):
red = 30
green = 10
blue = 20
times = 0
while times < number:
turtle.color(red % 255, green % 255, blue % 255)
turtle.begin_fill()
square(size)
turtle.end_fill()
turtle.right(360 / number)
red, green, blue = red + 20, green + 30, blue + 10
times += 1
size = int(input("How long do you want the side lengths to be? "))
number = int(input("How many squares do you want in the image? "))
screen = Screen()
screen.colormode(255)
turtle = Turtle()
turtle.speed('fastest') # because I have no patience
drawing(number)
screen.exitonclick()

Writing a function that asks a user to input a color and then fills a shape with that color

My task is to write a function, drawCircle(radius,fillColor), that asks a user for the specific radius of the circle and which color they'd like the circle to be filled.
I have the circle-drawing down, but I'm struggling with getting the circle to fill with the user-defined color. Any help would be greatly appreciated.
import turtle
def drawCircle(radius, fillColor):
x=360/300 #This gives the angle
r=radius#This is the radius of the circle.
c=fillColor
c=str("")
z=1 #Placeholder for the while loop.
win=turtle.Screen()
tom=turtle.Turtle()
fillColor=tom.color()
tom.begin_fill()
while (z<=300):
tom.forward(r)
tom.right(x)
tom.forward(r)
z=z+1
win.exitonclick()
tom.end_fill()
This is my function call: drawCircle(1,"red")
There are several problems with your code:
You call win.exitonclick before tom.end_fill, so programm exits before filling (as it happens on end_fill)
You do "fillColor=tom.color()" with gets you current color. Instead use "tom.fillcolor(fillColor)"
Unnecessary copying of variables radius->r and fillColor->c
This is python. Use for whenever possible. Instead of counting using z use:
for _ in range(300):
My final code:
import turtle
def drawCircle(radius, fillColor):
x = 360/300 # This gives the angle
win = turtle.Screen()
tom = turtle.Turtle()
tom.fillcolor(fillColor)
tom.begin_fill()
for _ in range(300):
tom.forward(radius)
tom.right(x)
tom.forward(radius)
tom.end_fill()
win.exitonclick()
drawCircle(1, "red")
I have the circle-drawing down
Before addressing your fill issue, I'd argue that your premise isn't true, you don't have circle-drawing down. As #Mysak0CZ shows, your circle of radius 1 is huge -- 1 what? You're drawing a circle but have no real control over its size.
As a professional turtle wrangler, I'd go about the problem as follows. Not only your angle needs to be divided by the number of segments you plan to draw, but you need to compute a circumference based on the requested radius and chop that up as well. I do so below and include a call to turtle's own .circle() method to show that we're in the right ballpark. And I fix your minor fill issue:
import math
from turtle import Turtle, Screen # force object-oriented turtles
SEGMENTS = 60 # how many lines make up the circle
def drawCircle(radius, fillColor):
distance = math.pi * radius * 2 / SEGMENTS # circumference / SEGMENTS
angle = 360 / SEGMENTS
turtle.fillcolor(fillColor)
turtle.begin_fill()
for _ in range(SEGMENTS):
turtle.forward(distance)
turtle.left(angle) # left for .circle() compatibility
turtle.end_fill()
screen = Screen()
turtle = Turtle()
drawCircle(100, 'red')
turtle.circle(100) # for comparison
screen.exitonclick()
Here is my code for a pink circle if you are going through the same Python learning resource. I think the original code was missing an argument.
import turtle
def drawPolygon(t, sideLength, numSides):
t.goto(0, 0)
turnAngle = 360 / numSides
for i in range(numSides):
t.forward(sideLength)
t.right(turnAngle)
def drawCircle(anyTurtle, radius):
circumference = 2 * 3.1415 * radius
sideLength = circumference / 360
drawPolygon(anyTurtle, sideLength, 360)
def drawFilledCircle(anyTurtle, radius, color):
anyTurtle.fillcolor(color)
anyTurtle.begin_fill()
drawCircle(anyTurtle, radius)
anyTurtle.end_fill()
anyTurtle.hideturtle()
wn = turtle.Screen()
wheel = turtle.Turtle()
drawFilledCircle(wheel, 80, "pink")
wn.exitonclick()

turtle drawing automatic centering

I'm looking for best way to automatically find starting position for new turtle drawing so that it would be centered in graphics window regardless of its size and shape.
So far I've developed a function that checks with each drawn element turtle position to find extreme values for left, right, top and bottom and that way I find picture size and can use it to adjust starting position before releasing my code. This is example of simple shape drawing with my picture size detection added:
from turtle import *
Lt=0
Rt=0
Top=0
Bottom=0
def chkPosition():
global Lt
global Rt
global Top
global Bottom
pos = position()
if(Lt>pos[0]):
Lt = pos[0]
if(Rt<pos[0]):
Rt= pos[0]
if(Top<pos[1]):
Top = pos[1]
if(Bottom>pos[1]):
Bottom = pos[1]
def drawShape(len,angles):
for i in range(angles):
chkPosition()
forward(len)
left(360/angles)
drawShape(80,12)
print(Lt,Rt,Top,Bottom)
print(Rt-Lt,Top-Bottom)
This method does work however it seems very clumsy to me so I would like to ask more experiences turtle programmers is there a better way to find starting position for turtle drawings to make them centered?
Regards
There is no universal method to center every shape (before you draw it and find all your max, min points).
For your shape ("almost" circle) you can calculate start point using geometry.
alpha + alpha + 360/repeat = 180
so
alpha = (180 - 360/repeat)/2
but I need 180-alpha to move right (and later to move left)
beta = 180 - aplha = 180 - (180 - 360/repeat)/2
Now width
cos(alpha) = (lengt/2) / width
so
width = (lengt/2) / cos(alpha)
Because Python use radians in cos() so I need
width = (length/2) / math.cos(math.radians(alpha))
Now I have beta and width so I can move start point and shape will be centered.
from turtle import *
import math
# --- functions ---
def draw_shape(length, repeat):
angle = 360/repeat
# move start point
alpha = (180-angle)/2
beta = 180 - alpha
width = (length/2) / math.cos(math.radians(alpha))
#color('red')
penup()
right(beta)
forward(width)
left(beta)
pendown()
#color('black')
# draw "almost" circle
for i in range(repeat):
forward(length)
left(angle)
# --- main ---
draw_shape(80, 12)
penup()
goto(0,0)
pendown()
draw_shape(50, 36)
penup()
goto(0,0)
pendown()
draw_shape(70, 5)
penup()
goto(0,0)
pendown()
exitonclick()
I left red width on image.
I admire #furas' explanation and code, but I avoid math. To illustrate that there's always another way to go about a problem here's a math-free solution that produces the same concentric polygons:
from turtle import Turtle, Screen
def draw_shape(turtle, radius, sides):
# move start point
turtle.penup()
turtle.sety(-radius)
turtle.pendown()
# draw "almost" circle
turtle.circle(radius, steps=sides)
turtle = Turtle()
shapes = [(155, 12), (275, 36), (50, 5)]
for shape in shapes:
draw_shape(turtle, *shape)
turtle.penup()
turtle.home()
turtle.pendown()
screen = Screen()
screen.exitonclick()

Categories

Resources