Creating ASCII art#

Simple drawings#

We have to practise the usage of loops and decisions a little. It is one of the most fundamental concepts in programming, so we need gain experience with this concept. Let’s play around with it by creating some ASCII art. Way back in the beginning of computers the machines at that time were not able to create pixel based graphics. These machines have been invented to do number crunching, thus a text based output was the only possible way to show something on the computers screen. People became creative though and were able to create some amazing pieces of art just using text characters on a 80x25 character screen. Let’s try to resemble a very simple one. It’s one of the classics, which could often be seen on the accessible computer screens in warehouses back then. An image of a maze.

We just need two characters to draw them. One character would show a diaginal drawn from the bottom left to the top right corner. The other one would show a diagonal from the top left to the bottom right corner. Pretty comparable to the / and \ characters. They don’t match perfectly though, as they leave some pixels out at the border, to match standard letter and digit sizes. There has been an extended set of characters though with variants which better suited the idea, and those special characters still exist today in the defined character sets. Actually the amount of possible characters us huge and includes all letters known from the ASCII character set, as well as greek letters, math symbols and even emojis. Python has several ways to access those special letters, for example by using the index in the character set, or a speaking name. We’ll make use of the latter here.

So the idea for the algorithm is as follows.

  • visit each position on the screen by looping over all available rows and columns

  • draw a random decision to either draw the one or the other symbol at that very screens position

That’s already it.

import random
canvas_width = 80
canvas_height = 25
text = ""
for row in range(canvas_height):
    for column in range(canvas_width):
        symbol = random.choice(
            (
                "\N{BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT}",
                "\N{BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT}",
            )
        )
        text += symbol

    text += "\n"
