亲自测试了一个大牛写的shell脚本,感兴趣可以看看,效果如下:

aaarticlea/png;base64,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" alt="" />

代码如下:

 #!/bin/bash

 # Tetris Game
# 10.21. xhchen<[email]xhchen@winbond.com.tw[/email]> #APP declaration
APP_NAME="${0##*[\\/]}"
APP_VERSION="1.0" #颜色定义
cRed=
cGreen=
cYellow=
cBlue=
cFuchsia=
cCyan=
cWhite=
colorTable=($cRed $cGreen $cYellow $cBlue $cFuchsia $cCyan $cWhite) #位置和大小
iLeft=
iTop=
((iTrayLeft = iLeft + ))
((iTrayTop = iTop + ))
((iTrayWidth = ))
((iTrayHeight = )) #颜色设置
cBorder=$cGreen
cScore=$cFuchsia
cScoreValue=$cCyan #控制信号
#改游戏使用两个进程,一个用于接收输入,一个用于游戏流程和显示界面;
#当前者接收到上下左右等按键时,通过向后者发送signal的方式通知后者。
sigRotate=
sigLeft=
sigRight=
sigDown=
sigAllDown=
sigExit= #七中不同的方块的定义
#通过旋转,每种方块的显示的样式可能有几种
box0=( )
box1=( )
box2=( )
box3=( )
box4=( )
box5=( )
box6=( )
#所有其中方块的定义都放到box变量中
box=(${box0[@]} ${box1[@]} ${box2[@]} ${box3[@]} ${box4[@]} ${box5[@]} ${box6[@]})
#各种方块旋转后可能的样式数目
countBox=( )
#各种方块再box数组中的偏移
offsetBox=( ) #每提高一个速度级需要积累的分数
iScoreEachLevel= #be greater than #运行时数据
sig= #接收到的signal
iScore= #总分
iLevel= #速度级
boxNew=() #新下落的方块的位置定义
cBoxNew= #新下落的方块的颜色
iBoxNewType= #新下落的方块的种类
iBoxNewRotate= #新下落的方块的旋转角度
boxCur=() #当前方块的位置定义
cBoxCur= #当前方块的颜色
iBoxCurType= #当前方块的种类
iBoxCurRotate= #当前方块的旋转角度
boxCurX=- #当前方块的x坐标位置
boxCurY=- #当前方块的y坐标位置
iMap=() #背景方块图表 #初始化所有背景方块为-, 表示没有方块
for ((i = ; i < iTrayHeight * iTrayWidth; i++)); do iMap[$i]=-; done #接收输入的进程的主函数
function RunAsKeyReceiver()
{
local pidDisplayer key aKey sig cESC sTTY pidDisplayer=$
aKey=( ) cESC=`echo -ne "\033"`
cSpace=`echo -ne "\040"` #保存终端属性。在read -s读取终端键时,终端的属性会被暂时改变。
#如果在read -s时程序被不幸杀掉,可能会导致终端混乱,
#需要在程序退出时恢复终端属性。
sTTY=`stty -g` #捕捉退出信号
trap "MyExit;" INT TERM
trap "MyExitNoSub;" $sigExit #隐藏光标
echo -ne "\033[?25l" while :
do
#读取输入。注-s不回显,-n读到一个字符立即返回
read -s -n key aKey[]=${aKey[]}
aKey[]=${aKey[]}
aKey[]=$key
sig= #判断输入了何种键
if [[ $key == $cESC && ${aKey[]} == $cESC ]]
then
#ESC键
MyExit
elif [[ ${aKey[]} == $cESC && ${aKey[]} == "[" ]]
then
if [[ $key == "A" ]]; then sig=$sigRotate #<向上键>
elif [[ $key == "B" ]]; then sig=$sigDown #<向下键>
elif [[ $key == "D" ]]; then sig=$sigLeft #<向左键>
elif [[ $key == "C" ]]; then sig=$sigRight #<向右键>
fi
elif [[ $key == "W" || $key == "w" ]]; then sig=$sigRotate #W, w
elif [[ $key == "S" || $key == "s" ]]; then sig=$sigDown #S, s
elif [[ $key == "A" || $key == "a" ]]; then sig=$sigLeft #A, a
elif [[ $key == "D" || $key == "d" ]]; then sig=$sigRight #D, d
elif [[ "[$key]" == "[]" ]]; then sig=$sigAllDown #空格键
elif [[ $key == "Q" || $key == "q" ]] #Q, q
then
MyExit
fi if [[ $sig != ]]
then
#向另一进程发送消息
kill -$sig $pidDisplayer
fi
done
} #退出前的恢复
function MyExitNoSub()
{
local y #恢复终端属性
stty $sTTY
((y = iTop + iTrayHeight + )) #显示光标
echo -e "\033[?25h\033[${y};0H"
exit
} function MyExit()
{
#通知显示进程需要退出
kill -$sigExit $pidDisplayer MyExitNoSub
} #处理显示和游戏流程的主函数
function RunAsDisplayer()
{
local sigThis
InitDraw #挂载各种信号的处理函数
trap "sig=$sigRotate;" $sigRotate
trap "sig=$sigLeft;" $sigLeft
trap "sig=$sigRight;" $sigRight
trap "sig=$sigDown;" $sigDown
trap "sig=$sigAllDown;" $sigAllDown
trap "ShowExit;" $sigExit while :
do
#根据当前的速度级iLevel不同,设定相应的循环的次数
for ((i = ; i < - iLevel; i++))
do
sleep 0.02
sigThis=$sig
sig= #根据sig变量判断是否接受到相应的信号
if ((sigThis == sigRotate)); then BoxRotate; #旋转
elif ((sigThis == sigLeft)); then BoxLeft; #左移一列
elif ((sigThis == sigRight)); then BoxRight; #右移一列
elif ((sigThis == sigDown)); then BoxDown; #下落一行
elif ((sigThis == sigAllDown)); then BoxAllDown; #下落到底
fi
done
#kill -$sigDown $$
BoxDown #下落一行
done
} #BoxMove(y, x), 测试是否可以把移动中的方块移到(x, y)的位置, 返回0则可以, 1不可以
function BoxMove()
{
local j i x y xTest yTest
yTest=$
xTest=$
for ((j = ; j < ; j += ))
do
((i = j + ))
((y = ${boxCur[$j]} + yTest))
((x = ${boxCur[$i]} + xTest))
if (( y < || y >= iTrayHeight || x < || x >= iTrayWidth))
then
#撞到墙壁了
return
fi
if ((${iMap[y * iTrayWidth + x]} != - ))
then
#撞到其他已经存在的方块了
return
fi
done
return ;
} #将当前移动中的方块放到背景方块中去,
#并计算新的分数和速度级。(即一次方块落到底部)
function Box2Map()
{
local j i x y xp yp line #将当前移动中的方块放到背景方块中去
for ((j = ; j < ; j += ))
do
((i = j + ))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
((i = y * iTrayWidth + x))
iMap[$i]=$cBoxCur
done #消去可被消去的行
line=
for ((j = ; j < iTrayWidth * iTrayHeight; j += iTrayWidth))
do
for ((i = j + iTrayWidth - ; i >= j; i--))
do
if ((${iMap[$i]} == -)); then break; fi
done
if ((i >= j)); then continue; fi ((line++))
for ((i = j - ; i >= ; i--))
do
((x = i + iTrayWidth))
iMap[$x]=${iMap[$i]}
done
for ((i = ; i < iTrayWidth; i++))
do
iMap[$i]=-
done
done if ((line == )); then return; fi #根据消去的行数line计算分数和速度级
((x = iLeft + iTrayWidth * + ))
((y = iTop + ))
((iScore += line * - ))
#显示新的分数
echo -ne "\033[1m\033[3${cScoreValue}m\033[${y};${x}H${iScore} "
if ((iScore % iScoreEachLevel < line * - ))
then
if ((iLevel < ))
then
((iLevel++))
((y = iTop + ))
#显示新的速度级
echo -ne "\033[3${cScoreValue}m\033[${y};${x}H${iLevel} "
fi
fi
echo -ne "\033[0m" #重新显示背景方块
for ((y = ; y < iTrayHeight; y++))
do
((yp = y + iTrayTop + ))
((xp = iTrayLeft + ))
((i = y * iTrayWidth))
echo -ne "\033[${yp};${xp}H"
for ((x = ; x < iTrayWidth; x++))
do
((j = i + x))
if ((${iMap[$j]} == -))
then
echo -ne " "
else
echo -ne "\033[1m\033[7m\033[3${iMap[$j]}m\033[4${iMap[$j]}m[]\033[0m"
fi
done
done
} #下落一行
function BoxDown()
{
local y s
((y = boxCurY + )) #新的y坐标
if BoxMove $y $boxCurX #测试是否可以下落一行
then
s="`DrawCurBox 0`" #将旧的方块抹去
((boxCurY = y))
s="$s`DrawCurBox 1`" #显示新的下落后方块
echo -ne $s
else
#走到这儿, 如果不能下落了
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
fi
} #左移一列
function BoxLeft()
{
local x s
((x = boxCurX - ))
if BoxMove $boxCurY $x
then
s=`DrawCurBox `
((boxCurX = x))
s=$s`DrawCurBox `
echo -ne $s
fi
} #右移一列
function BoxRight()
{
local x s
((x = boxCurX + ))
if BoxMove $boxCurY $x
then
s=`DrawCurBox `
((boxCurX = x))
s=$s`DrawCurBox `
echo -ne $s
fi
} #下落到底
function BoxAllDown()
{
local k j i x y iDown s
iDown=$iTrayHeight #计算一共需要下落多少行
for ((j = ; j < ; j += ))
do
((i = j + ))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
for ((k = y + ; k < iTrayHeight; k++))
do
((i = k * iTrayWidth + x))
if (( ${iMap[$i]} != -)); then break; fi
done
((k -= y + ))
if (( $iDown > $k )); then iDown=$k; fi
done s=`DrawCurBox ` #将旧的方块抹去
((boxCurY += iDown))
s=$s`DrawCurBox ` #显示新的下落后的方块
echo -ne $s
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
} #旋转方块
function BoxRotate()
{
local iCount iTestRotate boxTest j i s
iCount=${countBox[$iBoxCurType]} #当前的方块经旋转可以产生的样式的数目 #计算旋转后的新的样式
((iTestRotate = iBoxCurRotate + ))
if ((iTestRotate >= iCount))
then
((iTestRotate = ))
fi #更新到新的样式, 保存老的样式(但不显示)
for ((j = , i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * ; j < ; j++, i++))
do
boxTest[$j]=${boxCur[$j]}
boxCur[$j]=${box[$i]}
done if BoxMove $boxCurY $boxCurX #测试旋转后是否有空间放的下
then
#抹去旧的方块
for ((j = ; j < ; j++))
do
boxCur[$j]=${boxTest[$j]}
done
s=`DrawCurBox ` #画上新的方块
for ((j = , i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * ; j < ; j++, i++))
do
boxCur[$j]=${box[$i]}
done
s=$s`DrawCurBox `
echo -ne $s
iBoxCurRotate=$iTestRotate
else
#不能旋转,还是继续使用老的样式
for ((j = ; j < ; j++))
do
boxCur[$j]=${boxTest[$j]}
done
fi
} #DrawCurBox(bDraw), 绘制当前移动中的方块, bDraw为1, 画上, bDraw为0, 抹去方块。
function DrawCurBox()
{
local i j t bDraw sBox s
bDraw=$ s=""
if (( bDraw == ))
then
sBox="\040\040"
else
sBox="[]"
s=$s"\033[1m\033[7m\033[3${cBoxCur}m\033[4${cBoxCur}m"
fi for ((j = ; j < ; j += ))
do
((i = iTrayTop + + ${boxCur[$j]} + boxCurY))
((t = iTrayLeft + + * (boxCurX + ${boxCur[$j + ]})))
#\[y;xH, 光标到(x, y)处
s=$s"\033[${i};${t}H${sBox}"
done
s=$s"\033[0m"
echo -n $s
} #更新新的方块
function RandomBox()
{
local i j t #更新当前移动的方块
iBoxCurType=${iBoxNewType}
iBoxCurRotate=${iBoxNewRotate}
cBoxCur=${cBoxNew}
for ((j = ; j < ${#boxNew[@]}; j++))
do
boxCur[$j]=${boxNew[$j]}
done #显示当前移动的方块
if (( ${#boxCur[@]} == ))
then
#计算当前方块该从顶端哪一行"冒"出来
for ((j = , t = ; j < ; j += ))
do
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurY = -t))
for ((j = , i = -, t = ; j < ; j += ))
do
if ((${boxCur[$j]} > i)); then i=${boxCur[$j]}; fi
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurX = (iTrayWidth - - i - t) / )) #显示当前移动的方块
echo -ne `DrawCurBox ` #如果方块一出来就没处放,Game over!
if ! BoxMove $boxCurY $boxCurX
then
kill -$sigExit ${PPID}
ShowExit
fi
fi #清除右边预显示的方块
for ((j = ; j < ; j++))
do
((i = iTop + + j))
((t = iLeft + * iTrayWidth + ))
echo -ne "\033[${i};${t}H "
done #随机产生新的方块
((iBoxNewType = RANDOM % ${#offsetBox[@]}))
((iBoxNewRotate = RANDOM % ${countBox[$iBoxNewType]}))
for ((j = , i = (${offsetBox[$iBoxNewType]} + $iBoxNewRotate) * ; j < ; j++, i++))
do
boxNew[$j]=${box[$i]};
done ((cBoxNew = ${colorTable[RANDOM % ${#colorTable[@]}]})) #显示右边预显示的方块
echo -ne "\033[1m\033[7m\033[3${cBoxNew}m\033[4${cBoxNew}m"
for ((j = ; j < ; j += ))
do
((i = iTop + + ${boxNew[$j]}))
((t = iLeft + * iTrayWidth + + * ${boxNew[$j + ]}))
echo -ne "\033[${i};${t}H[]"
done
echo -ne "\033[0m"
} #初始绘制
function InitDraw()
{
clear
RandomBox #随机产生方块,这时右边预显示窗口中有方快了
RandomBox #再随机产生方块,右边预显示窗口中的方块被更新,原先的方块将开始下落
local i t1 t2 t3 #显示边框
echo -ne "\033[1m"
echo -ne "\033[3${cBorder}m\033[4${cBorder}m" ((t2 = iLeft + ))
((t3 = iLeft + iTrayWidth * + ))
for ((i = ; i < iTrayHeight; i++))
do
((t1 = i + iTop + ))
echo -ne "\033[${t1};${t2}H||"
echo -ne "\033[${t1};${t3}H||"
done ((t2 = iTop + iTrayHeight + ))
for ((i = ; i < iTrayWidth + ; i++))
do
((t1 = i * + iLeft + ))
echo -ne "\033[${iTrayTop};${t1}H=="
echo -ne "\033[${t2};${t1}H=="
done
echo -ne "\033[0m" #显示"Score"和"Level"字样
echo -ne "\033[1m"
((t1 = iLeft + iTrayWidth * + ))
((t2 = iTop + ))
echo -ne "\033[3${cScore}m\033[${t2};${t1}HScore"
((t2 = iTop + ))
echo -ne "\033[3${cScoreValue}m\033[${t2};${t1}H${iScore}"
((t2 = iTop + ))
echo -ne "\033[3${cScore}m\033[${t2};${t1}HLevel"
((t2 = iTop + ))
echo -ne "\033[3${cScoreValue}m\033[${t2};${t1}H${iLevel}"
echo -ne "\033[0m"
} #退出时显示GameOVer!
function ShowExit()
{
local y
((y = iTrayHeight + iTrayTop + ))
echo -e "\033[${y};0HGameOver!\033[0m"
exit
} #显示用法.
function Usage
{
cat << EOF
Usage: $APP_NAME
Start tetris game. -h, --help display this help and exit
--version output version information and exit
EOF
} #游戏主程序在这儿开始.
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
Usage
elif [[ "$1" == "--version" ]]; then
echo "$APP_NAME $APP_VERSION"
elif [[ "$1" == "--show" ]]; then
#当发现具有参数--show时,运行显示函数
RunAsDisplayer
else
bash $ --show& #以参数--show将本程序再运行一遍
RunAsKeyReceiver $! #以上一行产生的进程的进程号作为参数
fi

shell脚本俄罗斯方块游戏的更多相关文章

  1. shell脚本实例-游戏脚本

    http://bbs.chinaunix.net/thread-3580033-1-1.html shell游戏收集贴 #!/bin/bash # Tetris Game #APP declarati ...

  2. shell脚本小案例

    1.获取远程ftp数据到本地目录 #!/bin/bash ftp -n<<! open 135.0.24.19 user exchange exchange binary cd /idep ...

  3. 【转】shell脚本写的俄罗斯方块游戏

    亲测一个很好玩的shell脚本写的俄罗斯方块游戏,脚本来自互联网 先来讲一下思维流程 一.方块的表示 由于shell不能定义二维数组,所以只能用一维数组表示方块,俄罗斯方块主要可以分为7类,每一类方块 ...

  4. SHELL脚本编程基础知识

    SHELL脚本编程基础知识 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Linux之父Linus有一句话很经典:"Talk is cheap, show me the ...

  5. Android随笔之——用shell脚本模拟用户按键、触摸操作

    之前写过两篇关于Android中模拟用户操作的博客(其实用一篇是转载的),现在就来讲讲用shell脚本来模拟用户按键操作.本次的目标是用shell脚本打开微信并在其搜索框中搜索相关内容. 本文的模拟功 ...

  6. Shell脚本编程具体解释

    第12章 Shell脚本编程   l  Shell命令行的执行 l  编写.改动权限和运行Shell程序的步骤 l  在Shell程序中使用參数和变量 l  表达式比較.循环结构语句和条件结构语句 l ...

  7. Shell脚本2

      5 Shell传递参数 我们可以在执行 Shell 脚本时,向脚本传递参数, 脚本内获取参数的格式为:$n.n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推…… ...

  8. Linux运维之shell脚本进阶篇

    一.if语句的使用 1)语法规则 if [条件] then 指令 fi 或 if [条件];then 指令 fi 提示:分号相当于命令换行,上面两种语法等同特殊写法:if[ -f"$file ...

  9. Shell脚本应用(for、while循环语句和case分支语句)

    1.for:读取不同的变量值,逐个执行同一组命令,直到取值完毕退出,变量值以空格分隔 语法: for  变量值  in  取值列表 do 命令序列 done 2.while:重复测试某个条件,成立则执 ...

随机推荐

  1. Atitit 常用二维码对比(QR、PDF417、DM、汉信码 Aztec code maxicode

    Atitit 常用二维码对比(QR.PDF417.DM.汉信码 Aztec code maxicode DM码则更"小",可在仅仅25mm²的面积上编码30个数字.但也就是因为太小 ...

  2. ActiveMQ的集群方案对比及部署

    转载:http://blog.csdn.net/lifetragedy/article/details/51869032 ActiveMQ的集群 内嵌代理所引发的问题: 消息过载 管理混乱 如何解决这 ...

  3. 在IDEA上跑eclipse开发的J2EE项目

    Context MacOS 10.12.1 IDEA ULTIMATE 2016.2 项目使用eclipse开发 项目使用SVN进修版本管理 核心步骤 检出项目,完成基本配置 从svn检出 当项目下载 ...

  4. IL指令详细表

    名称 说明 Add 将两个值相加并将结果推送到计算堆栈上. Add.Ovf 将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上. Add.Ovf.Un 将两个无符号整数值相加,执行溢出检查,并且 ...

  5. Matlab 利用参数方程绘制空心球体

    基本原理: 实质为利用球面参数方程,利用网格化数据绘制 x=R*sin(theta)*cos(phi) y=R*sin(theta)*sin(phi) z=R*cos(theta) 绘制函数: fun ...

  6. ElasticSearch 5学习(3)——单台服务器部署多个节点

    一般情况下单台服务器只会部署一个ElasticSearch node,但是在学习过程中,很多情况下会需要实现ElasticSearch的分布式效果,所以需要启动多个节点,但是学习开发环境(不想开多个虚 ...

  7. VS2013:Unit Test 单元测试入门

    一.打开VS ,找到工具栏的“工具->扩展和更新”,添加图片内容 二.新建控制台应用程序: CalculatorDemo 三.新建类:Operation.cs,并添加方法 namespace C ...

  8. 计算机程序的思维逻辑 (53) - 剖析Collections - 算法

    之前几节介绍了各种具体容器类和抽象容器类,上节我们提到,Java中有一个类Collections,提供了很多针对容器接口的通用功能,这些功能都是以静态方法的方式提供的. 都有哪些功能呢?大概可以分为两 ...

  9. CSS3与页面布局学习总结(六)——CSS3新特性(阴影、动画、渐变、变形、伪元素等)

    CSS3在CSS2.1的基础上新增加了许多属性,这里选择了较常用的一些功能与大家分享,帮助文档中有很详细的描述,可以在本文的示例中获得帮助文档. 一.阴影 1.1.文字阴影 text-shadow&l ...

  10. angularjs之filter过滤器

    现在公司用ionic,就是基于angularjs封装了一些api用于webapp,最近用的angularjs的filter确实省了很多代码,现在总结一下! ng比较鸡肋的过滤器,这里就一笔带过吧!鸡汤 ...