I'm new to programming and in my project, I'm trying to print basic dice graphics.
I'm trying to make a function that accepts two numbers from 1 to 6, and prints corresponding two dice faces next to each other. I've tried several approaches, but this is the only one that worked, and it's quite chunky:
s="+ - - - - + + - - - - +"
m1="| o o |"
m2="| o |"
m3="| o |"
m4="| o |"
m5="| |"
def dice(a,b):
if a == 1:
str1=m5
str2=m3
str3=m5
elif a == 2:
str1=m2
str2=m5
str3=m4
elif a == 3:
str1=m2
str2=m3
str3=m4
elif a == 4:
str1=m1
str2=m5
str3=m1
elif a == 5:
str1=m1
str2=m3
str3=m1
elif a == 6:
str1=m1
str2=m1
str3=m1
if b == 1:
str1=str1+" "+m5
str2=str2+" "+m3
str3=str3+" "+m5
elif b == 2:
str1=str1+" "+m2
str2=str2+" "+m5
str3=str3+" "+m4
elif b == 3:
str1=str1+" "+m2
str2=str2+" "+m3
str3=str3+" "+m4
elif b == 4:
str1=str1+" "+m1
str2=str2+" "+m5
str3=str3+" "+m1
elif b == 5:
str1=str1+" "+m1
str2=str2+" "+m3
str3=str3+" "+m1
elif b == 6:
str1=str1+" "+m1
str2=str2+" "+m1
str3=str3+" "+m1
print(s)
print(str1)
print(str2)
print(str3)
print(s)
Is there a more compact and elegant way to do this?
You're attempt shows already some good parts: finding common parts, and store these in separate variables.
But we can do a better job by implementing a single function that generates one die. For example:
s ="+ - - - - +"
m1="| o o |"
m2="| o |"
m3="| o |"
m4="| o |"
m5="| |"
dice = [
[m5, m3, m5],
[m2, m5, m4],
[m2, m3, m4],
[m1, m5, m1],
[m1, m3, m1],
[m1, m1, m1]
]
so now we can make a function for one die with:
def die(i):
return [s, *dice[i-1], s]
This will, for a given i
in the range, return a list containing three strings.
We can then make function that joins the lines together, like:
def join_row(*rows):
return [' '.join(r) for r in zip(*rows)]
So now for two dice, we can define a function like:
def twodice(a, b):
for line in join_row(die(a), die(b)):
print(line)
The nice thing is that we can generalize this for any number of dice, for example:
def ndice(*ns):
for line in join_row(*map(die, ns)):
print(line)
For example:
>>> ndice(3, 2, 5, 1)
+ - - - - + + - - - - + + - - - - + + - - - - +
| o | | o | | o o | | |
| o | | | | o | | o |
| o | | o | | o o | | |
+ - - - - + + - - - - + + - - - - + + - - - - +
>>> ndice(1)
+ - - - - +
| |
| o |
| |
+ - - - - +
>>> ndice(1, 4)
+ - - - - + + - - - - +
| | | o o |
| o | | |
| | | o o |
+ - - - - + + - - - - +
>>> ndice(1, 4, 2)
+ - - - - + + - - - - + + - - - - +
| | | o o | | o |
| o | | | | |
| | | o o | | o |
+ - - - - + + - - - - + + - - - - +
>>> ndice(1, 4, 2, 5)
+ - - - - + + - - - - + + - - - - + + - - - - +
| | | o o | | o | | o o |
| o | | | | | | o |
| | | o o | | o | | o o |
+ - - - - + + - - - - + + - - - - + + - - - - +
A nice thing of this approach is that you get a lot of utility functions with this that you can reuse for similar problems. Furthermore each function does simple things, and thus the odds that there are huge problems with one of the functions is rather "low". If problems occur, it is typically easy to fix these.
Although you could do something really fancy, for such a relatively simple case something like this using some hardcoded data would be probably be fine (and changing how they look would also be very easy to do):
DICE_DATA = """\
+ - - - - +,+ - - - - +,+ - - - - +,+ - - - - +,+ - - - - +,+ - - - - +
| |,| o |,| o |,| o o |,| o o |,| o o |
| o |,| |,| o |,| |,| o |,| o o |
| |,| o |,| o |,| o o |,| o o |,| o o |
+ - - - - +,+ - - - - +,+ - - - - +,+ - - - - +,+ - - - - +,+ - - - - +
"""
faces = [[] for _ in range(6)]
for line in DICE_DATA.splitlines():
for i, section in enumerate(line.split(',')):
faces[i].append(section)
for face in faces:
print('\n'.join(face)) # Print a single face.
Output:
+ - - - - +
| |
| o |
| |
+ - - - - +
+ - - - - +
| o |
| |
| o |
+ - - - - +
+ - - - - +
| o |
| o |
| o |
+ - - - - +
+ - - - - +
| o o |
| |
| o o |
+ - - - - +
+ - - - - +
| o o |
| o |
| o o |
+ - - - - +
+ - - - - +
| o o |
| o o |
| o o |
+ - - - - +
Here is a way that's definitely more compact:
print("\u2680\u2681\u2682\u2683\u2684\u2685")
prints:
⚀⚁⚂⚃⚄⚅
There are already Unicode symbols for that! Just save them in a string, and when asked to give i
-th die, return the i-1
-th character:
def die(i):
return "\u2680\u2681\u2682\u2683\u2684\u2685"[i - 1]
def dice(i, j):
print(f"{die(i)}{die(j)}")
Example:
>>> dice(2, 3)
⚁⚂
You can write the string representations of all dice as a dictionary, with the keys from 1 to 6. As value, you can use a list of strings, composing the dice.
When printing, you pick lines from each set of values, according to the keys.
As on how to create the dictionaries, the approach can be like the one you took there, but it is made at once, without all the if
s -
s= "+ - - - - +"
m1="| o o |"
m2="| o |"
m3="| o |"
m4="| o |"
m5="| |"
die = {
1: [s, m5, m3, m5, s],
2: ...,
...
6: [s, m2, m2, m2, s]
}
def print_dice(a, b):
for part1, part2 in zip(die[a], die[b)):
print (part1, part2)
The zip
is responsible for, given two or more sequences or iterators, pick an element from each and yield a tuple with each element. The print function itself can print both parts of the dices.
And if insetead of two dices you want any number of them, you just have to use the "*" syntax in Python, it will work both in the function parameters, in the call to zip, and call to print:
def print_n_dice(*args):
for parts in zip(*(die[x] for x in args)):
print(*parts)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With