Bash Shell 游戏:我们来玩钓鱼游戏!
如何开始开发流行的纸牌游戏的计算机版本。
在我之前为Linux Journal撰写的163篇专栏文章以及在创作我的Wicked Cool Shell Scripts书期间编程和探索的数十个游戏中,我已经编写了很多 Bash shell 游戏。挑战在于找到一个足够简单的,可以使用 shell 脚本实现,但又不会太简单以至于最终只有六行代码的游戏。
魔法 8 球是一个完美的例子。事实证明,整个“预测未来”的小玩意实际上只是一个漂浮在深紫色液体中的 20 面骰子。因此,一个包含 20 个可能值的数组和一个随机数选择器,砰——你就得到了一个魔法 8 球脚本
#!/bin/sh
# magic 8 ball. Yup. Pick a random number, output message
# messages harvested from the Wikipedia entry
answers=("It is certain." "It is decidedly so."
"Without a doubt." "Yes - definitely."
"You may rely on it." "As I see it, yes." "Most likely."
"Outlook good." "Yes." "Signs point to yes."
"Reply hazy, try again." "Ask again later."
"Better not tell you now." "Cannot predict now."
"Concentrate and ask again." "Don't count on it."
"My reply is no." "My sources say no."
"Outlook not so good." "Very doubtful.")
echo "Oh! Magic 8 Ball, Please Tell Me True..." ; echo ""
/bin/echo -n "What is your question? "
read question
answer=$(( $RANDOM % 20 ))
echo ""
echo "I have looked into the future and I say: "
echo " ${answers[$answer]}" ; echo ""
exit 0
让我们快速运行一下,看看我是否是最受欢迎的LJ作者
$ sh magic8.sh
Oh! Magic 8 Ball, Please Tell Me True...
What is your question? Am I the most popular LJ writer?
I have looked into the future and I say:
My reply is no.
哎哟,真苛刻。我写了这个该死的占卜程序,结果却砸了自己的脚。唉。
更严肃地说,魔法 8 球太简单了,无法制作成有趣的 shell 脚本。相比之下,使命召唤太复杂了,即使我做了一个文本输出版本而不是华丽的 3D 图形。
纸牌游戏函数库这就是为什么纸牌游戏被证明是很好的编程挑战或练习的原因:52 张牌的随机牌组的核心机制非常简单,所以关键在于实际的纸牌玩法。
不仅如此,正如我之前写过的关于纸牌游戏作为 shell 脚本的文章,我已经有一套方便的函数来创建、洗牌和显示牌组中的牌。如果您想在档案中查找,我已经处理过 Acey-Deucey、百家乐 和一些 Cribbage 的片段。
为了直接进入我将要描述如何构建的新游戏钓鱼游戏!,让我们从我之前的脚本中借用以下函数
-
initializeDeck
-
shuffleDeck
-
pickCard
-
showCard
我已经将脚本库上传到我的 AskDaveTaylor 网站,如果您愿意,可以在这里获取。
有了这些可用的函数,让我们开始编写一个钓鱼游戏!游戏。
前往钓鱼场如果您没有孩子,那么您可能已经很久没有玩过简单的钓鱼游戏!了。我会将其归类为记忆游戏,因为如果您能记住对方玩家问了什么,您通常会赢得比赛。
钓鱼游戏!非常简单。每个玩家开始时都有七张牌,他们轮流询问对方玩家是否有一张或多张特定牌值的牌。如果他们有,他们会交出所有该牌值的牌。如果他们没有,那么您就“钓鱼”,并从牌组中取走最上面的一张牌。
一旦您有四张相同牌值的牌,您应立即将它们放在您面前。如果您手中没有任何牌,您应立即从牌组中抽取两张牌,然后继续游戏。当两个人的手中都没有牌并且牌组中也没有牌时,游戏结束。获胜者是在游戏结束时拥有更多套牌的人。这很简单。
注意:当有三到四个玩家时,游戏会变得更加有趣。试试看!
要开始,这里有一种从另一个文件包含一组函数的简单方法
cardlib="playing-card-library.sh"
if [ ! -f $cardlib ] ; then
echo "Can't find the playing card library $cardlib"
exit 1
fi
. $cardlib
在“.”source 语句之前的条件测试可能是多余的,但是为什么不设置一个友好的错误消息,以防找不到 cardlib 文件呢?
source 语句(在不同的 shell 中语法略有不同)很有趣。它读取指定的文件,就好像其内容是当前文件的一部分一样。这意味着文件中的任何函数、任何变量、任何内容都将合并到当前 shell 中,而不是子 shell 中(例如,如果您使用 sh $cardlib
,就会发生这种情况)。
现在函数已经定义好了,是时候给电脑玩家和用户各发七张牌了。为了跟踪所有这些,我将使用两个数组:myhand
和 yourhand
。shell 会根据需要动态调整数组大小,这对于钓鱼游戏!来说非常棒,因为在游戏过程中您最终可能会拥有超过七张牌
i=1
while [ $i -lt 8 ] ; do
myhand[$i]=${newdeck[$i]}
yourhand[$i]=${newdeck[$(( $i + 7 ))]}
i=$(( $i + 1 ))
done
这行代码中有很多标点符号
yourhand[$i]=${newdeck[$(( $i + 7 ))]}
逐步解开它,您会记住任何数组引用都必须是 ${name[x]}
,这只是复杂性的一半。另一半是 $(( equation ))
表示法,用于在不使用子 shell 的情况下进行一些基本数学运算。基本上,这就像世界上最糟糕的发牌员,将牌 1-7 发给电脑,将 8-14 发给玩家。但如果它被洗牌了...
showCard
函数(cardlib
的一部分)有点笨拙,因为它实际上并没有输出牌名,它只是用正确的值预加载全局变量 cardname
。所以这里是如何显示一手牌
echo computer hand:
showCard ${myhand[1]} ; echo " $cardname"
showCard ${myhand[2]} ; echo " $cardname"
showCard ${myhand[3]} ; echo " $cardname"
showCard ${myhand[4]} ; echo " $cardname"
showCard ${myhand[5]} ; echo " $cardname"
showCard ${myhand[6]} ; echo " $cardname"
showCard ${myhand[7]} ; echo " $cardname"
运行这段代码,很明显我可能需要按牌值对牌进行排序,以使游戏更容易玩
$ sh gofish.sh
computer hand:
5 of Diamonds
9 of Hearts
4 of Clubs
7 of Diamonds
8 of Hearts
K of Hearts
K of Clubs
your hand:
5 of Hearts
9 of Diamonds
Q of Diamonds
2 of Spades
6 of Clubs
2 of Diamonds
Q of Spades
由于玩家永远不必指定单张牌,我认为我可以不用对牌进行排序,所以当您开始摆弄代码时,我将把它作为一项任务留给您,亲爱的读者。
不需要指定牌?没错。您将通过在提示符下输入“2”来询问计算机是否有任何,例如,“二”。事实上,为了让这更有趣,让我们让玩家有可能通过让电脑询问他们是否有一张特定的牌来作弊,而不是自动从手中取出牌。
我设想了这样的游戏流程
Your hand:
5 of Hearts
9 of Diamonds
Q of Diamonds
2 of Spades
6 of Clubs
2 of Diamonds
Q of Spades
You go first. You ask me if I have: 3
** You don't have any 3s so you can't ask for that!
You ask me if I have: 2
** I do not. Go fish.
(( you pick up the 9 of Hearts ))
My turn. Do you have any 7s? (yes/no):
考虑到这一点,我们先到此为止,下次再继续这个编码项目。到时见,与此同时,找个年轻人玩几局钓鱼游戏!,看看这个游戏(诚然相当简单)的细微之处。