print(text)
╲╲╲╱╲╱╱╱╲╲╱╲╱╱╲╲╲╲╲╱╱╱╱╱╱╱╱╱╱╱╱╱╲╲╱╱╲╱╱╲╱╱╲╱╱╱╱╲╱╲╲╱╲╲╱╲╲╱╲╱╲╲╱╱╱╲╱╱╲╱╱╱╲╱╲╱╱╲╲╱
╲╱╱╱╱╱╲╱╱╱╲╱╱╱╲╲╲╲╱╲╱╲╲╲╱╲╱╲╱╲╲╲╱╲╲╲╲╲╱╱╱╲╱╲╲╲╱╱╱╱╲╱╱╲╱╲╲╱╱╱╱╲╲╱╱╱╱╲╲╲╲╲╲╱╲╱╲╱╲╱
╲╱╲╱╲╲╲╲╱╲╱╱╱╱╲╱╱╲╲╲╱╱╱╲╱╲╲╲╱╲╲╱╲╲╲╲╱╲╲╲╲╱╱╱╱╱╱╱╱╲╱╱╱╲╲╱╲╲╱╱╱╱╱╲╲╱╲╲╱╱╱╲╲╲╲╱╲╱╲╲
╱╱╲╲╲╱╱╱╲╱╲╱╲╱╱╱╱╱╱╲╲╱╱╲╲╱╲╱╱╲╲╲╱╲╲╲╱╲╲╱╲╱╱╱╱╱╲╲╱╲╲╲╲╲╱╱╲╲╲╱╱╲╱╱╱╲╱╲╲╱╱╱╲╱╲╲╱╱╱╲
╱╲╲╲╱╱╲╲╲╱╲╱╲╱╱╲╱╱╲╲╱╲╲╱╱╲╱╲╲╱╱╱╱╲╲╱╱╱╱╲╲╲╱╲╲╲╱╱╲╱╱╲╲╱╱╲╱╱╲╱╲╲╱╱╱╲╲╲╲╱╱╲╱╲╱╱╱╱╲╱
╱╱╱╲╲╲╲╱╱╲╲╲╲╱╲╱╲╲╲╱╲╱╱╲╱╱╱╲╱╱╱╱╱╲╲╲╱╲╲╱╱╱╲╱╲╱╲╲╱╱╱╱╲╲╲╲╱╲╱╱╲╱╲╱╱╲╲╱╲╲╱╲╱╲╱╲╱╲╱╱
╱╲╱╱╲╲╱╲╱╱╲╲╲╱╱╱╱╱╱╱╲╱╱╱╲╲╱╱╱╲╲╱╱╱╲╱╲╲╱╱╱╲╲╱╱╲╲╲╱╱╱╲╱╱╱╱╲╱╱╲╱╱╱╱╲╱╱╲╲╱╱╱╲╱╱╲╲╲╱╱
╱╱╱╲╱╱╲╲╱╲╱╱╱╱╲╲╲╱╱╱╱╲╲╲╱╲╲╲╱╱╱╲╱╲╲╲╱╱╱╱╱╱╱╱╲╱╲╲╲╱╱╲╱╱╲╲╱╱╱╲╲╱╲╲╱╱╲╱╱╲╲╱╲╲╱╱╱╲╲╲
╱╲╲╱╲╱╱╱╱╱╱╲╲╱╲╱╱╱╱╲╱╱╲╲╱╱╱╱╱╲╲╱╲╲╱╲╱╲╲╱╱╱╲╱╱╱╲╲╲╲╱╱╲╲╱╲╱╲╲╱╲╱╲╲╱╱╲╲╱╱╱╲╲╲╲╲╱╱╲╱
╱╲╲╱╱╱╲╲╱╱╱╱╲╲╱╲╱╱╲╲╱╱╲╱╲╲╱╲╱╲╲╲╲╲╲╱╱╲╲╲╲╱╲╱╱╲╲╲╲╱╱╲╲╲╱╱╱╱╲╲╲╲╲╲╲╲╱╱╱╱╱╲╱╱╲╱╲╱╲╲
╱╱╲╱╱╱╱╲╱╱╱╲╱╲╱╲╲╱╲╱╲╲╲╱╱╲╱╲╲╲╲╲╲╲╱╱╱╱╲╲╲╱╱╲╱╲╲╱╲╲╲╲╲╱╲╲╱╲╲╱╲╲╲╲╲╲╲╱╲╱╱╱╲╱╱╱╲╱╲╱
╱╱╲╲╲╲╲╲╲╱╲╱╲╱╱╱╱╱╲╱╱╲╱╱╲╱╱╱╱╱╱╲╲╲╲╱╱╲╲╱╲╲╱╱╱╲╲╲╲╲╱╲╲╲╱╲╱╲╲╲╱╱╲╲╱╱╲╱╱╱╱╲╱╲╱╱╱╲╱╲
╲╱╱╲╱╱╱╲╱╱╲╱╱╱╲╱╱╲╱╲╱╱╲╲╱╲╱╱╱╱╱╱╲╲╱╱╱╱╱╲╱╲╲╱╱╱╱╱╱╱╲╲╲╱╱╱╲╲╱╲╱╲╲╲╲╱╲╲╱╱╱╱╲╱╱╱╲╲╲╱
╱╲╱╲╱╱╲╱╲╱╱╱╲╱╱╱╱╱╲╲╲╲╲╲╱╱╲╲╲╲╱╱╱╲╲╱╱╱╱╲╲╱╱╱╱╲╲╲╲╲╱╲╱╲╱╱╱╱╱╱╲╲╲╱╲╱╲╱╲╲╱╲╱╱╱╲╲╲╲╲
╲╱╲╲╲╲╱╲╲╱╲╲╲╲╱╱╱╱╱╲╱╱╲╱╲╱╲╲╲╱╱╱╲╲╲╱╲╲╲╲╲╱╲╱╱╲╱╲╱╲╲╱╲╱╱╱╲╲╱╲╱╲╲╲╱╱╱╱╲╱╲╱╱╲╱╱╱╱╱╲
╱╱╲╲╱╲╲╱╲╲╱╲╲╱╱╲╱╲╲╱╱╱╲╱╲╱╱╱╱╱╱╲╲╲╱╲╲╱╲╲╱╱╱╲╱╱╱╲╲╲╱╲╱╲╲╲╲╲╲╱╲╲╱╲╱╱╲╲╲╱╱╱╱╲╱╱╱╲╲╱
╱╲╲╲╱╱╲╲╲╲╲╱╱╲╱╲╲╲╲╲╱╱╱╲╱╲╲╱╲╱╲╱╱╱╲╱╲╲╲╱╱╱╱╱╱╱╱╲╲╱╱╱╱╱╱╱╲╲╱╱╱╱╱╲╱╱╲╱╲╱╱╲╱╲╱╲╱╱╲╱
╲╲╲╲╲╲╱╲╱╲╲╲╲╲╲╲╱╲╲╲╱╲╲╱╱╲╲╲╱╲╱╱╱╱╱╲╱╲╱╲╱╱╱╲╱╱╲╲╱╱╱╲╱╱╲╱╲╲╲╱╱╲╱╲╱╲╱╱╲╲╲╱╲╲╲╲╱╲╱╱
╱╱╱╱╱╲╲╱╲╲╲╱╲╱╱╱╲╲╱╱╲╲╲╱╱╱╱╱╲╱╱╱╱╱╲╲╲╲╱╲╲╱╲╲╲╱╲╱╲╱╲╲╲╲╱╲╱╲╱╱╲╱╱╱╲╲╲╱╱╲╱╱╲╲╲╲╱╲╱╲
╲╲╱╲╲╲╱╲╲╱╱╱╲╲╱╱╱╱╱╱╱╱╲╲╱╱╱╱╱╱╱╱╲╲╱╱╲╲╱╲╱╱╲╱╱╱╲╲╱╱╱╲╲╲╲╲╱╲╲╲╱╲╲╲╲╲╱╱╱╲╱╲╱╱╱╲╱╲╲╲
╱╲╱╱╱╱╲╲╲╱╱╲╱╲╱╲╱╱╲╱╲╱╲╲╱╱╱╲╱╱╲╱╲╱╱╱╲╲╱╲╱╱╱╱╲╱╲╱╲╲╲╱╲╱╲╲╱╲╲╲╱╱╲╲╱╲╱╲╲╱╱╱╲╲╲╱╲╲╲╲
╲╲╲╲╱╱╱╱╲╱╱╲╱╲╱╲╱╱╱╲╲╱╲╲╱╲╲╲╱╲╱╱╱╱╱╲╲╱╲╲╱╲╲╱╲╱╲╲╱╱╱╲╱╲╱╱╱╲╲╲╱╱╱╲╲╲╱╱╲╱╲╲╱╲╱╲╱╲╱╱
╲╱╲╲╲╲╱╱╱╲╲╲╱╲╲╱╱╱╲╱╲╲╱╲╱╲╱╱╲╲╲╲╲╲╲╲╱╲╲╱╱╱╱╱╱╱╱╱╱╱╲╱╲╱╲╱╱╲╱╱╱╲╱╱╱╲╱╱╱╲╲╲╱╱╱╱╱╲╲╲
╱╱╱╲╱╱╱╱╲╱╲╲╱╱╱╲╲╱╱╱╱╲╲╲╲╱╱╱╱╱╲╱╱╱╱╲╱╱╲╲╲╱╱╲╱╱╱╲╲╱╱╱╲╲╱╱╲╱╲╲╲╱╱╲╱╲╱╲╱╲╱╱╲╲╱╲╱╱╱╱
╱╱╱╲╱╲╲╲╲╲╱╱╱╱╱╲╱╱╲╱╱╲╱╱╱╱╱╲╲╱╲╲╲╲╱╲╱╱╱╲╱╲╱╱╱╲╱╱╱╲╲╲╲╱╲╲╲╱╱╱╱╱╱╱╱╲╱╲╲╱╱╲╱╲╲╱╲╱╲╱

