那些令人怀念的经典游戏可是提高编程能力的好素材。今天就让我们仔细探索一番,怎么用 Bash 编写一个扫雷程序。
我在编程教学方面不是专家,但当我想更好掌握某一样东西时,会试着找出让自己乐在其中的方法。比方说,当我想在 shell 编程方面更进一步时,我决定用 Bash 编写一个扫雷游戏来加以练习。
如果你是一个有经验的 Bash 程序员,希望在提高技巧的同时乐在其中,那么请跟着我编写一个你的运行在终端中的扫雷游戏。完整代码可以在这个 GitHub 存储库中找到。
做好准备
在我编写任何代码之前,我列出了该游戏所必须的几个部分:
- 显示雷区
- 创建游戏逻辑
- 创建判断单元格是否可选的逻辑
- 记录可用和已查明(已排雷)单元格的个数
- 创建游戏结束逻辑
显示雷区
在扫雷中,游戏界面是一个由 2D 数组(列和行)组成的不透明小方格。每一格下都有可能藏有地雷。玩家的任务就是找到那些不含雷的方格,并且在这一过程中,不能点到地雷。这个 Bash 版本的扫雷使用 10x10 的矩阵,实际逻辑则由一个简单的 Bash 数组来完成。
首先,我先生成了一些随机数字。这将是地雷在雷区里的位置。控制地雷的数量,在开始编写代码之前,这么做会容易一些。实现这一功能的逻辑可以更好,但我这么做,是为了让游戏实现保持简洁,并有改进空间。(我编写这个游戏纯属娱乐,但如果你能将它修改的更好,我也是很乐意的。)
下面这些变量在整个过程中是不变的,声明它们是为了随机生成数字。就像下面的 a - g 的变量,它们会被用来计算可排除的地雷的值:
# 变量 score=0 # 会用来存放游戏分数 # 下面这些变量,用来随机生成可排除地雷的实际值 a="1 10 -10 -1" b="-1 0 1" c="0 1" d="-1 0 1 -2 -3" e="1 2 20 21 10 0 -10 -20 -23 -2 -1" f="1 2 3 35 30 20 22 10 0 -10 -20 -25 -30 -35 -3 -2 -1" g="1 4 6 9 10 15 20 25 30 -30 -24 -11 -10 -9 -8 -7" # # 声明 declare -a room # 声明一个 room 数组,它用来表示雷区的每一格。
接下来,我会用列(0-9)和行(a-j)显示出游戏界面,并且使用一个 10x10 矩阵作为雷区。(M[10][10] 是一个索引从 0-99,有 100 个值的数组。) 如想了解更多关于 Bash 数组的内容,请阅读这本书那些关于 Bash 你所不了解的事: Bash 数组简介。
创建一个叫 plough 的函数,我们先将标题显示出来:两个空行、列头,和一行 - ,以示意往下是游戏界面:
printf '\n\n' printf '%s' " a b c d e f g h i j" printf '\n %s\n' "-----------------------------------------"
然后,我初始化一个计数器变量,叫 r ,它会用来记录已显示多少横行。注意,稍后在游戏代码中,我们会用同一个变量 r ,作为我们的数组索引。 在 Bash for 循环中,用 seq 命令从 0 增加到 9。我用数字(d% )占位,来显示行号($row ,由 seq 定义):
r=0 # 计数器 for row in $(seq 0 9); do printf '%d ' "$row" # 显示 行数 0-9
在我们接着往下做之前,让我们看看到现在都做了什么。我们先横着显示 [a-j] 然后再将 [0-9] 的行号显示出来,我们会用这两个范围,来确定用户排雷的确切位置。
接着,在每行中,插入列,所以是时候写一个新的 for 循环了。这一循环管理着每一列,也就是说,实际上是生成游戏界面的每一格。我添加了一些辅助函数,你能在源码中看到它的完整实现。 对每一格来说,我们需要一些让它看起来像地雷的东西,所以我们先用一个点(. )来初始化空格。为了实现这一想法,我们用的是一个叫 is_null_field 的自定义函数。 同时,我们需要一个存储每一格具体值的数组,这儿会用到之前已定义的全局数组 room , 并用 变量 r 作为索引。随着 r 的增加,遍历所有单元格,并随机部署地雷。
for col in $(seq 0 9); do ((r+=1)) # 循环完一列行数加一 is_null_field $r # 假设这里有个函数,它会检查单元格是否为空,为真,则此单元格初始值为点(.) printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" # 最后显示分隔符,注意,${room[$r]} 的第一个值为 '.',等于其初始值。 #结束 col 循环 done
(编辑:ASP站长网)
|