Prev - #29 Pyramid Drawing | Table of Contents | Next - #31 Convert Integers To Strings

Exercise #30: 3D Box Drawing

drawBox(2)     +----+
                 /    /|
                /    / |
               +----+  +
              |    | /
             |    |/
            +----+

In this exercise, we’ll move from 2D ASCII art into 3D ASCII art by programmatically generating boxes at any given size.

Exercise Description

Write a drawBox() function with a size parameter. The size parameter contains an integer for the width, length, and height of the box. The horizontal lines are drawn with - dash characters, the vertical lines with | pipe characters, and the diagonal lines with / forward slash characters. The corners of the box are drawn with + plus signs.

There are no Python assert statements to check the correctness of your program. Instead, you can visually inspect the output yourself. For example, calling drawBox(1) through drawBox(5) would output the following boxes, respectively:

                                                        +----------+

                                                       /          /|

                                      +--------+      /          / |

                                     /        /|     /          /  |

                       +------+     /        / |    /          /   |

                      /      /|    /        /  |   /          /    |

           +----+    /      / |   /        /   |  +----------+     +

          /    /|   /      /  |  +--------+    +  |          |    /

  +--+   /    / |  +------+   +  |        |   /   |          |   / 

 /  /|  +----+  +  |      |  /   |        |  /    |          |  /  

+--+ +  |    | /   |      | /    |        | /     |          | /   

|  |/   |    |/    |      |/     |        |/      |          |/    

+--+    +----+     +------+      +--------+       +----------+

 

Size 1  Size 2      Size 3         Size 4            Size 5

If the argument for size is less than 1, the function prints nothing.

Try to write a solution based on the information in this description. If you still have trouble solving this exercise, read the Solution Design and Special Cases and Gotchas sections for additional hints.

Prerequisite concepts: strings, string concatenation, string replication, for loops, range()

Solution Design

This exercise is a significant leap in complexity compared to the previous rectangle, border, and pyramid drawing exercises. Nine different lines must be drawn, as well as several whitespace areas on the left side and interior of the box. However, solving this exercise is still a matter of figuring out the sizing patterns. Drawing the boxes manually in a text editor first can help you determine the pattern behind the boxes’ lines. Here are the boxes from size 1 to 5 with the lines numbered and the whitespace marked with periods (since spaces’ invisibility makes them hard to count):

                                                  ......+----1-----+

                                                  ...../........../|

                                 .....+---1----+  ..../........../.|

                                 ..../......../|  ...2..........3..4

                   ....+--1---+  ...2........3.4  ../........../...|

                   .../....../|  ../......../..|  ./........../....|

        ...+-1--+  ..2......3.4  ./......../...|  +----5-----+.....+

        ../..../|  ./....../..|  +---5----+....+  |..........|..../

..+1-+  .2....3.4  +--5---+...+  |........|.../   |..........|.../ 

.2..34  +-5--+..+  |......|../   6........7..8    6..........7..8  

+5-+.+  6....7.8   6......7.8    |........|./     |..........|./   

6..78   |....|/    |......|/     |........|/      |..........|/    

+9-+    +-9--+     +--9---+      +---9----+       +----9-----+

 

Size 1  Size 2      Size 3         Size 4            Size 5    

Because print() calls display text left-to-right and top-to-bottom, we’ll have to consider the lines and whitespace in that order. For the following descriptions, note that size is the integer parameter passed to the drawBox() function.

The box’s diagonal lines follow the pattern of having size slash characters. The box’s vertical lines follow the pattern of having size pipe characters. Meanwhile, the horizontal lines made of size * 2 dash characters. Look at the largest box on the right of the above diagram: The horizontal lines 1, 5, and 9 are made of 10 - dash characters (that is, size * 2). The diagonal lines 2, 3, and 8 are made of 5 / slash characters (that is, size). The vertical lines 4, 6, and 7 are also made of 5 | pipe characters (that is, size).

The horizontal lines 1, 5, and 9 are identical: They’re made of a + plus character, followed by size * 2 dash characters and another + plus character. Line 1 has a number of spaces to the left of the line that equals size + 1.

The interior spaces for the top and front surfaces of the box are size space characters, the same as the number of - dash characters. The interior space of the right surface of the box is trickier. For example, here’s a box with size as 5 with the right-side surface spaces marked with periods:

      +----------+

     /          /| 0 periods

    /          /.| 1 period

   /          /..| 2 periods

  /          /...| 3 periods

 /          /....| 4 periods

+----------+.....+ 5 periods

|          |..../  4 periods

|          |.../   3 periods

|          |../    2 periods

|          |./     1 period

|          |/      0 periods

+----------+


   Size 5

As you print the top surface, the right-side surface has an increasing number of spaces ranging from 0 to size - 1 before printing the | pipe character of line 4. When you print line 5, the right-side surface has exactly size spaces before printing the + plus sign for the corner. And as you print the front surface, the right-side surface has a decreasing number of spaces ranging from size - 1 to 0 before printing the / slash character of line 8.

Finally, you’ll print the + plus and - dash characters of line 9 at the bottom.

Special Cases and Gotchas

There’s nothing unexpected about printing these boxes. While there are many things to keep track of, always remember that the number of space and dash characters you print in each row is always relative to the size parameter. There will be size pipe and slash characters in each vertical line, and size * 2 dash characters in each horizontal line.

Now try to write a solution based on the information in the previous sections. If you still have trouble solving this exercise, read the Solution Template section for additional hints.

Solution Template

Try to first write a solution from scratch. But if you have difficulty, you can use the following partial program as a starting place. Copy the following code from https://invpy.com/boxdrawing-template.py and paste it into your code editor. Replace the underscores with code to make a working program:

def drawBox(size):

    # Special case: Draw nothing if size is less than 1:

    if size < ____:

        return

 

    # Draw back line on top surface:

    print(' ' * (____ + 1) + '+' + '-' * (____ * 2) + '+')

 

    # Draw top surface:

    for i in range(____):

        print(' ' * (____ - i) + '/' + ' ' * (____ * 2) + '/' + ' ' * i + '|')

 

    # Draw top line on top surface:

    print(____ + ____ * (size * 2) + ____ + ' ' * size + '+')

 

    # Draw front surface:

    for i in range(size - 1, ____, ____):

        print(____ + ' ' * (size * ____) + ____ + ' ' * i + ____)

 

    # Draw bottom lie on front surface:

    print(____ + ____ * (size * 2) + ____)

 

# In a loop, call drawBox() with arguments 1 to 5:

for i in range(1, 6):

    drawBox(i)

The complete solution for this exercise is given in Appendix A and https://invpy.com/boxdrawing.py. You can view each step of this program as it runs under a debugger at https://invpy.com/boxdrawing-debug/.

Further Reading

If you enjoy the challenge of these generative ASCII art exercises, check out https:// github.com/asweigart/programmedpatterns/. This website has several growing patterns that you can try to replicate as Python programs. For example, one such pattern looks like this:

#     #      #       #

##    ##     ##      ##

      ###    ###     ###

             ####    ####

                     #####

The first four steps of the pattern are provided. You could then write a function with a step parameter that prints the pattern at that given step. There are hundreds of patterns featured on the site.

Prev - #29 Pyramid Drawing | Table of Contents | Next - #31 Convert Integers To Strings