# Pretty print dice faces from multiple rolls of multi-sided dices

In this question related to rolling multiple dices, the OP pretty prints for a single case where number of dices is less than or equal to 6. This led to me finding this code golf on "Draw dice result in ASCII", but still only 6 sides.

I wanted to extend this to at least 20 sides, and possibly some day any number of sides. This resulted in the following code which I would like reviewed for improvements and efficiency and design of ascii art.

from random import randrange

def get_dice_rolls(dice_size, number_of_rolls):
"""Returns list with number_of_rolls from a dice_size-sided dice."""

return [randrange(1, dice_size+1) for _ in range(number_of_rolls)]

def get_single_dice_face(dice_size, dice_roll, zero_based=False, eye='o '):
"""Return the full face of the roll for a dice-size sided dice."""

# Shorten roll variable, and account for zero_basing rolls
r = dice_roll if zero_based else dice_roll - 1

# Build a proper dice_str according to dice_size and roll
if dice_size > 12:
dice_str ='---------\n|' \
+  eye[r<1] + ' ' + eye[r<5]  + ' ' +  eye[r<7] + ' ' +  eye[r<3] + '|\n|' \
+  eye[r<9] + ' ' + eye[r<13] + ' ' + eye[r<15] + ' ' + eye[r<11] + '|\n|' \
+ eye[r<17] + ' ' + eye[r<19  ]

elif dice_size > 6:
dice_str = ' ------- \n|{} {} {} {}|\n|{} {}'.format(*(eye[r<i]
for i in [1, 5, 7, 3, 9, 11]))

else:
dice_str = '+-----+\n| {0} {1} |\n| {2}'.format(eye[r<1], eye[r<3], eye[r<5])

# Return mirrored dice string with changing middle to get a full face
return dice_str + eye[r&1] + dice_str[::-1]

def print_dice_rolls(dice_size, dice_rolls, zero_based=False,  max_width=72, eye='o '):
"""Pretty print all dice_rolls using dice_size-sided dice(s)."""

# Verify parameters
if dice_size > 20:
raise ValueError('Support only up to 20 sided dices')

if any(roll > dice_size for roll in dice_rolls):
raise ValueError('Roll is higher than dice size')

if len(eye) != 2:
raise ValueError('Excpected two choice for eye parameter')

# Set up some default values
dice_width = 7 if dice_size > 6 else 5
dice_lines = 7 if dice_size > 12 else 5

# Will try to collate output of multiple dice rolls into lines
# of up to max_width length
output_buffer = [''] * dice_lines

# Debug print for test purposes...
print('\n{}-sided dice{}: {}'.format(dice_size, ', zero-based' if zero_based else '', dice_rolls))

# Output the dice rolls using output_buffer
for roll in dice_rolls:

# Build a proper dice_str according to dice_size and roll
current_dice = get_single_dice_face(dice_size, roll, zero_based, eye)

# Check width of output_buffer against max_width,
# and if next line go over, then print and reset buffer
if len(output_buffer[0]) + dice_width >= 72:
for idx, line in enumerate(output_buffer):
print(line)
output_buffer[idx] = ''

# Append dice to output_buffer
for idx, line in enumerate(current_dice.split('\n')):
output_buffer[idx] += line + '  '

# Print remaining dices in output_buffer
if len(output_buffer[0]) > 0:
for line in output_buffer:
print(line)

if __name__ == '__main__':
print_dice_rolls(6, [1, 2, 3, 4, 5, 6])
print_dice_rolls(4, [1, 2, 3, 4], eye='* ')
print_dice_rolls(9, get_dice_rolls(9, 5), eye='#.')
print_dice_rolls(12, range(12), True)
print_dice_rolls(15, get_dice_rolls(15, 5), eye='*.')
print_dice_rolls(20, range(20), True)


The output of this script is with various characters used for eyes (and missing eyes) of the dice:

6-sided dice: [1, 2, 3, 4, 5, 6]
+-----+  +-----+  +-----+  +-----+  +-----+  +-----+
|     |  | o   |  | o   |  | o o |  | o o |  | o o |
|  o  |  |     |  |  o  |  |     |  |  o  |  | o o |
|     |  |   o |  |   o |  | o o |  | o o |  | o o |
+-----+  +-----+  +-----+  +-----+  +-----+  +-----+

