脚本编程之骰子游戏
创始人
2024-03-01 21:52:01
0

Bunco:一个使你的“快艇”游戏看起来更复杂的掷骰子游戏。

我已经有段时间没有编写游戏了,所以我觉得现在正是做一些这方面事情的时候。起初,我想“用脚本编一个 Halo游戏?”(LCTT 译注:Halo,光晕系列游戏),但我后来意识到这不太可能。来编一个叫 Bunco 的简单骰子游戏吧。你也许没有听说过,不过你母亲绝对知道 —— 当一群年轻女孩聚在当地的酒吧或者小酒馆的时候,这是个很受欢迎的游戏。

游戏一共六轮,有三个骰子,规则很简单。每次投三个骰子,投出的点数要和当前的轮数数字一致。如果三个骰子都和当前的轮数一致,(比如,在第三轮三个骰子都是 3),你这一轮的分数就是 21。 如果三个骰子点数都相同但和轮数数字不同,你会得到最低的 Bunco 分数,只有 5 分。如果你投出的点数两者都不是,每一个和当前轮数相同的骰子得 1 分。

要想玩这个游戏,它还涉及到团队合作,每一队(包括赢的那队),每人付 5 美元现金,或赢家得到其他类似现金奖励,并规定什么样的情况下才是赢家,例如“最多 Buncos” 或“最大点数”的情况下胜利。在这里我会跳过这些,而只关注投骰子这一部分。

关于数学逻辑部分

在专注于编程这方面的事之前,我先简单说说游戏背后的数学逻辑。要是有一个适当重量的骰子投骰子会变得很容易,任意一个值出现概率都是 1/6。

完全随机小提示:不确定你的骰子是否每个面都是一样重量? 把它们扔进盐水里然后掷一下。YouTube 上有一些有趣的 D&D 世界的视频向你展示了怎么来做这个测试。

所以三个骰子点数一样的几率有多大? 第一个骰子 100% 会有一个值 (这儿没什么可说的),所以很简单。第二个则有 16.66% 的概率和第一个骰子的值一样,接下来第三个骰子也是一样。 但当然,总概率是三个概率相乘的结果,所以最后,三个骰子值相等的概率是 2.7%。

接下来,每个骰子和当前轮数数字相同的概率都是 16.66%。从数学角度来说:0.166 * 0.166 * 0.166 = 0.00462 。

换句话说,你有 0.46% 的可能性投出 Bunco,比 200 次中出现一次的可能性还小一点。

实际上还可以更难。如果你有 5 个骰子,投出 Mini Bunco (也可以叫做 Yahtzee “快艇”) 的概率为 0.077%,如果你想所有的骰子的值都相同,假设都是 6,那概率就是 0.00012%,那就基本上没什么可能了。

开始编程吧

和所有游戏一样,最难的部分是有一个能生成真正的随机数的随机数发生器。这一部分在 shell 脚本中还是很难实现的,所以我需要先回避这个问题,并假设 shell 内置的随机数发生器就够用了。

不过好在内置的随机数发生器很好用。用 $RANDOM 就能得到一个 0MAXINT(32767) 之间的随机值:

$ echo $RANDOM $RANDOM $RANDOM
10252 22142 14863

为了确保产生的值一定是 1 - 6 之中的某个值,使用取余函数:

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

哦!我忘了要加 1,下面是另一次尝试:

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

下面要实现投骰子这一功能。这个函数中你可以声明一个局部变量来存储生成的随机值:

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

使用 eval 确保生成的随机数被实际存储在变量中。这一部分也很容易:

rolldie die1

这会为第一个骰子生成一个 1 - 6 之间的随机值存储到 die1 中。要掷 3 个骰子,很简单:

rolldie die1 ; rolldie die2 ; rolldie die3

现在判断下生成的值。首先,判断是不是 Bunco(3 个骰子值相同),然后是不是和当前轮数值也相同:

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