Quite a-maze-ing, isn’t it?

Note

We’ve created a large string here with a special symbol \n to break the text into lines here. This symbol is a control sequence to create a new line when printing out the text. We’ll be learning more about this in the file handling chapter.

We could have just printed each symbol one by one instead without the default line ending character for each symbol, and a standard print with an empty string at each lines end. On a console that would have created the same output. For this book printing all text at once is the cleaner approach though.

Tip

Try to create a little standalone python script printing those random lines in and endless loop instead of stopping after 25 rows. The endlessly scrolling output can be quite satisfying to watch.

Drawing geometric shapes#

But let’s get a bit more serious now. What about drawing a filled rectangle on the screen?

canvas: 80x25

rectangle_width: 6
rectangle_height: 5
rectangle_x: 10
rectangle_y: 5

x --->
y                 
|   +----+      
|   |####|      
|   +----+
v

pixel: "#"
no pixel: "."

A naive implementation#

canvas_width = 80
canvas_height = 25

rectangle_width = 6
rectangle_height = 5
rectangle_x = 10
rectangle_y = 5
text = ""

for y in range(canvas_height):
    for x in range(canvas_width):
        rectangle_test = (
            (y > rectangle_y)
            and (x > rectangle_x)
            and (y <= rectangle_y + rectangle_height)
            and (x <= rectangle_x + rectangle_width)
        )

        if rectangle_test:
            text += "#"
        else:
            text += "."

    text += "\n"

