shell脚本实现俄罗斯方块

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

shell脚本实现俄罗斯方块相关推荐

  1. shell linux中shell脚本编写俄罗斯方块

    #!/bin/bash# Tetris Game#APP declaration APP_NAME="${0##*[\\/]}" APP_VERSION="1.0&quo ...

  2. Ubuntu下用shell脚本实现俄罗斯方块游戏

    源文件名为 1.sh 运行效果图如下 源代码如下 nihao #!/bin/bash #APP declaration APP_NAME="${0##*[\\/]}" APP_VE ...

  3. shell脚本部署俄罗斯方块

    #!/bin/bash   APP_NAME="${0##*[\\/]}" APP_VERSION="1.0"   #颜色定义 iSumColor=7      ...

  4. shell脚本之俄罗斯方块

    #!/bin/bashAPP_NAME="${0##*[\\/]}" APP_VERSION="1.0"#颜色定义 iSumColor=7 #颜色总数 cRed ...

  5. shell脚本的俄罗斯方块 : )

    #!/bin/bash # Tetris Game # 10.21.2003 xhchen<[email]xhchen@winbond .com.tw[/email]> #APP decl ...

  6. bash 脚本_Bash技巧:可以左右下移动和旋转俄罗斯方块的Shell脚本

    在 Linux bash 中,之前文章介绍过使用 k.j.h.l 键来上下左右移动单个方块的 shell 脚本. 下面继续介绍如何旋转单个方块. 执行效果 具体的执行效果如下: 旋转前的截图 移动并旋 ...

  7. shell脚本俄罗斯方块

    俄罗斯方块的shell脚本 #!/bin/bash# Tetris Game # 10.21.2003 xhchen<[email]xhchen@winbond.com.tw[/email]&g ...

  8. 用shell脚本写的一个简单的俄罗斯方块

    用shell脚本写的一个简单的俄罗斯方块 代码 代码 测试 下载链接 代码 代码 #!/bin/bash #version 1.2,若非正常退出,请使用附带的killel.sh脚本杀死进程 #定义用于 ...

  9. shell脚本俄罗斯方块游戏

    亲自测试了一个大牛写的shell脚本,感兴趣可以看看,效果如下: 代码如下: 1 #!/bin/bash 2 3 # Tetris Game 4 # 10.21.2003 xhchen<[ema ...

最新文章

  1. Alyona and a tree (树上倍增+差分)
  2. Windows环境安装Gradle6.4.1
  3. HTML <q> 标签的简单介绍
  4. postman返回值设置为全局变量
  5. Java 网络实例一(获取指定主机的IP地址、查看端口是否已使用、获取本机ip地址及主机名、获取远程文件大小)
  6. 查找重复文件_快速查找、删除重复图片及文件!
  7. 如何打造工业物联网帝国?
  8. 3.mysql的主从原理是什么_mysql 的主从实现原理
  9. Windows 10 Python 深度学习环境安装
  10. MyBatis架构图
  11. ODBC连接数据库实例
  12. 利用YYLabel实现图文混排
  13. Tomcat 修改网站旁边的小图标
  14. 433MHz无线通信
  15. Vue 中英文切换设置
  16. Deconstructing laws of accessibility and facility distribution in cities
  17. QT报错: ‘C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\link.exe‘ failed
  18. gpio_desc()的分析
  19. 2G内存刚刚好 浅谈4G内存对笔记本的影响
  20. exec与sp_executesql

热门文章

  1. 用ASP.NET创建网络相册
  2. 浪漫侧影 ( 题解 )
  3. Java使用aspose生成简历
  4. 写给刚接触Auto CAD新人的建议——第三期
  5. Python作画玫瑰花
  6. 调用方法求出数组两个元素的和
  7. 人类一败涂地做图教程_人类一败涂地皮肤怎么弄 人类一败涂地皮肤制作教程...
  8. Android Lost RAM的统计方法
  9. MATLAB矩阵相关函数学习--中级函数
  10. 网易云音乐外链播放器代码的一个bug