这可能是所有判断语句中最难的部分了,注意第一个条件语句中这种不常用的写法 : [ 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/Mini Bunco 就不需要再统计本轮分数了。所以整个第二部分的判断语句都要写在第一个条件语句的 else 中(为了判断 3 个骰子值是否都相同)。

把所有的综合起来,然后在命令行中输入轮数,下面是现在的脚本执行后的结果:

$ 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/Mini Bunco 出现次数所占的百分比。但是我想把这部分作为练习,留给亲爱的读者你们。不过,也许我下次会抽时间完成剩下的部分。

让我们完成这一脚本吧,还有分数统计和一次性执行 6 次投骰子(这次不用再在命令行中手动输入当前轮数了)这两个功能。这也很容易,因为只是将上面的内容整个嵌套在里面,换句话说,就是将一个复杂的条件嵌套结构全部写在了一个函数中:

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

嗯。并不是很令人满意,可能是因为它只是游戏的一次完整执行。不过,你可以将脚本执行几百几千次,记下“Game over”出现的位置,然后用一些快速分析工具来看看你在每 6 轮中有几次得分超过 3 分。(要让 3 个骰子值相同,这个概率大概在 50% 左右)。

无论怎么说,这都不是一个复杂的游戏,但是它是一个很有意思的小程序项目。现在,如果有一个 20 面的骰子,每一轮游戏有好几十轮,每轮都掷同一个骰子,情况又会发生什么变化呢?


via: http://www.linuxjournal.com/content/shell-scripting-bunco-game

作者:Dave Taylor 译者:wenwensnow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

原创 ...
文/杨剑勇 英伟达再次创出世界纪录,市值突破4万亿美元大关,换算人...
2025-07-13 15:43:18
AI赋能游戏“出海” 精准...
本报记者 丁 蓉 今年以来,多地因地制宜出台新政,支持游戏企业拓展...
2025-07-08 10:12:29
《星际:异端先知》或将颠覆...
顽皮狗新作《星际:异端先知》将带来前所未有的雄心勃勃体验。尽管目前...
2025-07-04 16:43:39
哈工大团队打造会玩Mine...
想象一下,如果有一个AI助手不仅能理解你说的话,还能看懂周围的环境...
2025-06-17 23:12:56
UL Solution 游...
IT之家 6 月 13 日消息,UL Solution 今日宣布其...
2025-06-14 06:41:07
基座模型成掣肘 AI游戏革...
AIGC浪潮席卷全球已两年多,曾被寄予厚望的游戏行业的AI应用落地...
2025-06-05 07:10:28

热门资讯

Helix:高级 Linux ... 说到 基于终端的文本编辑器,通常 Vim、Emacs 和 Nano 受到了关注。这并不意味着没有其他...
使用 KRAWL 扫描 Kub... 用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernet...
JStock:Linux 上不... 如果你在股票市场做投资,那么你可能非常清楚投资组合管理计划有多重要。管理投资组合的目标是依据你能承受...
通过 SaltStack 管理... 我在搜索Puppet的替代品时,偶然间碰到了Salt。我喜欢puppet,但是我又爱上Salt了:)...
Epic 游戏商店现在可在 S... 现在可以在 Steam Deck 上运行 Epic 游戏商店了,几乎无懈可击! 但是,它是非官方的。...
《Apex 英雄》正式可在 S... 《Apex 英雄》现已通过 Steam Deck 验证,这使其成为支持 Linux 的顶级多人游戏之...
如何在 Github 上创建一... 学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它。你知道如何使用 git 了,你有一个 G...
2024 开年,LLUG 和你... Hi,Linuxer,2024 新年伊始,不知道你是否已经准备好迎接新的一年~ 2024 年,Lin...
什么是 KDE Connect... 什么是 KDE Connect?它的主要特性是什么?它应该如何安装?本文提供了基本的使用指南。科技日...
从 Yum 更新中排除特定/某... 作为系统更新的一部分,你也许需要在基于 Red Hat 系统中由于应用依赖排除一些软件包。如果是,如...