Python 中的双骰图形

Double dice graphics in Python

我是编程新手,在我的项目中,我正在尝试打印基本的骰子图形。

我正在尝试制作一个函数,它接受从 1 到 6 的两个数字,并打印相应的两个相邻的骰子面。我尝试了几种方法,但这是唯一有效的方法,而且它很笨拙:

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)

有没有更简洁优雅的方式来做到这一点?

你的尝试已经展示了一些好的部分:找到共同的部分,并将它们存储在单独的变量中。

但我们可以通过实现一个 单个 函数来生成 一个 骰子来做得更好。例如:

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]
]

所以现在我们可以为 one 创建一个函数:

def die(i):
    return [s, *dice[i-1], s]

对于范围内给定的 i,这将是一个包含三个字符串的列表 return。

然后我们可以创建行连接在一起的函数,例如:

def join_row(*rows):
    return ['   '.join(r) for r in zip(*rows)]

所以现在对于两个骰子,我们可以定义一个函数:

def twodice(a, b):
    for line in join_row(die(a), die(b)):
        print(line)

好消息是我们可以将此概括为任意数量的骰子,例如:

def ndice(*ns):
    for line in join_row(*map(die, ns)):
        print(line)

例如:

>>> 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  |
+ - - - - +   + - - - - +   + - - - - +   + - - - - +

这种方法的一个好处是,您可以获得很多 实用函数 ,您可以将它们重复用于类似的问题。此外,每个函数都做一些简单的事情,因此其中一个函数出现大问题的几率相当 "low"。如果出现问题,通常很容易解决这些问题。

您可以将所有骰子的字符串表示形式写成字典,键从 1 到 6。作为值,您可以使用字符串列表来组成骰子。

打印时,根据键从每组值中选择行。

关于如何创建字典,方法可以像您在那里采用的方法,但它是一次创建的,没有所有 ifs -

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)

zip 负责给定两个或多个序列或迭代器,从每个序列或迭代器中选择一个元素,并为每个元素生成一个元组。打印函数本身可以打印骰子的两个部分。

如果你想要任意数量的两个骰子,你只需要在 Python 中使用“*”语法,它在函数参数、zip 调用中都有效,并调用打印:

def print_n_dice(*args):
    for parts in zip(*(die[x] for x in args)):
         print(*parts)

这是主题的另一个变体。我将面部图案编码为数字字符串。

rows = (
    "+ - - - - +",
    "|  o   o  |",
    "|  o      |",
    "|    o    |",
    "|      o  |",
    "|         |",
)

faces = ['555', '535', '254', '234', '151', '131', '111']

def dice(n):
    out = [rows[0]]
    for u in faces[n]:
        out.append(rows[int(u)])
    out.append(rows[0])
    return out

def multi_dice(*nums):
    buf = [[] for _ in range(5)]
    for row, seg in zip(buf, zip(*[dice(n) for n in nums])):
        row.extend(seg)
    return '\n'.join(map('   '.join, buf))

