Drawing and Displaying the Dice Faces
00:00 Your goal now is to implement generating dice face ASCII diagrams, the text art that will be displayed to users. It’s going to be the most complex part of the app, but don’t stress.
00:10
We’ll roll through this lesson step by step, taking things dice and slow. Since the last lesson, I added some starting code to my version of dice.py. This DICE_ART
dictionary and the definition in docstring for generate_dice_faces_diagram()
.
00:25 Because your keyboard probably doesn’t include keys for most of these ASCII characters, it might be easier if you copy and paste from the course resources, or use the starting code file for this lesson.
00:36
Let’s look over the DICE_ART
dictionary first. This should be placed after the line importing random
. DICE_ART
is a dictionary and its keys are the integers one to six, and each key’s corresponding value is a tuple containing five strings that when viewed on subsequent lines make up the shape of their respective dice face.
00:54 The key one contains the die face with a single pip. The key two has two pips and so on, and yeah, that’s what those dots are called technically, pips. Believe me, I wouldn’t be making that up.
01:07 Okay. You’ll also want to create some constants based on this dictionary that will make things easier when you’re generating the faces and displaying the results.
01:15
DIE_HEIGHT
equals len(DICE_ART[1])
.
01:21
DIE_WIDTH
equals len(DICE_ART[1][0])
. DIE_FACE
_SEPARATOR
equals a string with a single space. DIE_
HEIGHT
holds the length of the value with the key one, which is a tuple.
01:37
The number of rows in the tuple corresponds to the height of the die. DIE_WIDTH
contains the length of the first string in the tuple of strings that make up the first die face, so it corresponds to the width of the die. DIE_FACE_
SEPARATOR
is the character you’ll be using to separate multiple dice faces, and technically these aren’t real constants.
01:55
Python doesn’t actually support constants, but it is a common pattern to treat variables like this defined in uppercase as constants. Next, you must define the generate_dice_faces_diagram()
function. To keep the function definitions more or less in order of how they’re used, you can place this after the roll_dice()
function. def
generate_dice_faces_diagram
taking in the parameter (dice_values)
and the docstring again details the behavior of the function.
02:23
Return an ASCII diagram of dice faces from dice_values
. The string return contains an ASCII representation of each die. For example, if dice_values
is the list [4, 1, 3, 2]
, then the string returned looks like this aligned with the word results padded on both sides with tildes or squigglies as I like to call them, followed by the four diagrams of the dice, 4, 1, 3, and 2.
02:51 And now you get to implement it. Before we get started, for a complex function like this, we can break it down into the steps that we’ll need to take.
02:59
First, generate a list of dice faces from DICE_ART
where you’ll retrieve the required faces.
03:06 Next, generate a list containing the dice faces rows, with each row becoming a horizontal slice of the final output.
03:14 You’ll also generate the header with the word “RESULTS” centered. And finally, combine header and rows to return output as a single string.
03:27 Pause here if you want to tackle this yourself.
03:30
Okay, let’s get started. To generate the list of dice, first, create the variable dice_faces
holding an empty list. For value
in dice_
values
, iterates over the dice values returned from roll_dice()
, dice_faces.append()
the value of DICE_ART
at value
, and now dice_faces
is a list of tuples matching the roll of dice.
03:52
Define another empty list: dice_faces_rows
.
03:57
For row_index
in range(DIE_HEIGHT)
, this iterates over a range of length DIE_HEIGHT
, creating the temporary variable row_index
in each loop. Within the loop, create the empty list row_components
.
04:10
And now iterate over dice_faces
. for die
in dice_faces
, to the row_components
list append the value of die
at row_index
.
04:19
Remember, die
is going to be a tuple of strings representing a die face at each iteration. After this nested loop runs, row_components
holds a list of horizontal slices of dice faces.
04:31
Now combine those slices into a single slice by using the string method .join()
called off of the DIE_FACE_SEPARATOR
. .join()
is called off of a string and takes an iterable as an argument, in this case row_components
, and combines the elements of that iterable into one string with each element separated by the string .join()
was called from. row_string
equals DIE_FACE_
SEPARATOR.join(row_components)
.
04:54
Now append row_string
to dice_faces_rows
.
05:00
When the outer loop finishes, dice_faces_
rows
will hold a list of strings, horizontal slices or rows of the final output. Now for the header: width
equals len(dice_faces_
rows[0])
.
05:14
This is the total width of the results. diagram
_header
equals the string " RESULTS "
calling the string method .center()
, passing in the arguments width
and the tilde character.
05:26
The .center()
method is called from a string and takes two arguments. The first is the total width of the resulting string, and the second is the value used for padding both sides to get to that width, centering the original string.
05:41
Finally, dice_faces_diagram
equals the string "n"
.join()
a list containing the single element header
plus dice_faces_rows
.
05:53
This uses list concatenation to combine the header with the list of result rows, and by joining on n
, the new line character, creates one long string that when printed will display each element on a separate line.
06:06
Lastly, return dice_faces_diagram
, and that’s it. That’s the whole function. Now would be a good time to review the main logic of your app and add some final touches to bring it all together.
06:17 I might be pushing my luck, but I bet you’ll follow me to the next lesson where we’ll do just that.
Become a Member to join the conversation.