print(text)
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................

A bit optimized#

text = ""

for y in range(canvas_height):
    for x in range(canvas_width):

        rectangle_test = all(
            [
                (y > rectangle_y),
                (x > rectangle_x),
                (y <= rectangle_y + rectangle_height),
                (x <= rectangle_x + rectangle_width),
            ]
        )

        if rectangle_test:
            text += "#"
        else:
            text += "."

    text += "\n"

print(text)
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................

Even more clean#

text = ""

for y in range(canvas_height):
    for x in range(canvas_width):

        rectangle_test = all(
            [
                rectangle_y < y <= rectangle_y + rectangle_height,
                rectangle_x < x <= rectangle_x + rectangle_width,
            ]
        )

        if rectangle_test:
            text += "#"
        else:
            text += "."

    text += "\n"

print(text)
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................

Possibly the most pythonic version#

text = ""

for y in range(canvas_height):
    for x in range(canvas_width):

        rectangle_test = all(
            [
                rectangle_y < y <= rectangle_y + rectangle_height,
                rectangle_x < x <= rectangle_x + rectangle_width,
            ]
        )

        text += "#" if rectangle_test else "."

    text += "\n"

print(text)
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
...........######...............................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................

Challenges#

Paint a rectangle and a circle#

circle_x = 50
circle_y = 12
circle_radius = 5
text = ""

for y in range(canvas_height):
    for x in range(canvas_width):

        rectangle_test = all(
            [
                rectangle_y < y <= rectangle_y + rectangle_height,
                rectangle_x < x <= rectangle_x + rectangle_width,
            ]
        )
        
        circle_test = (circle_x - x)**2 + (circle_y - y)**2 <= circle_radius**2

        text += "#" if rectangle_test or circle_test else "."

    text += "\n"

print(text)
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
...........######...............................................................
...........######.................................#.............................
...........######..............................#######..........................
...........######.............................#########.........................
...........######.............................#########.........................
..............................................#########.........................
.............................................###########........................
..............................................#########.........................
..............................................#########.........................
..............................................#########.........................
...............................................#######..........................
..................................................#.............................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................

Paint a number of rectangles and circles of varying sizes and positions#

