Skip to content

Instantly share code, notes, and snippets.

@programus
Created August 3, 2014 15:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save programus/c2dbb5c9f3d6b10a61e0 to your computer and use it in GitHub Desktop.
Save programus/c2dbb5c9f3d6b10a61e0 to your computer and use it in GitHub Desktop.
Hit plane game in shell script
#!/bin/sh
HIT="X"
BLANK="."
function printBanner()
{
echo "****************************"
echo "* PLANE *"
echo "****************************"
}
function generatePlanes()
{ # 随机生成飞机位置
local num=$1
if [[ ! -n $num ]] || echo $num | grep '[^0-9]' > /dev/null
then
num=3
fi
# 准备一个池,包含了00-99的所有数字
local pool=($(seq -w 0 99))
unset plane[@]
for ((i = 0; i < $num; i++))
do
# 随机抽取一个数字作为飞机坐标
let local pick=${RANDOM}%${#pool[@]}
local plane[$i]=${pool[$pick]}
# 删除抽取走的数字,重新构建池
pool=(${pool[@]:0:$pick} ${pool[@]:$((pick+1))})
done
echo ${plane[@]}
}
function generateSky()
{ # 生成空白天空
yes $BLANK|head -100|tr '\n' ' '
}
function getIndex()
{ # 根据二维坐标计算一维数组序号
if [[ -n $3 ]]
then
local w=$3
else
local w=10
fi
local x=$1
local y=$2
echo $((x+y*w))
}
function showSky()
{ # 显示天空状况
local sky=($*)
# 打印y坐标值
echo " $(seq 0 9|tr '\n' ' ')"
# 打印分割线
echo " +$(yes "-"|head -19|tr -d '\n')+"
for y in $(seq 0 9)
do
for x in $(seq 0 9)
do
# 取得每行数据
local i=$(getIndex $x $y)
local line[$x]=${sky[$i]}
done
# 打印每行内容
printf "$y |%s|\n" "${line[*]}"
done
# 打印分割线
echo " +$(yes "-"|head -19|tr -d '\n')+"
}
function split2Char()
{ # 将字符串分离为空格分隔的字符
echo $*|sed 's/./& /g'
}
function isValidPosition()
{ # 检查位置信息是否合法
# 必须为两个一位数
[[ $# -eq 2 ]] && echo $*|grep '^[0-9] [0-9]$' > /dev/null
}
function readPosition()
{ # 从stdin读取坐标数据,数据合法时返回坐标数据
read -p 'You hit: ' input
local pos=$(split2Char $input)
isValidPosition $pos && echo $pos
}
function abs()
{
local result=$1
if [[ $1 -lt 0 ]]
then
result=$((-result))
fi
echo $result
}
function updateSky()
{ # 更新天空数据
local x=${101}
local y=${102}
local sky=($(echo $*|cut -d ' ' -f 1-100))
local planes=($(echo $*|cut -d ' ' -f 103-))
local i=$(getIndex $x $y)
local index=0
for plane in ${planes[@]}
do
# 抽取飞机坐标
local px=${plane:0:1}
local py=${plane:1:2}
# 计算距离:距离=max(dx, dy)
local distance[$((index++))]=$(echo $(abs $((px-x))) $(abs $((py-y)))|tr ' ' '\n'|sort -n|tail -1)
done
# 取得最近飞机距离
local r=$(echo ${distance[@]}|tr ' ' '\n'|sort -n|head -1)
if [[ r -eq 0 ]]
then
r=$HIT
fi
sky[$i]=$r
echo ${sky[@]}
}
function game()
{ # 开始一次游戏
# 从参数取得飞机数,默认为3
if [[ -n $1 ]] && echo $1|grep '^[0-9]\{1,2\}$' > /dev/null
then
local num=$1
else
local num=3
fi
local planes=$(generatePlanes $num)
local sky=$(generateSky)
local step=0
# 要羞辱中途退出的懦夫
trap 'echo;echo "You lose because you aborted!";exit' INT
# 正式开始游戏,给出信息提示
echo "There are $num planes. "
echo "Shoot them down!"
while [[ 1 = 1 ]]
do
((step++))
showSky ${sky}
printf "[%3d]" $step
# 让玩家输入坐标
until pos=$(readPosition)
do
# 格式错误时给出提示
echo "Position format wrong!"
echo "Please input a valid position in format x y."
done
# 输出分割线
echo $(yes "="|head -23|tr -d '\n')
# 根据玩家输入更新天空信息
sky=$(updateSky $sky $pos $planes)
# 统计击落飞机数
hitCount=$(echo $sky|tr ' ' '\n'|grep -c $HIT)
if [[ hitCount -eq $num ]]
then
# 全部击落时,宣告胜利
showSky ${sky}
echo "You Win after $step steps!"
break
fi
done
trap - INT
}
printBanner
until [[ $exit ]]
do
game $1
echo "-----"
select sel in "Play again?" "Exit"
do
case $sel in
Exit)
exit=1
break;;
*)
echo "====="
break;;
esac
done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment