Bunco 游戏 Shell 脚本编写
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 ))
}
我承认,当我继续进行时,我无法抗拒一些改进,包括添加显示 Bunco
、Mini 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 面骰子,并让您每轮重新掷一颗骰子,并且有十几轮呢?