Throbbing Heart Animation with Python and Turtle (Source Code)

https://pythonturtle.academy/wp-content/uploads/2021/11/heart.mp4

Animate a throbbing heart. Check out this simple heart drawing tutorial if you need help.

Source Code:

import turtle
import math

screen = turtle.Screen()
screen.title('Heart Animation - PythonTurtle.Academy')
screen.setup(1000,1000)
screen.setworldcoordinates(-1000,-1000,1000,1000)
turtle.speed(0)
turtle.hideturtle()

screen.tracer(0,0)
turtle.color('red')

def draw_heart(alpha,d):
  r = d/math.tan(math.radians(180-alpha/2))
  turtle.up()
  turtle.goto(0,-d*math.cos(math.radians(45)))
  turtle.seth(90-(alpha-180))
  turtle.down()
  turtle.begin_fill()
  turtle.fd(d)
  turtle.circle(r,alpha)
  turtle.left(180)
  turtle.circle(r,alpha)
  turtle.fd(d)
  turtle.end_fill()

a = 220
sign = -1
def animate():
  global a,sign
  turtle.clear()
  draw_heart(a,1000)
  screen.update()
  a += sign
  if a < 215:
    sign = -sign
  elif a > 220:
    sign = -sign
  screen.ontimer(animate,50)

animate()

Typing Game with Python and Turtle (Source Code Included)

Develop a typing game to improve keyboard skill as demonstrated in the following YouTube video.

Typing Game with Python and Turtle

At any moment ten random letters fall from the top of screen. When you hit a correct letter from keyboard, that letter disappears and is replaced by a new random letter dropping from the top. Also, your score will increase by 1. When you hit an incorrect letter, your score will decrease by 1.

Make these letters fall at random speeds and also let the speed increase gradually as time progresses. The game will end when a letter falls to the bottom of the screen.

You will need to use Turtle’s ontimer() and onkey() events to implement this project.

Source Code:

import turtle
import random

screen = turtle.Screen()
screen.setup(1000,1000)
screen.title('Typing Game - PythonTurtle.Academy')
screen.bgcolor('blue')
screen.tracer(0,0)
turtle.hideturtle()
turtle.up()
turtle.color('red')
score_turtle = turtle.Turtle()
score_turtle.color('red')
score_turtle.up()
score_turtle.hideturtle()
turtle.goto(350,400)
turtle.write('Score: ', align='center', font=('Courier',25,'normal'))

min_speed = 5
max_speed = 30
letters = []
speeds = []
pos = []
lts = []
n = 10
game_over = False
score = 0

def increase_difficulty():
    global min_speed, max_speed
    min_speed += 1
    max_speed += 1
    screen.ontimer(increase_difficulty,5000)

def draw_game_over():
    turtle.goto(0,0)
    turtle.color('red')
    turtle.write('GAME OVER', align='center', font=('Courier',50,'normal'))
    turtle.goto(0,-150)
    turtle.color('orange')
    turtle.write('Your Score is {}'.format(score), align='center', font=('Courier',40,'normal'))
    screen.update()

def draw_score():
    score_turtle.clear()
    score_turtle.goto(420,400)
    score_turtle.write('{}'.format(score),align='center',font=('Courier',25,'normal'))
    screen.update()
    
def draw_letters():
    global game_over
    for i in range(len(letters)):
        lts[i].clear()
        lts[i].goto(pos[i])
        lts[i].write(letters[i],align='center',font=('courier',20,'normal'))
        pos[i][1] -= speeds[i]
        if pos[i][1]<-500:
            game_over = True
            draw_game_over()
            return
    screen.update()
    screen.ontimer(draw_letters,50)

def f(c): # handle keyboard press
    global score
    if c in letters:
        score += 1
        k = letters.index(c)
        while True:
            l = chr(ord('a')+random.randrange(26))
            if l not in letters:
                letters[k] = l
                break            
        pos[k] = [random.randint(-450,450),500]        
        speeds[k] = random.randint(min_speed,max_speed)
    else: score -= 1
    draw_score()
        
for _ in range(n):
    lts.append(turtle.Turtle())
    while True:
        l = chr(ord('a')+random.randrange(26))
        if l not in letters:
            letters.append(l)
            break
    speeds.append(random.randint(min_speed,max_speed))
    pos.append([random.randint(-450,450),500])
    
for i in range(n):
    lts[i].speed(0)
    lts[i].hideturtle()
    lts[i].up()
    lts[i].color('yellow')
    
draw_letters()
increase_difficulty()

screen.onkey(lambda: f('a'), 'a')
screen.onkey(lambda: f('b'), 'b')
screen.onkey(lambda: f('c'), 'c')
screen.onkey(lambda: f('d'), 'd')
screen.onkey(lambda: f('e'), 'e')
screen.onkey(lambda: f('f'), 'f')
screen.onkey(lambda: f('g'), 'g')
screen.onkey(lambda: f('h'), 'h')
screen.onkey(lambda: f('i'), 'i')
screen.onkey(lambda: f('j'), 'j')
screen.onkey(lambda: f('k'), 'k')
screen.onkey(lambda: f('l'), 'l')
screen.onkey(lambda: f('m'), 'm')
screen.onkey(lambda: f('n'), 'n')
screen.onkey(lambda: f('o'), 'o')
screen.onkey(lambda: f('p'), 'p')
screen.onkey(lambda: f('q'), 'q')
screen.onkey(lambda: f('r'), 'r')
screen.onkey(lambda: f('s'), 's')
screen.onkey(lambda: f('t'), 't')
screen.onkey(lambda: f('u'), 'u')
screen.onkey(lambda: f('v'), 'v')
screen.onkey(lambda: f('w'), 'w')
screen.onkey(lambda: f('x'), 'x')
screen.onkey(lambda: f('y'), 'y')
screen.onkey(lambda: f('z'), 'z')

screen.listen()
screen.mainloop()

Continuous Clock with Python Turtle (Source Code)

In a previous project you animated a clock. Improve the clock by making all hands move continuously.

Source Code:

import turtle
import datetime
import math

screen = turtle.Screen()
screen.title('Continuous Clock - PythonTurtle.Academy')
screen.bgcolor('sky blue')
screen.setup(1000,1000)
screen.setworldcoordinates(-1000,-1000,1000,1000)
screen.tracer(0,0)


class clock:
    def __init__(self,hour,minute,second):
        self.hour, self.minute, self.second = hour, minute, second
        self.microsecond = 0
        self.face = turtle.Turtle()
        self.hand = turtle.Turtle()
        self.face.hideturtle()
        self.hand.hideturtle()

    def draw(self):
        self.draw_face()
        self.draw_hand()
        
    def draw_face(self):
        self.face.clear()
        self.face.up()
        self.face.goto(0,-700)
        self.face.pensize(4)
        self.face.down()
        self.face.fillcolor('white')
        self.face.begin_fill()
        self.face.circle(700,steps=100)
        self.face.end_fill()
        self.face.up()
        self.face.goto(0,0)
        self.face.dot(10)
        self.face.pensize(2)
        for angle in range(0,360,6):
            self.face.up()
            self.face.goto(0,0)
            self.face.seth(90-angle)
            self.face.fd(620)
            self.face.down()
            self.face.fd(30)
            
        self.face.pensize(3)
        for angle in range(0,360,30):
            self.face.up()
            self.face.goto(0,0)
            self.face.seth(90-angle)
            self.face.fd(600)
            self.face.down()
            self.face.fd(50)
            
        self.face.pensize(4)
        for angle in range(0,360,90):
            self.face.up()
            self.face.goto(0,0)
            self.face.seth(90-angle)
            self.face.fd(580)
            self.face.down()
            self.face.fd(70)
        
    def draw_hand(self):    
        self.hand.clear()       
        self.hand.up()
        self.hand.goto(0,0)
        self.hand.seth(90-math.floor(((self.hour%12)*60*60*1000000+self.minute*60*1000000+self.second*1000000+self.microsecond)/3600000000*30))
        self.hand.down()
        self.hand.color('black')
        self.hand.pensize(6)
        self.hand.fd(300)

        self.hand.up()
        self.hand.goto(0,0)
        self.hand.seth(90-math.floor((self.minute*60*1000000+self.second*1000000+self.microsecond)/60000000*6))
        self.hand.down()
        self.hand.color('black')
        self.hand.pensize(4)
        self.hand.fd(400)

        self.hand.up()
        self.hand.color('red')
        self.hand.goto(0,0)
        self.hand.dot(5)
        self.hand.seth(90-(self.second*1000000+self.microsecond)/1000000*6)
        self.hand.down()
        self.hand.pensize(2)
        self.hand.fd(570)