4-sided dice: [1, 2, 3, 4]
+-----+  +-----+  +-----+  +-----+
|     |  | *   |  | *   |  | * * |
|  *  |  |     |  |  *  |  |     |
|     |  |   * |  |   * |  | * * |
+-----+  +-----+  +-----+  +-----+

9-sided dice: [1, 8, 6, 4, 9]
-------    -------    -------    -------    -------
|. . . .|  |# # # #|  |# # . #|  |# . . #|  |# # # #|
|. .#. .|  |. ... .|  |. ... .|  |. ... .|  |. .#. .|
|. . . .|  |# # # #|  |# . # #|  |# . . #|  |# # # #|
-------    -------    -------    -------    -------

12-sided dice, zero-based: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
-------    -------    -------    -------    -------    -------
|       |  |o      |  |o      |  |o     o|  |o     o|  |o o   o|
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |      o|  |      o|  |o     o|  |o     o|  |o   o o|
-------    -------    -------    -------    -------    -------
-------    -------    -------    -------    -------    -------
|o o   o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
|   o   |  |       |  |   o   |  |o     o|  |o  o  o|  |o o o o|
|o   o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
-------    -------    -------    -------    -------    -------

15-sided dice: [9, 4, 12, 7, 8]
---------  ---------  ---------  ---------  ---------
|* * * *|  |* . . *|  |* * * *|  |* * . *|  |* * * *|
|. . . .|  |. . . .|  |* . . *|  |. . . .|  |. . . .|
|. .*. .|  |. ... .|  |. ... .|  |. .*. .|  |. ... .|
|. . . .|  |. . . .|  |* . . *|  |. . . .|  |. . . .|
|* * * *|  |* . . *|  |* * * *|  |* . * *|  |* * * *|
---------  ---------  ---------  ---------  ---------

20-sided dice, zero-based: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
---------  ---------  ---------  ---------  ---------  ---------
|       |  |o      |  |o      |  |o     o|  |o     o|  |o o   o|
|       |  |       |  |       |  |       |  |       |  |       |
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |       |  |       |  |       |  |       |  |       |
|       |  |      o|  |      o|  |o     o|  |o     o|  |o   o o|
---------  ---------  ---------  ---------  ---------  ---------
---------  ---------  ---------  ---------  ---------  ---------
|o o   o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
|       |  |       |  |       |  |o      |  |o      |  |o     o|
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |       |  |       |  |      o|  |      o|  |o     o|
|o   o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
---------  ---------  ---------  ---------  ---------  ---------
---------  ---------  ---------  ---------  ---------  ---------
|o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
|o     o|  |o o   o|  |o o   o|  |o o o o|  |o o o o|  |o o o o|
|   o   |  |       |  |   o   |  |       |  |   o   |  |o     o|
|o     o|  |o   o o|  |o   o o|  |o o o o|  |o o o o|  |o o o o|
|o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
---------  ---------  ---------  ---------  ---------  ---------
---------  ---------
|o o o o|  |o o o o|
|o o o o|  |o o o o|
|o  o  o|  |o o o o|
|o o o o|  |o o o o|
|o o o o|  |o o o o|
---------  ---------


What I would like some focus on is:

• General code review, as usual
• Possible extension to allow arbitrarily dice sizes
• Best choice for generating the dice_str in get_sincle_dice_face(). I've presented three variants
• Choice of design for framing around dices. Have presented three variants, and I don't agree with myself which I like best. Possibly the one with just spaces in the corners
• Don't like the output of 6, 7 (and 14, 15) for the 12- and 20-sided dices, as I would like for the lines with three eyes to be centered
• Best choice for dice_str based on which criteria? This SO question and this blog post present interesting thoughts on speed vs style. Nov 20, 2015 at 21:36
• @MathiasEttinger, A combination of speed, clarity and efficiency? :-) Nov 20, 2015 at 21:37

Thought I wouldn't have much to say at first, but as improvements were added, code changed slightly.

# Standard review

• Grammar: 1 die, 2 dice, 2 choices, 2 eyes

