So It has been some time since my last post but I am thinking of starting a new kind of post which I call “I can make that!“.

It will be a post about something that I saw either online or as a project and I thought to myself “I can make that!“. I will then go on to make it and post my process of how I made it.

I think it will be a fun way to get me to try and make new things. I hope you all enjoy it.

So let’s get on the first “I can make that!“ shall we?

So a couple of days ago it was Valentines Day! And I saw a post by thecodexyz on Instagram which showed a red ascii heart with the caption “Happy Valentine’s Day”.

Valentines Day

So I thought to myself “I can make that!“. And so I did!

We are gonna be making this in Python! (Yessss)

The first thing I needed to figure out was how to make colored ASCII on the terminal.

I wanted to use as less libraries as possible so it can be easily sent out to anyone and they can run it without having to install anything.

I came across something called ANSI escape codes which are a standard for in-band signaling to control the cursor location, color, and other options on video text terminals.

We can achieve the red-colored text by using the following code:

RED = '\033[91m'
END = '\033[0m'

print(RED + "Hello World!" + END)

'\033[91m' is the escape code for red and '\033[0m' is the escape code to reset the color back to normal. (If you don’t reset the color back to normal then everything after the red text will also remain red)

So now that we know how to make colored text we can move on to making the heart.

I wanted to make a heart which would be easy to change the dimensions of but I also didn’t want to have the text premade and then just print it out. I wanted to make the heart using code.

I remember in the past where I would use math equations to make different shapes online. So I thought I could do the same here.

We would need a mathematical representation of a heart shape. Thankfully I found one online which I was able to tweak to make it similar to the heart that I wanted.

((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3 <= 0

Let’s break the equation down a bit.

Note that ** in this case is the code representation of the power function. So x**2 is the same as x^2

The first part ((x*0.05)**2+(y*0.1)**2-1)**3 is the top half of the heart. The second part (x*0.05)**2*(y*0.1)**3 is the bottom half of the heart.

(x*0.05)**2+(y*0.1)**2-1 creates a circle with a radius of 1. The x*0.05 and y*0.1 terms stretch the circle into an ellipse, which forms the body of the heart.

(x*0.05)**2*(y*0.1)**3 creates a smaller ellipse that is subtracted from the first one to create the indentation at the top of the heart.

The <= 0 part means that we’re only interested in the points where the result of the equation is less than or equal to 0. These points form the heart shape.

If this seems confusing to you then don’t worry. I was also confused at first. You can just copy the equation and play around with the values to see how it changes the heart.

So now that we have the equation we can move on to the code. (ooooooh)

heart = '@'
output = []

# Adjust this value to change the size of the heart (Note this works as a zoom in/out so the higher the number the more you zoom out)
heart_size = 2.0  

# Adjust the size of the heart based on the heart_size variable
for y in range(15, -15, -1):
    row = []
    for x in range(-30, 30):
        if ((x*0.04*heart_size)**2+(y*0.1*heart_size)**2-1)**3-(x*0.04*heart_size)**2*(y*0.1*heart_size)**3 <= 0:
            row.append(heart[(x-y) % len(heart)])
        else:
            row.append(' ')
    output.append(''.join(row))

Ok. A lot changed so let me explain what I did.

See, we want to make the heart in the terminal, and to make it similar to the post we also want to use the @ symbol.

We also want to save each row of the heart in a list so we can print it out later layer by layer.

I also added a variable called heart_size which will allow us to change the size of the heart. The higher the number the more you zoom out. (Imagine you have a camera and you are zooming in and out from the heart)

Also depending on the mathematical condition it will add our @ character to our row list. the character is chosen based on the (x,y) position of the heart.

The (x-y) % len(heart) expression ensures that the index goes back to the start of the heart string once it reaches the end.

In the case where the condition is not met, we add a space to the row list so we can maintain the structure of the heart.

Now that we have the heart we can print it out.

for row in output:
    print(row)

But there is a problem. If we are lopping through each row and printing it out then it would be fine to use print(). But I want to create a sort of typing animation where the heart is printed out one letter at a time.

There is an issue with the print function. The print function automatically creates a new line after it is done printing. So we need to find a way to print out the heart without creating a new line.

Instead of using print, we can use the sys.stdout.write() function. This function will write the string to the terminal without creating or needing a new line.

import sys
import time

for row in output:
    letters = list(row)
    for letter in letters:
        sys.stdout.write(letter)
        time.sleep(0.1)
    sys.stdout.write('\n')

But for some reason, we don’t get any output when we run the code. This is because the sys.stdout.write function does not automatically flush the buffer (Show text on the console). We need to manually flush the buffer to get the output.

We can do this by using the sys.stdout.flush() function.

import sys
import time

for row in output:
    letters = list(row)
    for letter in letters:
        sys.stdout.write(letter)
        sys.stdout.flush()
        time.sleep(0.1)
    sys.stdout.write('\n')
    sys.stdout.flush()

Heart

Good! We have our heart which is the hard part done. Now we need to create our Happy Valentine’s Day text.

First, we need to make a variable with the text we want to print out.

text = "Happy Valentines Day"

If we want to print it out letter by letter we can make each letter into a list using the list() function.

text = "Happy Valentines Day"
text = list(text)

Now we can loop through each letter and print it out.

for letter in text:
    sys.stdout.write(letter)
    sys.stdout.flush()
    time.sleep(0.1)

Heart

And there we have it! We have our hearts and our Happy Valentine’s Day text.

Here you can find my full version of the code at https://github.com/Arisamiga/Valentines

(I have also added a lot of comments in the code to help explain it better)

Hope you enjoyed this post! It was an interesting project for me to do and quite fun.

Happy Valentine’s Day! And Thanks so much for reading :D