Work the Shell - <emphasis>Yahtzee</emphasis> 作为 Shell 脚本?何时结束?
我们似乎花了很多时间讨论游戏以及如何将它们编程为 shell 脚本,不是吗?从 Blackjack 到 Baccarat,我们有将本专栏重命名为“shell 中的游戏编程”的危险。但是,那太疯狂了;谁会用 shell 脚本编写多个游戏呢?
所以,本月,我认为看看骰子游戏会很有趣,看看我们之前编写的基本纸牌游戏函数集与玩骰子游戏所需的必要函数相比如何。
Yahtzee 最初由 Hasbro 在 1956 年以 Yacht 的名字推出(由一对富裕夫妇在他们的豪华游艇上发明),并且自那时以来一直是其最畅销的名称之一,衍生出许多变体,包括手持电子游戏等等。但从本质上讲,它基本上是用骰子玩的五张牌梭哈扑克。不同之处在于,您可以掷出一定数量的可能牌型,并且您尝试实现所有这些牌型以最大化您的分数。
例如,掷出 3 4 4 4 5,您很可能会拿起 3 和 5,希望得到“四个 4”(您只能获得一次,并且希望在显示最大数量的 4 时选择),或者如果您得到五个相同的点数,即“Yahtzee”,这是一个高分奖励,但显然难以实现。
就像五张牌梭哈一样,您可以拿起零到五个骰子并重新掷骰子,但与五张牌梭哈不同,您可以在您的回合中这样做两次,而不是一次。所以,也许 3 4 4 4 5 重新掷骰子变成 1 4 4 4 4。第二次掷骰子将是重新掷骰子 1 并希望得到另一个 4。无论哪种方式,这都是一个不错的掷骰子结果(除非您已经标记了您的四个 4)。
在脚本中创建骰子非常容易——如此容易,它揭示了像吹牛骰子这样的脚本是多么简单易写
function rollDie() { dieroll=$(( ( $RANDOM % 6 ) + 1 )) }
但是,如果掷骰子这么容易(顺便说一句,骰子是 die 的复数),那么编写一个快速的 龙与地下城 骰子掷骰器也很容易,如下所示
function rollDie() { sides=${1:-6} echo "testing with a $sides-sided die...." dieroll=$(( ( $RANDOM % $sides ) + 1 )) }
您需要做的就是使用您希望骰子滚动的面数来调用 rollDie。使用 20 面骰子?试试rollDie 20看看掷出什么。
这也可以快速轻松地转换为命令行函数,因此您可以通过在旁边放一台笔记本电脑并输入以下内容来成为真正的 D&D 迷roll 20每次您实际上应该掷骰子时。
但是回到 Yahtzee,是吗?游戏建模的简单部分是掷骰子。我们需要有五个骰子,这很容易通过数组来完成
rollDie ; dice[0]=$dieroll rollDie ; dice[1]=$dieroll rollDie ; dice[2]=$dieroll rollDie ; dice[3]=$dieroll rollDie ; dice[4]=$dieroll
好了,这是您第一次掷出的五个骰子。显示结果也很容易
echo "You rolled " ${dice[0]} ${dice[1]} ${dice[2]} ${dice[3]} ${dice[4]}
请仔细注意我在哪里需要以及在哪里不需要使用花括号来使数组在 shell 中正常工作。试试这个看看有什么不同
echo "You rolled " $dice[0] $dice[1]
正如您所见,结果大相径庭。(而且,与 shell 编程一样,没有有用的警告或错误消息来提示您可能出了什么问题。)
掷骰子以获得初始手牌非常简单,所以让我们进行下一步,编写代码让您重新掷骰子两次以获得您的最终手牌。
有很多方法可以要求这种输入,但为了使其更健谈,让我们简单地以序数值呈现每个骰子,并让玩家输入相应的数字以指示应该重新掷骰子。嗯,让我向您展示我的意思
echo -n "Reroll which dice? " read answer for reroll in $answer do echo "Requested: $reroll" done
在这里,您可能会通过输入以下内容来指定您想要重新掷骰子 1 和 31 3。稍微调整一下,for 循环然后可以测试每个条目的有效性
for reroll in $answer do if [ $reroll -lt 1 -o $reroll -gt 5 ] ; then echo "Invalid entry: $reroll. Please enter 1-5" else echo "Requested: $reroll" fi done
现在,当然,是时候在这里进行一些实际的逻辑了,而不仅仅是一个基本的测试。我稍微简化了事情,通过使用数组索引 1-5 而不是 0-4,牺牲了条目 0 的位置,以便更容易处理这些值。这意味着如果您要求重新掷骰子 4,例如,它只是对 dice[4] 的重新赋值。
这是新的、改进的 for 循环
for reroll in $answer do if [ $reroll -lt 1 -o $reroll -gt 5 ] ; then echo "Invalid entry: $reroll. Please enter 1-5" else rollDie dice[$reroll]=$dieroll fi done
您可以看到它非常简单,如果我们不害怕代码稍微拉伸一点,我们可以简单地复制并粘贴其中的一些代码来显示我们掷骰子之前和之后的结果
echo -n "Your new roll: [${dice[1]}], " echo -n "[${dice[2]}], [${dice[3]}], " echo "[${dice[4]}] and [${dice[5]}]"
让我们运行一次看看发生了什么,然后在下个月,我们将开始研究实际的游戏本身,而不仅仅是掷骰子
$ ./yahtzee.sh You rolled [2], [6], [5], [2] and [1] Reroll which dice? 2 3 5 Your new roll: [2], [2], [4], [2] and [5]
是的,我偷偷地使用了方括号内显示骰子值的符号,只是为了视觉效果。正如您之前看到的那样,这使得 echo 语句有点令人困惑,但输出更具吸引力。
列表 1. yahtzee.sh
#!/bin/sh function rollDie() { sides=${1:-6} dieroll=$(( ( $RANDOM % $sides ) + 1 )) } rollDie ; dice[1]=$dieroll rollDie ; dice[2]=$dieroll rollDie ; dice[3]=$dieroll rollDie ; dice[4]=$dieroll rollDie ; dice[5]=$dieroll echo -n "You rolled [${dice[1]}], [${dice[2]}], [${dice[3]}], " echo "[${dice[4]}] and [${dice[5]}]" echo -n "Reroll which dice? " read answer for reroll in $answer do if [ $reroll -lt 1 -o $reroll -gt 5 ] ; then echo "Invalid entry: $reroll. Please enter 1-5" else rollDie dice[$reroll]=$dieroll fi done echo -n "Your new roll: [${dice[1]}], [${dice[2]}], [${dice[3]}], " echo "[${dice[4]}] and [${dice[5]}]" exit 0
yahtzee.sh 脚本也可在 LJ FTP 站点上找到,网址为 ftp.linuxjournal.com/pub/lj/listings/issue162/9819.tgz
Dave Taylor 是 UNIX 领域 26 年的资深人士,The Elm Mail System 的创建者,以及最近畅销书 Wicked Cool Shell Scripts 和 Teach Yourself Unix in 24 Hours 的作者,在他的 16 本技术书籍中。他的主要网站是 www.intuitive.com,他还提供技术支持,网址为 AskDaveTaylor.com。