How to Make a Smiley Face in Turtle

python- draw a angry and surprise face

For an angry face we can create the mouth by just inverting the values for the smile part in your current code:

smiles.penup()
smiles.goto(0,50)
smiles.pendown()
smiles.circle(-100,90)

smiles.penup()
smiles.setheading(180)
smiles.goto(0,50)
smiles.pendown()
smiles.circle(100,90)

Result:

enter image description here

To make it look more like an classical angry face emoji such as the one shown below:

enter image description here

We need to add angry eyebrows and move the eyes down:

import turtle

smiles = turtle.Turtle()

smiles.penup()
smiles.goto(-105,155)
smiles.pendown()
smiles.goto(-45,115)

smiles.penup()
smiles.goto(-75,75)
smiles.pendown()
smiles.circle(10)

smiles.penup()
smiles.goto(105,155)
smiles.pendown()
smiles.goto(45,115)

smiles.penup()
smiles.goto(75,75)
smiles.pendown()
smiles.circle(10)

smiles.penup()
smiles.goto(0,25)
smiles.pendown()
smiles.circle(-100,80)

smiles.penup()
smiles.setheading(180)
smiles.goto(0,25)
smiles.pendown()
smiles.circle(100,80)

turtle.done()

Final result:

enter image description here

Improving this angry face to match the emoji more and making a surprise face would follow a similar process. Hint: make a full circle for the mouth of the surprise face.

The key to turtle graphics is to understand that first value corresponds to the x-coordinate and the second value corresponds to the y-coordinate. Once you understand that you can draw anything.

How to draw smily (arc) using python turtle

The turtle module does not provide advanced methods to drow arcs of circles or parabolas, however it isn't hard to come up with the right equations.

A circle C with origin at (x0, y0) and radius r is described by the equation:

(x-x0)^2 + (y-y0)^2 = r^2

We can expand this to get:

x^2 -2x·x0 + x0^2 + y^2 -2y·y0 + y0^2 - r^2 = 0

Now we can take for example the y as variable and obtain the second degree equation:

y^2 -2y0·y +(x^2-2x0·x+x0^2+y0^2-r^2) = 0

Let d = x^2-2x0·x+x0^2+y0^2-r^2. We can solve this using the usual formula:

y1 = (2y0 + sqrt(4y0^2 - 4d))/2 = y0 + sqrt(y0^2 - d)
y2 = (2y0 - sqrt(4y0^2 - 4d))/2 = y0 - sqrt(y0^2 - d)

So now you can write down a function that, given the coordinates of the center of the circle and the radius, and the value for x it returns the coordinate y and use these coordinates to move the turtle:

def find_circle_coord(x0, y0, r, x):
d = x**2 - 2*x0*x + x0**2 + y0**2 - r**2
D = y0**2 - d
if D < 0:
raise ValueError("Value for x is outside the circle!")
return y0 - D**.5, y0 + D**.5

As in:

>>> # bob is a turtle
>>> bob.pendown()
>>> for x in range(-50, 50):
... y1, _ = find_circle_coord(0, 0, 100, x)
... bob.goto(x, y1)

By choosing one of the two coordinates returned you choose whether to draw the "upper" or "lower" arc.

to draw a smile you simply have to come up with two circles one smaller and a larger one but with the center slightly above the previous one so that they have that kind of intersection.

So you have to choose a circle C1 centered in x0, y0 with radius r and a circle C2 centered in x0, y0+K with radius R > r.
Note that C2's center is vertically aligned with C1 center (hence the same x coordinate for the center) but it is above it (note: I'm not sure of y-axis orientation so the +K might be -K...)

To find the intersections you have to solve the system of their equations:

(x-x0)^2 + (y-y0)^2-r^2 = 0
(x-x0^2) + (y-y0-K)^2-R^2 = 0

Now subtracting the second equation from the first you get:

(y-y0)^2 - (y-y0-K)^2 -r^2 + R^2 = 0
y^2 -2y·y0 +y0^2 - y^2 -y0^2 -K^2 +2y·y0 +2K·y -2K·y0 -r^2 + R^2 = 0
-K^2 +2K·y -2K·y0 -r^2 + R^2 = 0

Where you get:

y = (K^2 +2K·y0 +r^2 -R^2)/(2K)

And you can substitute the y in one of the circle equations to obtain the xs corresponding to such y. Then you know which x to draw using find_circle_coord.

If you want to make the mouth more open you could use a circle and a parabola. To find the y value of a point on a parabole it's easy:

def find_parabola_coord(a, b, c, x):
return a*x**2 + b*x + c

Or you could use the form of equation of a parabola given its vertex V = (xv, yv):

y - yv = a(x - xv)^2

where a controls how steep the parabola is.

Turtle, and tilting an object

