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
inget_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
dice_str
based on which criteria? This SO question and this blog post present interesting thoughts on speed vs style. \$\endgroup\$