def animate():
    global c
    d = datetime.datetime.now()
    c.hour, c.minute, c.second, c.microsecond = d.hour, d.minute, d.second, d.microsecond
    c.draw_hand()
    screen.update()
    screen.ontimer(animate,100)
    
d = datetime.datetime.now()
c = clock(d.hour,d.minute,d.second)
c.draw_face()
screen.update()
animate()

Clock with Python Turtle (Source Code)

Define a ‘clock’ class with Python and use the datetime library to draw an animated clock shown.

Source Code:

import turtle
import datetime
screen = turtle.Screen()
screen.title('Clock - PythonTurtle.Academy')
screen.setup(1000,1000)
screen.setworldcoordinates(-1000,-1000,1000,1000)
screen.tracer(0,0)
screen.bgcolor('sky blue')

class clock:
    def __init__(self,hour,minute,second):
        self.hour, self.minute, self.second = hour, minute, second
        self.face = turtle.Turtle()
        self.hand = turtle.Turtle()
        self.face.hideturtle()
        self.hand.hideturtle()

    def draw(self):
        self.draw_face()
        self.draw_hand()
        
    def draw_face(self):
        self.face.clear()
        self.face.up()
        self.face.goto(0,-700)
        self.face.pensize(5)
        self.face.down()
        self.face.fillcolor('white')
        self.face.begin_fill()
        self.face.circle(700)
        self.face.end_fill()
        self.face.up()
        self.face.goto(0,0)
        self.face.dot(10)
        self.face.pensize(2)
        for angle in range(0,360,6):
            self.face.up()
            self.face.goto(0,0)
            self.face.seth(90-angle)
            self.face.fd(620)
            self.face.down()
            self.face.fd(30)
        self.face.pensize(4)
        for angle in range(0,360,30):
            self.face.up()
            self.face.goto(0,0)
            self.face.seth(90-angle)
            self.face.fd(600)
            self.face.down()
            self.face.fd(50)
        
    def draw_hand(self):    
        self.hand.clear()       
        self.hand.up()
        self.hand.goto(0,0)
        self.hand.seth(90-self.hour%12*360//12)
        self.hand.down()
        self.hand.color('black')
        self.hand.pensize(6)
        self.hand.fd(300)

        self.hand.up()
        self.hand.goto(0,0)
        self.hand.seth(90-self.minute*6)
        self.hand.down()
        self.hand.color('black')
        self.hand.pensize(4)
        self.hand.fd(400)

        self.hand.up()
        self.hand.color('red')
        self.hand.goto(0,0)
        self.hand.dot(5)
        self.hand.seth(90-self.second*6)
        self.hand.down()
        self.hand.pensize(2)
        self.hand.fd(600)

def animate():
    global c
    d = datetime.datetime.now()
    c.hour, c.minute, c.second = d.hour, d.minute, d.second
    c.draw_hand()
    screen.update()
    screen.ontimer(animate,1000)
    
d = datetime.datetime.now()
c = clock(d.hour,d.minute,d.second)
c.draw_face()
screen.update()
animate()

Animation of Sierpinski Triangle Tree with Turtle (Source Code)

Animate the transition from Sierpinski Triangle tree to Fractal tree as shown. This project is related to Sierpinski Triangle and Fractal Tree.

Source Code:

import turtle
turtle.title('Sierpinski Tree Animation - PythonTurtle.Academy')
turtle.setworldcoordinates(-2000,-2000,2000,2000)
screen = turtle.Screen()
screen.tracer(0,0)
turtle.speed(0)
turtle.hideturtle()

def sierpinski_tree(x,y,length,tilt,angle,n):
    if n==0: return
    turtle.up()
    turtle.goto(x,y)
    turtle.seth(tilt)
    turtle.down()
    turtle.fd(length)
    sierpinski_tree(turtle.xcor(),turtle.ycor(),length/2,turtle.heading(),angle,n-1)
    
    turtle.up()
    turtle.goto(x,y)
    turtle.seth(tilt+angle)
    turtle.down()
    turtle.fd(length)
    sierpinski_tree(turtle.xcor(),turtle.ycor(),length/2,turtle.heading(),angle,n-1)

    turtle.up()
    turtle.goto(x,y)
    turtle.seth(tilt-angle)
    turtle.down()
    turtle.fd(length)
    sierpinski_tree(turtle.xcor(),turtle.ycor(),length/2,turtle.heading(),angle,n-1)

def animate():
    global angle
    turtle.clear()
    sierpinski_tree(0,-250,1000,90,angle,7)
    screen.update()
    angle = 120 if angle <= 20 else angle-2
    screen.ontimer(animate,50)

angle = 120
animate()
screen.mainloop()

Animating Knight’s Minimum Move with Python Turtle (Source Code Included)

Write a program that animates the move of a knight in a chess board from any source to any destination with the minimum number of steps. You may need to use Breadth First Search (BFS) with Queue data structure.

Source Code:

import turtle
import time
import sys

turtle.setup(800,800)
turtle.setworldcoordinates(-250,-250,250,250)
turtle.title("Knight's Minimum Moves - PythonTurtle.Academy")

def draw_square(x,y,size,color):
    turtle.up()
    turtle.goto(x,y)
    turtle.seth(0)
    turtle.down()
    turtle.begin_fill()
    turtle.fillcolor(color)
    for i in range(4):
        turtle.fd(size)
        turtle.left(90)
    turtle.end_fill()
        
def draw_board(src=(-2,-2),dest=(-2,-2), mlist=[]):
    turtle.pencolor("black")
    y = -200
    piecesize = 50
    startpiececolor = "darkgray"
    for i in range(8):
        x = -200
        piececolor = startpiececolor
        for j in range(8):
            if (j+1,i+1)==src:
                draw_square(x,y,piecesize,'light blue')
            elif (j+1,i+1)==dest:
                draw_square(x,y,piecesize,'pink')
            elif (j+1,i+1) in mlist:
                draw_square(x,y,piecesize,'light green')                
            else:   
                draw_square(x,y,piecesize,piececolor)
            x += piecesize
            if piececolor == "darkgray":
                piececolor = "lightgray"
            else:
                piececolor = "darkgray"
        y += piecesize
        if startpiececolor == "darkgray":
            startpiececolor = "lightgray"
        else:
            startpiececolor = "darkgray"
    
def draw_knight(pos):
    xpos = 50*(pos[0]-1) - 175
    ypos = 50*(pos[1]-1) - 195
    turtle.up()
    turtle.goto(xpos,ypos)
    turtle.write('\u265e',align='center',font=('Arial',40,'normal'))

class node:
    def __init__(self,val,nxt=None):
        self.value=val
        self.next=nxt

class LinkedList:
    def __init__(self,it=None):
        self.head = None
        self.tail = None
        self.length = 0
        if it is None: return
        for x in it:
            self.insert_at_tail(x)

    def insert_at_head(self,k):
        if self.head is None:
            self.head = node(k)
            self.tail = self.head
        else:
            p = node(k,self.head)
            self.head = p
        self.length += 1

    def insert_after(self,p,k):
        if self.length < p or p < 0:
            raise Exception('Linked List doesn\'t have position '+str(p))
        if p==0:
            self.insert_at_head(k)
            return
        q = self.head
        for _ in range(p-1):
            q = q.next
        q.next = node(k,q.next)
        
    def insert_at_tail(self,k):
        if self.tail is None:
            self.head = node(k)
            self.tail = self.head
        else:
            self.tail.next = node(k)
            self.tail = self.tail.next
        self.length += 1

    def __iter__(self):
        p = self.head
        while p is not None:
            yield p.value
            p = p.next
            
    def __len__(self):
        return self.length
    
    def __str__(self):
        s = ""
        p = self.head
        while p is not None:
            s += str(p.value) + '->'
            p = p.next
        s += 'None'
        return s

    def delete_from_head(self):
        if self.head is None: return
        self.length -= 1
        self.head = self.head.next
        if self.head is None:
            self.tail = None

    def delete_from_tail(self):
        if self.head is None: return
        self.length -= 1
        if self.head == self.tail: self.head = self.tail = None
        p = self.head
        while p.next != self.tail:
            p = p.next
        p.next = None
        self.tail = p

class Queue:
    def __init__(self):
        self.ll = LinkedList()
        self.length = len(self.ll)

    def push(self,k):
        self.ll.insert_at_tail(k)

    def pop(self):
        if len(self.ll)==0:
            raise Exception('Queue is empty')
        self.ll.delete_from_head()

    def top(self):
        if len(self.ll)==0:
            raise Exception('Queue is empty')
        return self.ll.head.value;
        
    def empty(self):
        return len(self.ll)==0

    def __len__(self):
        return len(self.ll)

class position:
    def __init__(self,pos,dist,parent):
        self.pos = pos
        self.dist = dist
        self.parent = parent

moves = [ (1,2), (1,-2), (-1,2),(-1,-2), (2,-1), (2,1), (-2,1), (-2,-1) ]

def valid_position(pos):
    if pos[0] < 1 or pos[0] > 8 or pos[1] < 1 or pos[1] > 8: return False
    return True

def minimum_knight_move(src, dest):
    q = Queue()
    s = set()
    q.push(position(src,0,None))
    s.add(src)
    while not q.empty():
        current = q.top()
        pos = current.pos
        dist = current.dist
        q.pop()
        # try all possible moves from here
        for m in moves:
            new_pos = (pos[0]+m[0],pos[1]+m[1])
            if valid_position(new_pos) and new_pos not in s:
                if new_pos == dest: return current
                s.add(new_pos)
                q.push(position(new_pos,dist+1,current))
    return -1
    
if __name__=='__main__':
    turtle.speed(0)
    turtle.hideturtle()
    turtle.tracer(0)
    while True:
        turtle.clear()
        draw_board()
        src = (-1,-1)
        dest = (-1,-1)
        while src[0] < 0 or src[0] > 8 or src[1] < 0 or src[1] > 8:
            srctext=turtle.textinput("Begin Position","Please enter the starting position (e.g. 2 4):")
            if srctext is None: sys.exit(0)
            try:
                src = tuple(map(int,srctext.split()))
            except:
                src = (-1,-1)
        draw_board(src)
        draw_knight(src)
        while dest[0] < 0 or dest[0] > 8 or dest[1] < 0 or dest[1] > 8:
            desttext=turtle.textinput("End Position","Please enter the target position (e.g. 8 5):")
            if desttext is None: sys.exit(0)
            try:
                dest = tuple(map(int,desttext.split()))
            except:
                dest = (-1,-1)
        draw_board(src,dest)
        draw_knight(dest)
        current = minimum_knight_move(src,dest)
        s = LinkedList()
        s.insert_at_head(dest)
        mlist = list()
        while current is not None:
            s.insert_at_head(current.pos)
            current = current.parent
        for pos in s:
            turtle.clear()
            mlist.append(pos)
            draw_board(src,dest,mlist)
            draw_knight(pos)
            time.sleep(1)
            turtle.update()