number_of_rectangles = random.randint(1,3)
number_of_circles = random.randint(1, 3)
rectangles = []
for _ in range(number_of_rectangles):
    rx = random.randint(1, canvas_width)
    ry = random.randint(1, canvas_height)
    rw = random.randint(1, 5)
    rh = random.randint(1, 5)
    rectangles.append((rx, ry, rw, rh))
    
circles = []
for _ in range(number_of_circles):
    cx = random.randint(1, canvas_width)
    cy = random.randint(1, canvas_height)
    cr = random.randint(1, 5)
    circles.append((cx, cy, cr))
text = ""

for y in range(canvas_height):
    for x in range(canvas_width):
        test_results = []
        for rectangle in rectangles:
            rx, ry, rw, rh = rectangle
            
            if (rx < x <= rx + rw) and (ry < y <= ry + rh):
                test_results.append(True)
        
        for circle in circles:
            cx, cy, cr = circle
            if (cx - x)**2 + (cy - y)**2 <= cr**2:
                test_results.append(True)

        text += "#" if any(test_results) else "."

    text += "\n"

print(text)
...............................#................................................
.............................#####..............................................
.............................#####..............................................
............................#######.............................................
.............................#####..............................................
.............................#####..............................................
.......###.....................#................................................
.......###......................................................................
................................................................................
................................................................................
..............................................#.................................
............................................#####...............................
...........................................#######..............................
...........................................#######..............................
..........................................#########.#...........................
...........................................############.........................
...........................................############.........................
............................................############........................
..............................................#...#####.........................
..................................................#####.........................
.......................##...........................#...........................
.......................##.......................................................
................................................................................
................................................................................
................................................................................
text = ""

for y in range(canvas_height):
    for x in range(canvas_width):
        test_results = []
        for rx, ry, rw, rh in rectangles:
            if (rx < x <= rx + rw) and (ry < y <= ry + rh):
                test_results.append(True)
        
        for cx, cy, cr in circles:
            if (cx - x)**2 + (cy - y)**2 <= cr**2:
                test_results.append(True)

        text += "#" if any(test_results) else "."

    text += "\n"

print(text)
...............................#................................................
.............................#####..............................................
.............................#####..............................................
............................#######.............................................
.............................#####..............................................
.............................#####..............................................
.......###.....................#................................................
.......###......................................................................
................................................................................
................................................................................
..............................................#.................................
............................................#####...............................
...........................................#######..............................
...........................................#######..............................
..........................................#########.#...........................
...........................................############.........................
...........................................############.........................
............................................############........................
..............................................#...#####.........................
..................................................#####.........................
.......................##...........................#...........................
.......................##.......................................................
................................................................................
................................................................................
................................................................................

Something more complex: Drawing the Mandelbrot Set#

$$z_0=0, z_{n+1} = z_n^2 + c; c \in \mathbb{M} \iff \lim_{n \to \infty} |z_n| \leq 2 $$

canvas_width = 60
canvas_height = 24
xs = -2.0
xe = 0.75
ys = -1.25
ye = 1.25
dx = (xe - xs) / canvas_width
dy = (ye - ys) / canvas_height

text = ""

for y in range(canvas_height):
    for x in range(canvas_width):
        xc = xs + x * dx
        yc = ys + y * dy
        c0 = complex(xc, yc)
        c = c0

        for iteration in range(20):
            c = c**2 + c0
            if abs(c) > 2.0:
                text += " "
                break
        else:  # good use of the else clause here. Only print a symbol if we successfully completed the for loop, not in case of a break
            text += "."
    text += "\n"

print(text)
                                                            
                                                            
                                        .                   
                                                            
                                       ....                 
                                       .....                
                               ...  ...........             
                                ....................        
                              ......................        
                             ........................       
                   .......  ..........................      
                 ...................................        
..................................................          
                 ...................................        
                   .......  ..........................      
                             ........................       
                              ......................        
                                ....................        
                               ...  ...........             
                                       .....                
                                       ....                 
                                                            
                                        .