Shell 脚本:地下城、龙与骰子
地下城、龙与骰子——一个脚本,让你可以掷出那些令人惊讶的许多游戏所需的 3d6 和 2d20 骰子。
在我的上一篇文章中,我谈到了一个非常简单的 shell 脚本,用于一个名为 Bunco 的游戏,这是一种骰子游戏,在回合中进行,你掷三个骰子,并将你的值与回合数进行比较。如果三个都匹配并且匹配回合数,你就得到了 25 分的 bunco。否则,任何与回合匹配的骰子都值一分。这很简单——一个为在当地酒吧喝得醉醺醺的人们设计的游戏,而且也很容易编程。
Bunco 程序的核心功能是生成 1-6 之间随机数的函数,以模拟掷六面骰子。它看起来像这样
rolldie()
{
local result=$1
rolled=$(( ( $RANDOM % 6 ) + 1 ))
eval $result=$rolled
}
它以变量名作为唯一参数调用,它会将 1-6 之间的随机数加载到该值中——例如
rolldie die1
将为 $die1 分配一个值 1..6。明白了吗?
但是,如果你能做到这一点,有什么能阻止你使用第二个参数来指定你想要用该函数“掷”的骰子的面数呢?像这样
rolldie()
{
local result=$1 sides=$2
rolled=$(( ( $RANDOM % $sides ) + 1 ))
eval $result=$rolled
}
为了测试它,我们只需编写一个微小的包装器,简单地请求一个 20 面骰子 (d20) 的结果
rolldie die 20
echo resultant roll is $die
很简单。为了使其更有用,让我们允许用户使用标准的 D&D 符号 nDm 来指定一系列骰子滚动——也就是说,n 个 m 面骰子。例如,Bunco 将使用 3d6 完成(三个六面骰子)。明白了吗?
由于你很可能也有起始标志,让我们使用非常方便的 getopt
将其构建到解析循环中
while getopts "h" arg
do
case "$arg" in
* ) echo "dnd-dice NdM {NdM}"
echo "NdM = N M-sided dice"; exit 0 ;;
esac
done
shift $(( $OPTIND - 1 ))
for request in $* ; do
echo "Rolling: $request"
done
对于像 3d6 这样格式良好的符号,很容易将其参数分解为组成部分,就像这样
dice=$(echo $request | cut -dd -f1)
sides=$(echo $request | cut -dd -f2)
echo "Rolling $dice $sides-sided dice"
为了测试它,让我们给它一些参数,看看程序输出什么
$ dnd-dice 3d6 1d20 2d100 4d3 d5
Rolling 3 6-sided dice
Rolling 1 20-sided dice
Rolling 2 100-sided dice
Rolling 4 3-sided dice
Rolling 5-sided dice
啊,最后一个指出了脚本中的一个错误。如果没有指定骰子数量,默认值应为 1。理论上你也可以默认为六面骰子,但这远不如假设 1 安全。
有了这个,你就接近一个功能齐全的程序了,因为你所需要的只是一个循环来处理请求中的多个骰子。使用 while 循环很容易做到,但让我们为脚本添加一些额外的智能
for request in $* ; do
dice=$(echo $request | cut -dd -f1)
sides=$(echo $request | cut -dd -f2)
echo "Rolling $dice $sides-sided dice"
sum=0 # reset
while [ ${dice:=1} -gt 0 ] ; do
rolldie die $sides
echo " dice roll = $die"
sum=$(( $sum + $die ))
dice=$(( $dice - 1 ))
done
echo " sum total = $sum"
done
这实际上非常可靠,虽然输出语句需要稍微清理一下,但代码基本上是完全可用的
$ dnd-dice 3d6 1d20 2d100 4d3 d5
Rolling 3 6-sided dice
dice roll = 5
dice roll = 6
dice roll = 5
sum total = 16
Rolling 1 20-sided dice
dice roll = 16
sum total = 16
Rolling 2 100-sided dice
dice roll = 76
dice roll = 84
sum total = 160
Rolling 4 3-sided dice
dice roll = 2
dice roll = 2
dice roll = 1
dice roll = 3
sum total = 8
Rolling 5-sided dice
dice roll = 2
sum total = 2
你有没有注意到我修复了 $dice
没有值的情况?它被塞进了 while 语句的引用中。我没有将其称为 $dice
,而是使用了 ${dice:=1}
符号,它使用指定的值,除非它是空值或没有值,在这种情况下,值 1 被分配和使用。这很方便,并且在这种情况下是一个完美的修复。
在游戏中,你通常不太关心单个骰子的值;你只想将所有内容加起来,看看总值是多少。因此,如果你掷 4d20,例如,这只是你计算并与游戏主持人或地下城主持人分享的单个值。
稍微清理一下输出语句,你就可以做到这一点
$ dnd-dice.sh 3d6 1d20 2d100 4d3 d5
3d6 = 16
1d20 = 13
2d100 = 74
4d3 = 8
d5 = 2
让我们再次运行它,以确保你也得到不同的值
3d6 = 11
1d20 = 10
2d100 = 162
4d3 = 6
d5 = 3
肯定有不同的值,总而言之,这是一个非常有用的脚本。
你可以以此为基础创建许多变体,包括一些游戏玩家喜欢的“爆炸骰子”。这个想法很简单:如果你掷出可能的最佳值,你可以再次掷骰子并加上第二个值。掷一个 d20 并得到 20?你可以再次掷骰子,你的结果就是 20 + 第二个值。疯狂之处在于你可以多次循环执行此操作,因此 d20 可以变成 30、40 甚至 50。
这篇文章就到此为止。在这一点上,关于骰子没有什么可做的了。在我的下一篇文章中,我将看看……好吧,你必须拭目以待!别忘了,如果你有想让我处理的主题,请给我发个消息!