You can do this but it requires you rethink your drawing logic. For the emoticon to hold up under the 10 degree rotations, your positioning of the turtle while drawing the emoticon has to all be relative, not absolute. No turtle.goto(), no jump(turtle, x, y). And then to fit your ten emoticons on the page, you need to make the sizing relative too, not absolute. Here's a rework that does this:

from turtle import Turtle, Screen

def jump(turtle, x, y):
turtle.up()
turtle.goto(x, y)
turtle.down()

def head(turtle, size):
# to draw circle with current position as center, have to adjust the y position
turtle.up()
turtle.right(90)
turtle.forward(size)
turtle.left(90)
turtle.color("black", "yellow")
turtle.down()

turtle.begin_fill()
turtle.circle(size)
turtle.end_fill()

# return to the center of the circle
turtle.up()
turtle.color("black")
turtle.left(90)
turtle.forward(size)
turtle.right(90)
turtle.down()

def eyes(turtle, size):
turtle.up()
turtle.forward(0.35 * size)
turtle.left(90)
turtle.forward(0.2 * size)
turtle.right(90)
turtle.down()

turtle.dot(0.25 * size)

turtle.up()
turtle.backward(0.7 * size)
turtle.down()

turtle.dot(0.25 * size)

turtle.up()
turtle.forward(0.35 * size)
turtle.right(90)
turtle.forward(0.2 * size)
turtle.left(90)
turtle.down()

def happymouth(turtle, size):
turtle.up()
turtle.left(180)
turtle.forward(0.6 * size)
turtle.left(90)
turtle.forward(0.35 * size)
turtle.left(90)
turtle.down()

turtle.right(60)
turtle.circle(0.7 * size, 120)

turtle.up()
turtle.circle(0.7 * size, 240)
turtle.left(60)
turtle.forward(0.6 * size)
turtle.left(90)
turtle.forward(0.35 * size)
turtle.right(90)
turtle.down()

def emoticon(turtle, size):
turtle.pensize(0.03 * size)
head(turtle, size)
eyes(turtle, size)
happymouth(turtle, size)

screen = Screen()
yertle = Turtle()

width, height = screen.window_width(), screen.window_height()

yertle.setheading(-50)

for xy in range(-5, 5):
jump(yertle, xy * width / 10, xy * height / 10)

emoticon(yertle, 60)

yertle.setheading(yertle.heading() + 10)

screen.exitonclick()

The above code is not optimized as far as drawing -- it always returns to the center to make sure every component is draw relative to it. But it basically works:

enter image description here

There's a completely different way we can solve this problem which allows us to use the absolute turtle.goto() but has it's own difficulties. We can set the turtle itself to be an emoticon and stamp it across the page. This also allows us to ignore the relative sizing since the turtle cursor has its own sizing capability:

from turtle import Turtle, Screen, Shape

def jump(turtle, x, y):
turtle.up()
turtle.goto(x, y)
turtle.down()

def head(turtle, shape, x, y):
jump(turtle, x, y - 100)
turtle.begin_poly()
turtle.circle(100)
turtle.end_poly()
shape.addcomponent(turtle.get_poly(), "yellow", "black")

def happymouth(turtle, shape, x, y):
turtle.setheading(-60)
jump(turtle, x - 60, y - 35)
turtle.begin_poly()
turtle.circle(70, 120)
turtle.end_poly()
shape.addcomponent(turtle.get_poly(), "black")
turtle.setheading(90)

def eyes(turtle, shape, x, y):
jump(turtle, x + 35, y + 20)
turtle.begin_poly()
turtle.circle(13)
turtle.end_poly()
shape.addcomponent(turtle.get_poly(), "black")

jump(turtle, x - 35, y + 20)
turtle.begin_poly()
turtle.circle(13)
turtle.end_poly()
shape.addcomponent(turtle.get_poly(), "black")

def emoticon(turtle, x, y):
shape = Shape("compound")

head(turtle, shape, x, y)
eyes(turtle, shape, x, y)
happymouth(turtle, shape, x, y)

screen.register_shape("emoticon", shape)

screen = Screen()
yertle = Turtle(visible="False")
emoticon(yertle, 0, 0)
yertle.shape("emoticon")

yertle.clear()

yertle.shapesize(0.6, 0.6)

width, height = screen.window_width(), screen.window_height()

yertle.setheading(50)

for xy in range(-5, 5):
jump(yertle, xy * width / 10, xy * height / 10)

yertle.stamp()
yertle.setheading(yertle.heading() + 10)

screen.exitonclick()

Unfortunately, stamps done using turtle.*_poly() can only consist of closed polygons which means the emoticon smile changes somewhat:

enter image description here

Have fun!

How to make a turtle able to save other turtles ID in Netlogo?

If teams are random, I don't think you need a loop for this as ask will call the turtles in a random order anyway.

I think you should still make use of agentsets here as it makes certain things easier. For example, once turtles know their (agentset,3 turtles), you can easily query that agentset for the myIDs or whatever variable you're after.

