Bunco 游戏 Shell 脚本编写

作者: Dave Taylor

Bunco — 一种让 Yatzy 看起来都复杂的骰子游戏!

操作指南, 编程, Shell 脚本编写

我已经有一段时间没有深入研究游戏编程了,所以我认为现在是时候在这个领域做点什么了。起初,我想到“用 shell 脚本编写光环游戏?”,但后来我清醒了过来。相反,让我们看看一个简单的骰子游戏 Bunco。您可能没听说过它,但我敢打赌您妈妈听说过——这是一款在当地酒吧或酒馆的女士群体中非常受欢迎的游戏。

游戏使用三颗骰子进行六轮,规则很简单。您掷出所有三颗骰子,并且需要与当前轮数相匹配。如果所有三颗骰子都与当前轮数相匹配(例如,第三轮中三个 3),您得 21 分。如果所有三个都匹配但不是当前轮数,则为迷你 Bunco,价值五分。如果两者都失败,则每个与轮数相同值的骰子值一分。

如果正确进行游戏,游戏还涉及团队、包括获胜者桌在内的多张桌子,以及通常由每个人支付 5 美元或类似的费用来玩并根据特定的获胜场景(如“最多 Bunco”或“最多积分”)资助的现金奖励。但是,我将在此处跳过该部分,而只关注骰子部分。

让我们做些数学计算

在我深入编程方面之前,让我简要谈谈游戏背后的数学原理。骰子很容易使用,因为在适当加权的骰子上,出现特定值的机会是 1:6。

随机提示:不确定您的骰子是否平衡?将它们扔进盐水中并旋转它们。YouTube 上有一些来自 D&D 世界的非常有趣的视频,展示了如何进行此测试。

那么三颗骰子具有相同值的几率是多少?第一颗骰子有 100% 的几率具有一个值(这里没有倾斜),所以这很容易。第二颗骰子有 16.66% 的几率是任何特定值,然后第三颗骰子也有相同的几率是该值,但当然,它们会相乘,因此三颗骰子大约有 2.7% 的几率都具有相同的值。

然后,这三颗骰子是当前轮数的几率是 16.66%——或者,用数学术语来说:0.166 * 0.166 * 0.166 = 0.00462。

换句话说,您有 0.46% 的几率掷出 Bunco,这比每 200 次掷三颗骰子少一点。

不过,这可能会更难。如果您使用五颗骰子玩游戏,掷出迷你 Bunco(或 Yatzy)的几率是 0.077%,如果您试图完成一个特定的值,比如只是六,那么在任何给定的掷骰中,它的可能性是 0.00012% ——也就是说,不太可能!

因此进入编码环节

与每个游戏一样,最难的部分实际上是拥有一个良好的随机数生成器,它可以生成真正的随机值。但这实际上很难在 shell 脚本中影响,因此我将避开整个问题,并假设 shell 的内置随机数生成器就足够了。

好处是它非常容易使用。只需引用 $RANDOM,您将获得一个介于 0 和 MAXINT (32767) 之间的随机值


$ echo $RANDOM $RANDOM $RANDOM
10252 22142 14863

要将其约束为 1-6 之间的值,请使用模数函数


$ echo $(( $RANDOM % 6 ))
3
$ echo $(( $RANDOM % 6 ))
0

哎呀!我忘记把它移动一位了。这是另一种尝试


$ echo $(( ( $RANDOM % 6 ) + 1 ))
6

那是掷骰子功能。让我们把它变成一个函数,您可以在其中指定您希望将生成的值作为调用的一部分的变量


rolldie()
{
   local result=$1
   rolled=$(( ( $RANDOM % 6 ) + 1 ))
   eval $result=$rolled
}

使用 eval 是为了确保在调用中指定的变量实际上被分配了计算值。它很容易使用


rolldie die1

这会将 1-6 之间的随机值加载到变量 die1 中。要掷出您的三颗骰子,这很简单


rolldie die1 ; rolldie die2 ; rolldie die3

现在测试这些值。首先,让我们测试 Bunco,其中所有三颗骰子都具有相同的值,并且它也是当前轮数的值


if [ $die1 -eq $die2 ] && [ $die2 -eq $die3 ] ; then
  if [ $die1 -eq $round ] ; then
    echo "BUNCO!"
    score=25
  else
    echo "Mini Bunco!"
    score=5
  fi

