不知道为什么,这个脚本和CentOS 7不兼容。
载入脚本后,用WASD键控制光标移动,按空格挖开地块,挖到的数字是地块周围的地雷数量,挖到地雷后游戏失败;
按F标记有地雷的地块,按E表示可能有地雷。已挖开的地块无法被标记。将所有地雷标记完毕后游戏胜利。
按Q键退出游戏。无论如何退出游戏,脚本都会总结扫到雷的数量和本局游戏的时间。
#!/bin/bash
# ========================================
# Author: Kide_Lee
# Date: 2023.8.15
# Blog: https://www.cnblogs.com/-zyyz-/
# ========================================
# 用户设置
# ========================================
width=8 # 界面的宽度
height=8 # 界面的高度
mineCount=10 # 地雷数量
mine="#" # 地雷样式
title="MineSweeper"
# ========================================
# 方法
# 用一维数组模拟一张二维表;
# 下面提供若干方法,使脚本能够通过查询二维坐标的方式访问数组;
# 其中横纵坐标按书写方向,从零开始计数。
# ========================================
function ReadTable() {
local x=$2
local y=$3
# matrix和field是脚本维护的两张表,
# 其分别记录了雷区信息和用户界面。
case "$1" in
matrix) local info=("${matrix[@]}") ;;
field) local info=("${field[@]}") ;;
esac
# 若读取的坐标越界或无值,则返回0;否则返回坐标对应值。
local result=${info[$(("$y" * "$width" + "$x"))]}
if [ -z "$result" ]; then
return 0
elif [ "$x" -lt 0 ]; then
return 0
elif [ "$y" -lt 0 ]; then
return 0
elif [ "$x" -ge $width ]; then
return 0
elif [ "$y" -ge $height ]; then
return 0
else
return "$result"
fi
}
function WriteTable() {
local x=$2
local y=$3
local new=$4
if [ "$x" -lt 0 ]; then
return 0
elif [ "$y" -lt 0 ]; then
return 0
elif [ "$x" -ge $width ]; then
return 0
elif [ "$y" -ge $height ]; then
return 0
fi
if [ "$1" == "matrix" ]; then
matrix["$y" * "$width" + "$x"]=$new
elif [ "$1" == "field" ]; then
field["$y" * "$width" + "$x"]=$new
fi
}
# ========================================
# 初始化
# ========================================
# 主函数
function StartGame() {
X=$(("$width" / 2 - 1))
Y=$(("$height" / 2 - 1))
size=$(("$width" * "$height"))
tput civis
# 生成雷区
for ((i = 0; i < "$size"; i++)); do
matrix+=("0")
done
# 生成界面
for ((i = 0; i < "$size"; i++)); do
field+=("10")
done
DrawField
while [ -z "$checkFirst" ]; do
DrawFocus $X $Y
IFS_back=$IFS
IFS=""
read -srn1 input
IFS=$IFS_back
case "$input" in
w | W) MoveUp ;;
a | A) MoveLeft ;;
s | S) MoveDown ;;
d | D) MoveRight ;;
f | F) MarkMatrix $X $Y 11 ;;
e | E) MarkMatrix $X $Y 12 ;;
q | Q) return 1 ;;
" ")
CreateMine
CreateNumber
startTime=$(date +%s)
CheckMatrix $X $Y
local checkFirst="yes"
;;
esac
done
}
# 绘制界面
function DrawField() {
# 绘制标题栏
tput clear
local fieldWidth=$(("$width" * 3 + 2))
local titleWidth=${#title}
if [ "$fieldWidth" -gt "$titleWidth" ]; then
tput cup 0 $(("$fieldWidth" / 2 - "$titleWidth" / 2))
echo $title
else
tput cup 0 0
echo $title
fi
# 绘制上边框
echo -n +
for ((i = 0; i < "$width"; i++)); do
echo -n "---"
done
echo +
# 绘制游戏区域
for ((i = 0; i < "$height"; i++)); do
echo -n "|"
for ((j = 0; j < "$width"; j++)); do
echo -n "[ ]"
done
echo "|"
done
# 绘制下边框
echo -n +
for ((i = 0; i < "$width"; i++)); do
echo -n "---"
done
echo +
# 增加游戏提示
echo "move: WASD check: Space"
echo "mark: F question: E quit: Q"
}
# 铺设地雷
function CreateMine() {
# 定义安全区,保证首次排雷安全
local safeFieldList=()
for x in $X-1 $X $X+1; do
for y in $Y-1 $Y $Y+1; do
x=$(("$x"))
y=$(("$y"))
local safeNum=$(("$y" * "$width" + "$x"))
if [ $safeNum -ge 0 ] || [ $safeNum -lt "$size" ]; then
safeFieldList+=("$safeNum")
fi
done
done
# 定义地雷,本质是一串不重复的随机数
local mineList=()
while [ ${#mineList[*]} -lt $mineCount ]; do
local random=$(("$RANDOM" % "$size"))
local isRepeat=false
for i in "${mineList[@]}" "${safeFieldList[@]}"; do
if [ $random == "$i" ]; then
isRepeat=true
break
fi
done
if [ $isRepeat == false ]; then
mineList+=("$random")
fi
done
# 布置地雷,在雷区中,9代表有地雷
for i in "${mineList[@]}"; do
matrix["$i"]=9
done
}
# 生成数字
function CreateNumber() {
function PutOne() {
local x=$1
local y=$2
for i in $x-1 $x $x+1; do
for j in $y-1 $y $y+1; do
local i=$(("$i"))
local j=$(("$j"))
ReadTable matrix $i $j
tmpNum=$?
if [ $tmpNum != 9 ]; then
WriteTable matrix $i $j $(("$tmpNum" + 1))
fi
done
done
}
# 遇到地雷,非地雷邻格数字+1。
for ((y = 0; y < "$height"; y++)); do
for ((x = 0; x < "$width"; x++)); do
ReadTable matrix $x $y
if [ $? == 9 ]; then
PutOne $x $y
fi
done
done
}
# ========================================
# 游戏过程
# ========================================
# 主函数
function PlayGame() {
while true; do
DrawFocus $X $Y
IFS_back=$IFS
IFS=""
read -srn1 input
IFS=$IFS_back
case "$input" in
w | W) MoveUp ;;
a | A) MoveLeft ;;
s | S) MoveDown ;;
d | D) MoveRight ;;
f | F) MarkMatrix $X $Y 11 ;;
e | E) MarkMatrix $X $Y 12 ;;
q | Q) return 1 ;;
" ")
CheckMatrix $X $Y
if [ $? == 9 ]; then
tput bel
return 2
fi
;;
esac
Judging
if [ $? == 2 ]; then
return 3
fi
done
}
# 检查雷区
function CheckCell() {
local x=$1
local y=$2
ReadTable field "$x" "$y"
local result=$?
if [ $result -ge 10 ]; then
ReadTable matrix "$x" "$y"
local result=$?
WriteTable field "$x" "$y" "$result"
Draw "$x" "$y"
elif [ $result == 0 ]; then
local result=10
fi
return "$result"
}
# 递归检查雷区
function CheckMatrix() {
local x_1=$1
local y_1=$2
local edgeList=("$x_1" "$y_1")
local edgeLength=2
while [ "$edgeLength" -gt 0 ]; do
local x=${edgeList[$edgeLength - 2]}
local y=${edgeList[$edgeLength - 1]}
unset "edgeList[$edgeLength-2]"
unset "edgeList[$edgeLength-1]"
CheckCell "$x" "$y"
local result=$?
if [ $result == 0 ]; then
for i in $x-1 $x $x+1; do
for j in $y-1 $y $y+1; do
local i=$(("$i"))
local j=$(("$j"))
edgeList+=("$i" "$j")
done
done
fi
local edgeLength=${#edgeList[@]}
done
# 提供返回值
ReadTable field "$x_1" "$y_1"
return $?
}
# 渲染界面
# 本函数同时仅能渲染一个格子。
function Draw() {
local x=$1
local y=$2
ReadTable field "$x" "$y"
local result=$?
case "$result" in
0) display=" " ;;
9) display="$(tput setaf 1) ${mine} $(tput sgr0)" ;;
10) display="[ ]" ;;
11) display="$(tput setaf 2)[F]$(tput sgr0)" ;;
12) display="$(tput setaf 3)[?]$(tput sgr0)" ;;
*) display="$(tput setaf $((8 - "$result"))) ${result} $(tput sgr0)" ;;
esac
tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
echo -n "$(tput sgr0)${display}"
}
# 渲染焦点
function DrawFocus() {
local x=$1
local y=$2
if [ "$old_X" ]; then
Draw "$old_X" "$old_Y"
fi
Draw "$x" "$y"
tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
echo -n "$(tput rev)${display}"
old_X=$1
old_Y=$2
}
# 标记雷区
function MarkMatrix() {
local x=$1
local y=$2
local mark=$3
ReadTable field "$x" "$y"
local fieldChar=$?
if [ $fieldChar == "$mark" ]; then
WriteTable field "$x" "$y" 10
elif [ $fieldChar -gt 9 ]; then
WriteTable field "$x" "$y" "$mark"
fi
}
# 移动
function MoveUp() {
Y=$(("$Y" - 1))
if [ $Y -lt 0 ]; then
Y=$(("$Y" + "$height"))
fi
}
function MoveDown() {
Y=$(("$Y" + 1))
if [ $Y -ge $height ]; then
Y=$(("$Y" - "$height"))
fi
}
function MoveLeft() {
X=$(("$X" - 1))
if [ $X -lt 0 ]; then
X=$(("$X" + "$width"))
fi
}
function MoveRight() {
X=$(("$X" + 1))
if [ $X -ge $width ]; then
X=$(("$X" - "$width"))
fi
}
# 判断
function Judging() {
for i in "${field[@]}"; do
if [ "$i" == 10 ] || [ "$i" == 12 ]; then
return 1
fi
done
return 2
}
# ========================================
# 游戏清算
# ========================================
function ClearGame() {
endTime=$(date +%s)
Draw $X $Y
if [ "$startTime" ]; then
time=$(("$endTime" - "$startTime"))
else
time=0
fi
mineSweeper=0
if [ $result == 1 ]; then
for ((i = 0; i < ${#matrix[@]}; i++)); do
x=$(("$i" % "$width"))
y=$(("$i" / "$height"))
if [ "${matrix[$i]}" == 9 ]; then
if [ "${field[$i]}" == 11 ]; then
mineSweeper=$(("$mineSweeper" + 1))
Draw "$x" "$y"
tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
echo -n "$(tput rev)$(tput setaf 2)[F]$(tput sgr0)"
else
Draw "$x" "$y"
tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
echo -n "[${mine}]"
fi
fi
done
clearInfo="Game Exited.\nYou swept $mineSweeper mines in $time seconds."
elif [ $result == 2 ]; then
for ((i = 0; i < ${#matrix[@]}; i++)); do
x=$(("$i" % "$width"))
y=$(("$i" / "$height"))
if [ "${matrix[$i]}" == 9 ]; then
if [ "${field[$i]}" == 11 ]; then
mineSweeper=$(("$mineSweeper" + 1))
Draw "$x" "$y"
tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
echo -n "$(tput rev)$(tput setaf 2) ${mine} $(tput sgr0)"
else
Draw "$x" "$y"
tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
echo -n "$(tput rev)$(tput setaf 1) ${mine} $(tput sgr0)"
fi
fi
done
clearInfo="$(tput setaf 1)The Game Failed. \nYou swept $mineSweeper mines in $time seconds."
elif [ $result == 3 ]; then
clearInfo="$(tput setaf 2)You Win!\nYou swept all mines in $time seconds."
fi
tput cnorm
tput cup $(("$height" + 3)) 0
tput el
echo -e "$(tput rev)${clearInfo}$(tput sgr0)"
}
# ========================================
# 游戏运行
# ========================================
StartGame
result=$?
if [ $result == 0 ]; then
PlayGame
result=$?
fi
ClearGame
标签:脚本,do,shell,tput,扫雷,result,done,fi,local
From: https://www.cnblogs.com/-zyyz-/p/17635907.html