I'm not entirely clear on the purpose of teamID so I may be off base here, but I don't think you want it as a global variable if the teamIDs are to be unique to each group of three turtles. You'll probably want it to be a turtles-own variable as well.

Here is an example that incorporates the above ideas. With this setup:

turtles-own [ myteamset teamID myID teammatesID ]

to setup
ca
crt 10 [
set myID who
set myteamset nobody
set teammatesID [ ]
]
setup-groups
print remove-duplicates [teammatesID] of turtles
print sort [teamID] of turtles
reset-ticks
end

And the setup-groups procedure (more detail in comments):

to setup-groups
ask turtles [
; If you don't have a team yet
if myteamset = nobody [
; Make a temporary agent-set out of all other turtles that
; are also not yet part of a team
let possible-teammates other turtles with [ myteamset = nobody ]

; If there are at least two more turtles, make a new team:
ifelse count possible-teammates > 1 [
; Make a team out of myself and two possible teammates
set myteamset ( turtle-set self n-of 2 possible-teammates )

; Make a temporary variable to pass on to my entire team
; (yourself included) for the team ids and the team members.
; Also, assign a random teamID to the whole team
let ids sort [myID] of myteamset
let teammmembers myteamset
let tempteam random 1000
ask myteamset [
set teammatesID ids
set myteamset teammmembers
set teamID tempteam
]
] [
; If there aren't enough turtles to form a new team,
; print a warning to the console.
show "Not enough turtles to make a new team!"
]
]
]
end

Let me know if that's kind of what you're after, hope it helps.

Edit- As per your comments:

To get sequential team numbers, you can make use of a simple counter that gets assigned to a team and then incremented for the next one- modified setup-groups would look like:

to setup-groups
; Create a temporary variable to use as a counter
let teamCounter 1
ask turtles [
if myteamset = nobody [
let possible-teammates other turtles with [ myteamset = nobody ]
ifelse count possible-teammates > 1 [
set myteamset ( turtle-set self n-of 2 possible-teammates )
let ids sort [myID] of myteamset
let teammmembers myteamset

; Assign the current teamCounter as team number, then
; increment it by one for the next team
let tempteam teamCounter
set teamCounter teamCounter + 1
ask myteamset [
set teammatesID ids
set myteamset teammmembers
set teamID tempteam
]
] [
show "Not enough turtles to make a new team!"
]
]
]
end

The second question may be worth a new question on its own, depending on how in depth you're hoping to get, but here is one very simplistic approach where you just get all unique team IDs and have one turtle with that ID have their team move together:

to move-in-groups
; Get the unique team IDs
let teamNumbers remove-duplicates [teamID] of turtles

; Get one member of each team to ask all members
; of its team (itself included) to move
foreach teamNumbers [
tn ->
ask one-of turtles with [ teamID = tn ] [
let newHeading heading + random 60 - 30
if myteamset != nobody [
ask myteamset [
set heading newHeading
fd 1
]
]
]
]
end

Edit 2: NetLogo 5-friendly version

to move-in-groups
; Get the unique team IDs
let teamNumbers remove-duplicates [teamID] of turtles

; Get one member of each team to ask all members
; of its team (itself included) to move
foreach teamNumbers [
ask one-of turtles with [ teamID = ? ] [
let newHeading heading + random 60 - 30
if myteamset != nobody [
ask myteamset [
set heading newHeading
fd 1
]
]
]
]
end

Google Colaboratory: AttributeError: module 'ColabTurtle.Turtle' has no attribute 'circle'

the circle function is not available in the google colaboratory turtle library.
i kind of recreated the circle with the help of cdlane's function:

circle is supposed to draw a circle with only the radius given

!pip3 install ColabTurtle
import ColabTurtle.Turtle as t
t.initializeTurtle()

from math import pi

def tcircle(radius):

#function could be summarized into:
#regular_polygon(int((2 * pi * radius)/9)),9)

#explained step by step:
"""draws a regular polygon of n sides
that is supposed to appear like a circle.
n is set to 9 for fast drawing time.
it calculates rounded side length from n and radius"""
#circumference (c)= 2*pi*radius
c = 2 * pi * radius


#n = amount of lines or corners, it defines the accuracy of the circle
n = 9 # lower number to decrease drawing time (can be any float or int)

#circumference (c) = ca. l * n
#l = length of individual lines
l = c / n

regular_polygon(int(l),n)


def regular_polygon(l, n):
"""draws a regular polygon of n amount sides of length l
that is supposed to appear like a circle.
function by cdlane from a stackoverflow post"""
for _ in range(n):
t.forward(l)
t.left(360 / n)

#circle_example
t.forward(35)
tcircle(45)

screenshot of my solution, how the circle_example would look like: https://imgur.com/LXgaB4v



Related Topics



Leave a reply



Submit