# Test showing all 6 faces
print(multi_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  |
+ - - - - +   + - - - - +   + - - - - +   + - - - - +   + - - - - +   + - - - - +

我们可以使用列表理解将 dice 函数减少到一行:

def dice(n):
    return [rows[0]] + [rows[int(u)] for u in faces[n]] + [rows[0]]

作为奖励,如果你将 n=0 传递给 dice,你会得到一张空白的脸。

虽然你可以做一些非常奇特的事情,但对于这样一个相对简单的情况,使用一些硬编码数据可能会很好(并且改变它们的外观也很容易做到):

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.

输出:

+ - - - - +
|         |
|    o    |
|         |
+ - - - - +
+ - - - - +
|  o      |
|         |
|      o  |
+ - - - - +
+ - - - - +
|  o      |
|    o    |
|      o  |
+ - - - - +
+ - - - - +
|  o   o  |
|         |
|  o   o  |
+ - - - - +
+ - - - - +
|  o   o  |
|    o    |
|  o   o  |
+ - - - - +
+ - - - - +
|  o   o  |
|  o   o  |
|  o   o  |
+ - - - - +

不要尝试同时生成两个骰子的线条; Python 字符串处理足够强大,可以将两个行块连接在一起,使它们并排工作。专注于高效地生成骰子面。

您不需要在骰子中生成每一行。骰子是对称的;下半部分是上半部分的旋转。您可以纯粹通过一些布尔测试来创建一半,以决定是一只眼睛还是一只眼睛;这是当三只眼睛在一半(忽略中间的眼睛)时的骰子值 on:

+ - - - - - - - - - - +
| {2,3,4,5,6} {4,5,6} |
|
|     {6}

中眼是奇数的时候。因此,您可以分别用 value > 1value > 3value > 5 来确定是否存在眼睛。

下面的版本生成这样一个没有中心眼的一半,然后将两半组合起来('rotating'后半部分通过反转字符串),并在它们之间插入中间眼:

def ascii_dice(v, e=' o'):
    half = f'+ - - - - +\n|  {e[v > 1]}   {e[v > 3]}  |\n|  {e[v > 5]} '
    return f'{half}{e[v & 1]}{half[::-1]}'

这会根据需要生成 6 个骰子面中的任何一个:

>>> for i in range(1, 7):
...     print(ascii_dice(i))
...
+ - - - - +
|         |
|    o    |
|         |
+ - - - - +
+ - - - - +
|  o      |
|         |
|      o  |
+ - - - - +
+ - - - - +
|  o      |
|    o    |
|      o  |
+ - - - - +
+ - - - - +
|  o   o  |
|         |
|  o   o  |
+ - - - - +
+ - - - - +
|  o   o  |
|    o    |
|  o   o  |
+ - - - - +
+ - - - - +
|  o   o  |
|  o   o  |
|  o   o  |
+ - - - - +

接下来,将多个骰子并排组合,简单来说就是拆分多个线块,并将每个块的线分组的功能;所有第一行放在一起,第二行放在一起,依此类推,然后用 space 重新加入它们。这是 zip()str.join() 非常擅长的工作;以下函数可以连续生成任意数量的骰子:

def multi_dice(*d, sep='   '):
    zipped = zip(*(ascii_dice(v).splitlines() for v in d))
    return '\n'.join([sep.join(l) for l in zipped])

zip(*(...)) 函数在这里完成所有工作,它将每个骰子面的线(作为不带换行符的字符串列表)作为单独的参数传递,并完成第一行的所有配对,第二行等。然后我们将骰子面的这些部分与 sep 变量(默认情况下为 3 spaces)连接起来,并用换行符连接所有结果行。

现在您可以打印尽可能多的相邻骰子:

>>> print(multi_dice(*random.sample(range(1, 7), 6)))
+ - - - - +   + - - - - +   + - - - - +   + - - - - +   + - - - - +   + - - - - +
|  o      |   |  o   o  |   |  o   o  |   |  o      |   |         |   |  o   o  |
|         |   |  o   o  |   |    o    |   |    o    |   |    o    |   |         |
|      o  |   |  o   o  |   |  o   o  |   |      o  |   |         |   |  o   o  |
+ - - - - +   + - - - - +   + - - - - +   + - - - - +   + - - - - +   + - - - - +

对于您的用例,只需传入 2 个骰子值,然后打印函数 returns:

>>> print(multi_dice(4, 5))
+ - - - - +   + - - - - +
|  o   o  |   |  o   o  |
|         |   |    o    |
|  o   o  |   |  o   o  |
+ - - - - +   + - - - - +

这是一种绝对更紧凑的方法:

print("\u2680\u2681\u2682\u2683\u2684\u2685")

打印:

⚀⚁⚂⚃⚄⚅

已经有 Unicode 符号了!只需将它们保存在一个字符串中,当要求给出第 i 个骰子时,return 第 i-1 个字符:

def die(i):
  return "\u2680\u2681\u2682\u2683\u2684\u2685"[i - 1]

def dice(i, j):
  print(f"{die(i)}{die(j)}")

示例:

>>> dice(2, 3)
⚁⚂