这可能是最难的测试之一,并注意在第一个条件语句中不寻常地使用了 test:[ cond1 ] && [ cond2 ]。如果您认为您也可以将其写成 cond1 -a cond2,那么您是对的。与 shell 中的许多内容一样,有不止一种方法可以获得解决方案。

代码的其余部分很简单;您只需要测试骰子是否与当前轮数值匹配


if [ $die1 -eq $round ] ; then
  score=1
fi
if [ $die2 -eq $round ] ; then
  score=$(( $score + 1 ))
fi
if [ $die3 -eq $round ] ; then
  score=$(( $score + 1 ))
fi

这里唯一需要考虑的是,如果您也获得了 Bunco 或迷你 Bunco,则您不想对骰子值与轮数进行评分,因此第二组测试都需要在第一个条件语句的 else 子句中(以查看所有三颗骰子是否具有相同的值)。

将它们放在一起并在命令行上指定轮数,这就是您此时拥有的


$ sh bunco.sh 5
You rolled: 1 1 5
score = 1
$ sh bunco.sh 2
You rolled: 6 4 3
score = 0
$ sh bunco.sh 1
You rolled: 1 1 1
BUNCO!
score = 25

这么快就 Bunco 了?好吧,正如我所说,shell 中随机数生成器的随机性可能存在轻微问题。

一旦您的脚本正常工作,您可以通过运行它几百次,然后检查 Bunco 或迷你 Bunco 的百分比来对其进行测试,但我会将此作为给您,亲爱的读者,的练习。嗯,也许我会在其他时间再回来研究它。

让我们完成这个脚本,使其累积分数并运行所有六轮,而不是在命令行上指定轮数。这很容易做到,因为它只是整个脚本的一个包装器,或者,更好的是,大的条件语句本身就变成了一个函数


BuncoRound()
{
   # roll, display, and score a round of bunco!
   # round is specified when invoked, score added to totalscore

   local score=0 ; local round=$1 ; local hidescore=0

   rolldie die1 ; rolldie die2 ; rolldie die3
   echo Round $round. You rolled: $die1 $die2 $die3

   if [ $die1 -eq $die2 ] && [ $die2 -eq $die3 ] ; then
     if [ $die1 -eq $round ] ; then
       echo "  BUNCO!"
       score=25
       hidescore=1
     else
       echo "  Mini Bunco!"
       score=5
       hidescore=1
     fi
   else
     if [ $die1 -eq $round ] ; then
       score=1
     fi
     if [ $die2 -eq $round ] ; then
       score=$(( $score + 1 ))
     fi
     if [ $die3 -eq $round ] ; then
       score=$(( $score + 1 ))
     fi
   fi

   if [ $hidescore -eq 0 ] ; then
     echo "  score this round: $score"
   fi

   totalscore=$(( $totalscore + $score ))
}

我承认,当我继续进行时,我无法抗拒一些改进,包括添加显示 BuncoMini Bunco 或分数(这就是 $hidescore 所做的)。

调用它非常容易,您将使用 for 循环


for round in {1..6} ; do
  BuncoRound $round
done

这就是目前整个程序的样子。让我们运行一次看看会发生什么


$ sh bunco.sh 1
Round 1. You rolled: 2 3 3
  score this round: 0
Round 2. You rolled: 2 6 6
  score this round: 1
Round 3. You rolled: 1 2 4
  score this round: 0
Round 4. You rolled: 2 1 4
  score this round: 1
Round 5. You rolled: 5 5 6
  score this round: 2
Round 6. You rolled: 2 1 3
  score this round: 0
Game over. Your total score was 4

哎。不太令人印象深刻,但这可能是一个典型的回合。同样,您可以运行它几百次——或几千次——只需保存“游戏结束”行,然后进行一些快速统计分析,看看在六轮中您有多少次得分超过 3 分。(使用三颗骰子掷出一个给定的值,您应该有 50% 的机会击中它。)

无论如何,这不是一个复杂的游戏,但它构成了一个有趣的小型编程项目。现在,如果他们使用 20 面骰子,并让您每轮重新掷一颗骰子,并且有十几轮呢?

Dave Taylor 长期以来一直在 UNIX 和 Linux 系统上破解 shell 脚本。他是 Learning Unix for Mac OS XWicked Cool Shell Scripts 的作者。您可以在 Twitter 上找到他 @DaveTaylor,您也可以通过他的技术问答网站联系他: Ask Dave Taylor

加载 Disqus 评论