It seems that 1 dice is accepted, but I learnt the former so I’ll stick with it.

• Naming: having dice within most of variable names feels ugly to me, I’d rather simplify to face, faces, roll, rolls and so on. I have the same feeling about the use of get in functions names.
• Random: randint(a,b) is an alias to randrange(a, b+1).
• Containers: if len(output_buffer[0]) > 0 can be simplified to if output_buffer[0].
• Output length: you hardcode 72 instead of using max_width.
• Zero-based rolls: you check for it in get_single_dice_face but forgot to check it in print_dice_rolls. A 0-based roll equal to the number of faces should be invalid as well. Negative rolls too. Better convert your rolls to 0-based ones in print_dice_rolls and call get_single_dice_face with only 0-based rolls.

# Pretty printing improvement

The first step before accounting for infinite-sized dice is to simplify handling of the various ascii-arts. The steps for a generic approach will be:

• Build a template that can be used for up to limit-sized dice;
• Fill this pattern with empty or full eyes based on the roll;
• Mirror it and accound for the central eye.

The only form that can easily handle such task is the one using the generator expression:

def die_face(faces_count, roll, eyes='o '):
"""Return the full face of the roll for a faces_count-sided die."""

# Build a proper die pattern according to faces_count
if faces_count > 12:
limit, pattern = 20, '---------\n|{} {} {} {}|\n|{} {} {} {}|\n|{} {}'

elif faces_count > 6:
limit, pattern = 12, ' ------- \n|{} {} {} {}|\n|{} {}'

else:
limit, pattern = 6, '+-----+\n| {} {} |\n| {}'

# Fill the pattern with correct eye for current roll
upper_die = pattern.format(*(eyes[roll<i] for i in range(1, limit, 2)))

# Return mirrored pattern string with changing middle to get a full face
return upper_die + eyes[roll&1] + upper_die[::-1]


This lead to slightly different output, but I find them more natural (compared to the outputs for your 6 and 7):

6-sided dice: [1, 2, 3, 4, 5, 6]
+-----+  +-----+  +-----+  +-----+  +-----+  +-----+
|     |  | o   |  | o   |  | o o |  | o o |  | o o |
|  o  |  |     |  |  o  |  |     |  |  o  |  | o o |
|     |  |   o |  |   o |  | o o |  | o o |  | o o |
+-----+  +-----+  +-----+  +-----+  +-----+  +-----+

4-sided dice: [1, 2, 3, 4]
+-----+  +-----+  +-----+  +-----+
|     |  | *   |  | *   |  | * * |
|  *  |  |     |  |  *  |  |     |
|     |  |   * |  |   * |  | * * |
+-----+  +-----+  +-----+  +-----+

9-sided dice: [8, 6, 4, 6, 7]
-------    -------    -------    -------    -------
|# # # #|  |# # # .|  |# # . .|  |# # # .|  |# # # .|
|. ... .|  |. ... .|  |. ... .|  |. ... .|  |. .#. .|
|# # # #|  |. # # #|  |. . # #|  |. # # #|  |. # # #|
-------    -------    -------    -------    -------

12-sided dice, zero-based: range(0, 12)
-------    -------    -------    -------    -------    -------
|       |  |o      |  |o      |  |o o    |  |o o    |  |o o o  |
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |      o|  |      o|  |    o o|  |    o o|  |  o o o|
-------    -------    -------    -------    -------    -------
-------    -------    -------    -------    -------    -------
|o o o  |  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
|   o   |  |       |  |   o   |  |o     o|  |o  o  o|  |o o o o|
|  o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
-------    -------    -------    -------    -------    -------

15-sided dice: [4, 1, 8, 14, 14]
---------  ---------  ---------  ---------  ---------
|* * . .|  |. . . .|  |* * * *|  |* * * *|  |* * * *|
|. . . .|  |. . . .|  |. . . .|  |* * * .|  |* * * .|
|. ... .|  |. .*. .|  |. ... .|  |. ... .|  |. ... .|
|. . . .|  |. . . .|  |. . . .|  |. * * *|  |. * * *|
|. . * *|  |. . . .|  |* * * *|  |* * * *|  |* * * *|
---------  ---------  ---------  ---------  ---------

20-sided dice, zero-based: range(0, 20)
---------  ---------  ---------  ---------  ---------  ---------
|       |  |o      |  |o      |  |o o    |  |o o    |  |o o o  |
|       |  |       |  |       |  |       |  |       |  |       |
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |       |  |       |  |       |  |       |  |       |
|       |  |      o|  |      o|  |    o o|  |    o o|  |  o o o|
---------  ---------  ---------  ---------  ---------  ---------
---------  ---------  ---------  ---------  ---------  ---------
|o o o  |  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
|       |  |       |  |       |  |o      |  |o      |  |o o    |
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |       |  |       |  |      o|  |      o|  |    o o|
|  o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
---------  ---------  ---------  ---------  ---------  ---------
---------  ---------  ---------  ---------  ---------  ---------
|o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
|o o    |  |o o o  |  |o o o  |  |o o o o|  |o o o o|  |o o o o|
|   o   |  |       |  |   o   |  |       |  |   o   |  |o     o|
|    o o|  |  o o o|  |  o o o|  |o o o o|  |o o o o|  |o o o o|
|o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|  |o o o o|
---------  ---------  ---------  ---------  ---------  ---------
---------  ---------
|o o o o|  |o o o o|
|o o o o|  |o o o o|
|o  o  o|  |o o o o|
|o o o o|  |o o o o|
|o o o o|  |o o o o|
---------  ---------


# Handling infinite-sized dice

Now that we can generate a face based on a pattern, we can try to automatically build the pattern based on the number of faces of the die. All in all it is pretty simple. Since we are aiming for square faces, one length of the face is the square root of the number of faces and the other one should be high enougth for the die to contain at least number of faces. Modulo minor tweaks to end up with an odd number of rows so we have a central point.

Since the template is the same for all rolls of an faces_count-sized die, we can extract it, run it once, and use its result for each roll. What's best than a class whose __init__ compute the template that will be used in its face method:

from random import randint
from math import sqrt, ceil

class Die:
def __init__(self, faces_count, eyes='o ', corner='+'):
"""Compute statistics about places of eyes on a die face"""

if len(eyes) != 2:
raise ValueError('Excpected two choices for eyes parameter')

self.eyes = eyes
width = int(sqrt(faces_count))
height = ceil(faces_count/width)

# Fix lengthes for nearly square ascii-art
while height > width + 1:
width += 1
height = ceil(faces_count/width)

# Account for python 2 ceil returning float
height = int(height)
if not height % 2:
# Fix height to have a middle point
height += 1

# Values to generate a specific face
self.limit = width * height
self.faces = faces_count

# Template of the face
pattern = ' '.join('{}' for _ in range(width))
pattern = '| {} |'.format(pattern)
top = corner + ('-' * (2 * width + 1)) + corner
middle = ' '.join('{}' for _ in range(width//2))
middle = '| ' + middle + ' ' * (width % 2)
self.pattern = '\n'.join([top] + [pattern for _ in range(height//2)] + [middle])

# Size of the ascii-art
self.width = len(top)
self.height = self.pattern.count('\n') * 2 + 1

def face(self, roll):
"""Return the full face of the roll for this die.

roll is accounted in a 0-base fashion.
"""

if not (0 <= roll < self.faces):
raise ValueError('Roll is higher than die size or negative')

eye_full, eye_empty = self.eyes

# Fill the pattern with correct eye for current roll
upper_face = self.pattern.format(*(eye_empty if roll < i else eye_full
for i in range(1, self.limit, 2)))

# Return mirrored pattern string with changing middle to get a full face
return upper_face + self.eyes[roll&1] + upper_face[::-1]

def dice_rolls(faces_count, number_of_rolls):
"""Returns list with number_of_rolls from a faces_count-sided die"""

return [randint(1, faces_count) for _ in range(number_of_rolls)]

def print_dice_rolls(faces_count, rolls, zero_based=False,  max_width=72, eyes='o '):
"""Pretty print all rolls using faces_count-sided di(c)e."""

# Debug print for test purposes...
print('\n{}-sided dice{}: {}'.format(faces_count, ', zero-based' if zero_based else '', rolls))

# Set up some default values
die = Die(faces_count, eyes)
face_width = die.width

# Will try to collate output of multiple dice rolls into lines
# of up to max_width length
output_buffer = ['' for _ in range(die.height)]

# Output the dice rolls using output_buffer
# Make sure to use 0-based rolls
for roll in (r + zero_based - 1 for r in rolls):

# Flush buffer if too wide
if len(output_buffer[0]) + face_width >= max_width:
for idx, line in enumerate(output_buffer):
print(line)
output_buffer[idx] = ''

# Build a proper face according to faces_count and roll
current_face = die.face(roll)

# Append die to output_buffer
for idx, line in enumerate(current_face.split('\n')):
output_buffer[idx] += line + '  '

# Print remaining dice in output_buffer
if output_buffer[0]:
for line in output_buffer:
print(line)

if __name__ == '__main__':
print_dice_rolls(6, [1, 2, 3, 4, 5, 6])
print_dice_rolls(4, [1, 2, 3, 4], eyes='* ')
print_dice_rolls(9, dice_rolls(9, 5), eyes='#.')
print_dice_rolls(12, range(12), True)
print_dice_rolls(15, dice_rolls(15, 5), eyes='*.')
print_dice_rolls(20, range(20), True)
print_dice_rolls(49, dice_rolls(49, 5), eyes='. ')


Which outputs:

6-sided dice: [1, 2, 3, 4, 5, 6]
+-----+  +-----+  +-----+  +-----+  +-----+  +-----+
|     |  | o   |  | o   |  | o o |  | o o |  | o o |
|  o  |  |     |  |  o  |  |     |  |  o  |  | o o |
|     |  |   o |  |   o |  | o o |  | o o |  | o o |
+-----+  +-----+  +-----+  +-----+  +-----+  +-----+

4-sided dice: [1, 2, 3, 4]
+-----+  +-----+  +-----+  +-----+
|     |  | *   |  | *   |  | * * |
|  *  |  |     |  |  *  |  |     |
|     |  |   * |  |   * |  | * * |
+-----+  +-----+  +-----+  +-----+

9-sided dice: [3, 4, 4, 9, 6]
+-------+  +-------+  +-------+  +-------+  +-------+
| # . . |  | # # . |  | # # . |  | # # # |  | # # # |
| . # . |  | . . . |  | . . . |  | # # # |  | . . . |
| . . # |  | . # # |  | . # # |  | # # # |  | # # # |
+-------+  +-------+  +-------+  +-------+  +-------+

12-sided dice, zero-based: range(0, 12)
+-------+  +-------+  +-------+  +-------+  +-------+  +-------+
|       |  | o     |  | o     |  | o o   |  | o o   |  | o o o |
|       |  |       |  |       |  |       |  |       |  |       |
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |       |  |       |  |       |  |       |  |       |
|       |  |     o |  |     o |  |   o o |  |   o o |  | o o o |
+-------+  +-------+  +-------+  +-------+  +-------+  +-------+
+-------+  +-------+  +-------+  +-------+  +-------+  +-------+
| o o o |  | o o o |  | o o o |  | o o o |  | o o o |  | o o o |
|       |  | o     |  | o     |  | o o   |  | o o   |  | o o o |
|   o   |  |       |  |   o   |  |       |  |   o   |  |       |
|       |  |     o |  |     o |  |   o o |  |   o o |  | o o o |
| o o o |  | o o o |  | o o o |  | o o o |  | o o o |  | o o o |
+-------+  +-------+  +-------+  +-------+  +-------+  +-------+

15-sided dice: [15, 6, 7, 2, 15]
+---------+  +---------+  +---------+  +---------+  +---------+
| * * * * |  | * * * . |  | * * * . |  | * . . . |  | * * * * |
| * * * . |  | . . . . |  | . . . . |  | . . . . |  | * * * . |
| . .*. . |  | . ... . |  | . .*. . |  | . ... . |  | . .*. . |
| . * * * |  | . . . . |  | . . . . |  | . . . . |  | . * * * |
| * * * * |  | . * * * |  | . * * * |  | . . . * |  | * * * * |
+---------+  +---------+  +---------+  +---------+  +---------+

20-sided dice, zero-based: range(0, 20)
+---------+  +---------+  +---------+  +---------+  +---------+
|         |  | o       |  | o       |  | o o     |  | o o     |
|         |  |         |  |         |  |         |  |         |
|    o    |  |         |  |    o    |  |         |  |    o    |
|         |  |         |  |         |  |         |  |         |
|         |  |       o |  |       o |  |     o o |  |     o o |
+---------+  +---------+  +---------+  +---------+  +---------+
+---------+  +---------+  +---------+  +---------+  +---------+
| o o o   |  | o o o   |  | o o o o |  | o o o o |  | o o o o |
|         |  |         |  |         |  |         |  | o       |
|         |  |    o    |  |         |  |    o    |  |         |
|         |  |         |  |         |  |         |  |       o |
|   o o o |  |   o o o |  | o o o o |  | o o o o |  | o o o o |
+---------+  +---------+  +---------+  +---------+  +---------+
+---------+  +---------+  +---------+  +---------+  +---------+
| o o o o |  | o o o o |  | o o o o |  | o o o o |  | o o o o |
| o       |  | o o     |  | o o     |  | o o o   |  | o o o   |
|    o    |  |         |  |    o    |  |         |  |    o    |
|       o |  |     o o |  |     o o |  |   o o o |  |   o o o |
| o o o o |  | o o o o |  | o o o o |  | o o o o |  | o o o o |
+---------+  +---------+  +---------+  +---------+  +---------+
+---------+  +---------+  +---------+  +---------+  +---------+
| o o o o |  | o o o o |  | o o o o |  | o o o o |  | o o o o |
| o o o o |  | o o o o |  | o o o o |  | o o o o |  | o o o o |
|         |  |    o    |  | o     o |  | o  o  o |  | o o o o |
| o o o o |  | o o o o |  | o o o o |  | o o o o |  | o o o o |
| o o o o |  | o o o o |  | o o o o |  | o o o o |  | o o o o |
+---------+  +---------+  +---------+  +---------+  +---------+

49-sided dice: [11, 27, 40, 45, 11]
+---------------+  +---------------+  +---------------+
| . . . . .     |  | . . . . . . . |  | . . . . . . . |
|               |  | . . . . . .   |  | . . . . . . . |
|               |  |               |  | . . . . . .   |
|       .       |  |       .       |  |               |
|               |  |               |  |   . . . . . . |
|               |  |   . . . . . . |  | . . . . . . . |
|     . . . . . |  | . . . . . . . |  | . . . . . . . |
+---------------+  +---------------+  +---------------+
+---------------+  +---------------+
| . . . . . . . |  | . . . . .     |
| . . . . . . . |  |               |
| . . . . . . . |  |               |
| .     .     . |  |       .       |
| . . . . . . . |  |               |
| . . . . . . . |  |               |
| . . . . . . . |  |     . . . . . |
+---------------+  +---------------+


# Further improvements

• Having to input twice the number of faces for both print_dice_rolls and dice_rolls might be improve using a try .. except in print_dice_rolls to account for numeric values in rolls instead of a sequence of rolls. Meaning print_dice_rolls(6, 12) would be equivalent to print_dice_rolls(6, dice_rolls(6, 12)).
• Template could be improved with positional format arguments to start filling the corner eyes first or something alike.
• After fixing the self.height attribute to be a proper int, this does work with the minor exception of the change in displayed output for some of the basic cases. I was actually contemplating going to use a class, but didn't get around to it. Now I'm considering whether I can change the order somewhat intelligent to get the other display variant... Nov 21, 2015 at 12:36
• Regarding the zero_based in print_dice_rolls() I don't need to check it there, as it is not used before within the get_single_dice_face(). But other than that, loads of great comments on my code! Nov 21, 2015 at 12:40
• Tried pretty printing for a 25-sided die, and it does look nicer, but is a little harder to get the die value. See chat in the Nth Monitor at chat.stackexchange.com/transcript/message/25587184#25587184 for a little monologue... Downside of pretty pattern is that it is hard to generate sequence... Nov 21, 2015 at 13:36