吃角子老虎机掉出的硬币和骰盒里摇晃的骰子是内华达州最美妙的乐器。
文章目录
一. 骰子与柏拉图多面体
当我们想用程序模拟骰子的投掷结果时,我们绝对不想仅仅局限于酒吧骰盒里那两个小小的正方体骰子 —— 我们可以选择任意的数量,任意的投掷次数……给我们造成限制的只有两个因素:CPU的温度和柏拉图的弟子。
作为一枚合格的骰子,每一个点数出现的可能性必须是相同的。在这样的限制下,除了常见的正方体骰子之外,我们能不能做一枚七面体的骰子或者二十一面体的骰子?两千多年前,柏拉图的追随者们给出了这个问题的答案:
柏拉图将尖锐的正四面体视作火,将可以完美堆砌的正方体视作土,将更加复杂的正八面体和正二十面体视作空气和水,而他的徒弟亚里士多德则将正十二面体视作构成世界的另一种元素——以太。柏拉图和他的弟子们,一群伟大的哲学家和数学家,他们的研究除了带给我们原始的哲学观念之外,还证明了这样一个事实:正多面体只有五种,即正四面体、正六面体、正八面体、正十二面体和正二十面体,又或者是火、土、空气、水与以太。
这些两千多年前的结论将骰子的形状限制在了一个狭小的范围,也使得我们的程序无法选择像是七面体或者二十一面体来作为合格的骰子。不过,虽然七面体的骰子很难想象,也绝对不可能用在拉斯维加斯的牌桌上,但我们可以在程序中模拟这些奇怪的骰子,看看他们和正常的骰子比起来有什么不同的地方。
下面,让我们用Python来实现这些模拟。
二. 核心:模拟骰子的投掷过程
1. 创造骰子
想要模拟骰子的投掷,我们首先需要模拟一个骰子出来 —— Python提供的面向对象的编程方法为这类想要模拟一个实物出来的任务提供了优秀的支持。我们只需要想一想,一个骰子有哪些关键的特点?骰子的材质或者颜色我们不需要关心,我们要的抽象骰子只要有点数、可以投掷出结果就行了。有了这些准备,我们可以很容易的创建出一个骰子出来:
import random
class Dice(object):
'创建一个类表示骰子'
def __init__(self,num_of_surface):
'初始化:指定骰子的面数'
self.num_of_surface = num_of_surface
def throw(self):
'方法:投掷一次骰子'
return random.randint(1,self.num_of_surface)
在这段代码中,我们用了random库中的randint方法,用来产生伪随机数去表示投掷的结果。这段代码很简单,但我们已经创造出一个强大的虚拟骰子 —— 我们可以让这个骰子拥有任意的面数,从柏拉图立方体到无法想象的一千个面的骰子。
我们先试着抛掷一个常见的正方体骰子,看看代码能不能正常工作:
if __name__ == '__main__':
dice = Dice(6)
result = [dice.throw() for _ in range(6)]
print(result)
这段代码将一枚正方体骰子投掷了六遍,结果是[4, 1, 5, 6, 2, 5]:投出了从1点到6点的几个结果,都很正常。
2. 创造骰盒
现在,我们有了一个可以用的骰子,但是我们想做的是投掷多个骰子 —— 可能只有两个,也可能有两百个。假如我们想看看投掷两百个骰子的结果,将一个骰子投掷两百次似乎很愚蠢。让我们来做一个骰盒解决这个问题:
class DiceBox(Dice):
'创建一个类表示有许多骰子的骰盒'
def __init__(self,num_of_surface,num_of_dice):
'初始化:指定骰子的面数以及骰盒中骰子的个数'
self.num_of_surface = num_of_surface
self.num_of_dice = num_of_dice
def rolldicebox(self):
'方法:摇骰盒'
return [self.throw() for _ in range(self.num_of_dice)]
在这段代码中,我们创建了一个骰盒 —— 骰盒里有许多骰子,我们只需要指定好骰盒里骰子的面数和个数,然后摇晃一次骰盒就可以获得想要的结果。用来代表骰盒的DiceBox类继承了我们之前用来表示一个骰子的Dice类,新增的rolldicebox方法使用了之前的throw方法。
这个骰盒的使用方法很简单: