Pro-Test a very fun shell script written by Tetris game, script from Internet
#!/bin/bash
# Tetris Game
# 10.21.2003 Xhchen<[email][email protected][/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)
#位置和大小
Ileft=3
itop=2
((Itrayleft = ILeft + 2))
((itraytop = iTop + 1))
((Itraywidth = 10))
((itrayheight = 15))
#颜色设置
Cborder= $cGreen
Cscore= $cFuchsia
Cscorevalue= $cCyan
#控制信号
#改游戏使用两个进程, one for receiving input, one for game flow and display interface;
#当前者接收到上下左右等按键时, inform the latter by sending signal to the latter.
Sigrotate=25
Sigleft=26
Sigright=27
Sigdown=28
sigalldown=29
Sigexit=30
#七中不同的方块的定义
#通过旋转, there may be several types of styles for each block's display
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, indicates no block
for ((i = 0; i < itrayheight * itraywidth; i++)); Do imap[$i]=-1; Done
#接收输入的进程的主函数
function Runaskeyreceiver ()
{
Local Piddisplayer key Akey Sig Cesc STTY
Piddisplayer=$1
akey= (0 0 0)
Cesc= ' Echo-ne "\033"
Cspace= ' Echo-ne "\040"
#保存终端属性. When Read-s reads the terminal key, the terminal's properties are temporarily changed.
#如果在read-S program is unfortunately killed, may cause terminal confusion,
#需要在程序退出时恢复终端属性.
Stty= ' Stty-g '
#捕捉退出信号
Trap "MYEXIT;" INT term
Trap "MYEXITNOSUB;" $sigExit
#隐藏光标
Echo-ne "\033[?25l"
While:
Do
#读取输入. Note-S does not echo,-N reads to a character immediately returns
Read-s-N 1 key
AKEY[0]=${AKEY[1]}
AKEY[1]=${AKEY[2]}
akey[2]= $key
Sig=0
#判断输入了何种键
if [[$key = = $cESC && ${akey[1]} = = $cESC]]
Then
#ESC键
Myexit
elif [[${akey[0]} = = $cESC && ${akey[1]} = = "["]]
Then
if [[$key = = "A"]]; Then sig= $sigRotate #< up ARROW >
elif [[$key = = "B"]]; Then sig= $sigDown #< down arrow >
elif [[$key = = "D"]]; Then sig= $sigLeft #< left arrow >
elif [[$key = = "C"]]; Then sig= $sigRight #< right >
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! = 0]]
Then
#向另一进程发送消息
kill-$sig $pidDisplayer
Fi
Done
}
#退出前的恢复
function Myexitnosub ()
{
Local Y
#恢复终端属性
Stty $sTTY
(y = iTop + itrayheight + 4))
#显示光标
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不同, set the number of times for the corresponding loop
for ((i = 0; i < 21-ilevel; i++))
Do
Sleep 0.02
sigthis= $sig
Sig=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; #下落到底
Fi
Done
#kill-$sigDown $$
Boxdown #下落一行
Done
}
#BoxMove (y, x), test whether the moving block can be moved to the position (x, y), return 0, 1 can not
function Boxmove ()
{
Local j I x y xTest ytest
Ytest=$1
Xtest=$2
for ((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 1
Fi
if ((${imap[y * itraywidth + x]}! =-1))
Then
#撞到其他已经存在的方块了
Return 1
Fi
Done
return 0;
}
#将当前移动中的方块放到背景方块中去,
#并计算新的分数和速度级. (That is, once the block falls to the bottom)
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]= $cBoxCur
Done
#消去可被消去的行
Line=0
for ((j = 0; J < Itraywidth * Itrayheight; J + = Itraywidth))
Do
for ((i = j + iTrayWidth-1; I >= J; i--))
Do
if ((${imap[$i]} = =-1)); Then break; Fi
Done
if ((i >= j)); then continue; Fi
((line++))
for ((i = j-1; I >= 0; i--))
Do
((x = i + itraywidth))
imap[$x]=${imap[$i]}
Done
for ((i = 0; i < itraywidth; i++))
Do
imap[$i]=-1
Done
Done
if (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))
Then
if ((Ilevel < 20))
Then
((ilevel++))
((y = iTop + 14))
#显示新的速度级
Echo-ne "\033[3${cscorevalue}m\033[${y};${x}h${ilevel}"
Fi
Fi
Echo-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))
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 + 1) #新的y坐标
If Boxmove $y $boxCurX #测试是否可以下落一行
Then
s= "' Drawcurbox 0 '" #将旧的方块抹去
((Boxcury = y))
s= "$s ' drawcurbox 1 '" #显示新的下落后方块
Echo-ne $s
Else
#走到这儿, if you can't fall.
Box2map #将当前移动中的方块贴到背景方块中
Randombox #产生新的方块
Fi
}
#左移一列
function Boxleft ()
{
Local x S
((x = boxCurX-1))
If Boxmove $boxCurY $x
Then
S= ' Drawcurbox 0 '
((Boxcurx = x))
S= $s ' drawcurbox 1 '
Echo-ne $s
Fi
}
#右移一列
function Boxright ()
{
Local x S
((x = Boxcurx + 1))
If Boxmove $boxCurY $x
Then
S= ' Drawcurbox 0 '
((Boxcurx = x))
S= $s ' drawcurbox 1 '
Echo-ne $s
Fi
}
#下落到底
function Boxalldown ()
{
Local k j I x y Idown s
idown= $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; Fi
Done
((k-= y + 1))
if (($iDown > $k)); Then idown= $k; Fi
Done
S= ' Drawcurbox 0 ' #将旧的方块抹去
((Boxcury + = Idown))
S= $s ' drawcurbox 1 ' #显示新的下落后的方块
Echo-ne $s
Box2map #将当前移动中的方块贴到背景方块中
Randombox #产生新的方块
}
#旋转方块
function Boxrotate ()
{
Local ICount itestrotate Boxtest J i s
icount=${countbox[$iBoxCurType]} #当前的方块经旋转可以产生的样式的数目
#计算旋转后的新的样式
((itestrotate = iboxcurrotate + 1))
if ((itestrotate >= iCount))
Then
((itestrotate = 0))
Fi
#更新到新的样式, save old style (but not show)
for (j = 0, I = (${offsetbox[$iBoxCurType]} + $iTestRotate) * 8; J < 8; J + +, i++))
Do
boxtest[$j]=${boxcur[$j]}
boxcur[$j]=${box[$i]}
Done
If Boxmove $boxCurY $boxCurX #测试旋转后是否有空间放的下
Then
#抹去旧的方块
for ((j = 0; J < 8; J + +))
Do
boxcur[$j]=${boxtest[$j]}
Done
S= ' Drawcurbox 0 '
#画上新的方块
for (j = 0, I = (${offsetbox[$iBoxCurType]} + $iTestRotate) * 8; J < 8; J + +, i++))
Do
boxcur[$j]=${box[$i]}
Done
S= $s ' drawcurbox 1 '
Echo-ne $s
Iboxcurrotate= $iTestRotate
Else
#不能旋转, or continue to use the old style
for ((j = 0; J < 8; J + +))
Do
boxcur[$j]=${boxtest[$j]}
Done
Fi
}
#DrawCurBox (Bdraw), draw the currently moving block, Bdraw to 1, draw on, Bdraw to 0, erase the block.
function Drawcurbox ()
{
Local I J T Bdraw SBox s
Bdraw=$1
S= ""
if ((Bdraw = = 0))
Then
sbox= "\040\040"
Else
Sbox= "[]"
s= $s "\033[1m\033[7m\033[3${cboxcur}m\033[4${cboxcur}m"
Fi
for ((j = 0; J < 8; J + = 2))
Do
((i = itraytop + 1 + ${boxcur[$j]} + Boxcury))
((t = itrayleft + 1 + 2 * (Boxcurx + ${boxcur[$j + 1]})))
#\033[y;xh, cursor to (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 = 0; J < ${#boxNew [@]}; j + +)
Do
boxcur[$j]=${boxnew[$j]}
Done
#显示当前移动的方块
if ((${#boxCur [@]} = = 8))
Then
#计算当前方块该从顶端哪一行 "Take" it.
for ((j = 0, t = 4; J < 8; J + = 2))
Do
if ((${boxcur[$j]} < T)); Then t=${boxcur[$j]}; Fi
Done
((Boxcury =-T))
for (j = 1, i = -4, t =; J < 8; J + = 2))
Do
if ((${boxcur[$j]} > i)); Then i=${boxcur[$j]}; Fi
if ((${boxcur[$j]} < T)); Then t=${boxcur[$j]}; Fi
Done
((Boxcurx = (iTrayWidth-1-i-t)/2))
#显示当前移动的方块
Echo-ne ' Drawcurbox 1 '
#如果方块一出来就没处放, Game over!
if! Boxmove $boxCurY $boxCurX
Then
kill-$sigExit ${ppid}
Showexit
Fi
Fi
#清除右边预显示的方块
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++))
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 = 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[]"
Done
Echo-ne "\033[0m"
}
#初始绘制
function Initdraw ()
{
Clear
Randombox #随机产生方块, then the right pre-display window is fast
Randombox #再随机产生方块, the block in the right pre-display window is updated, and the original block will begin to fall
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=="
Done
Echo-ne "\033[0m"
#显示 the words "score" and "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 [["$" = = "-H" | | "$" = = "--help"]; Then
Usage
elif [["$" = = "--version"]]; Then
echo "$APP _name $APP _version"
elif [["$" = = "--show"]]; Then
When #当发现具有参数--show, run the display function
Runasdisplayer
Else
bash $--show& #以参数--show to run the program again
Runaskeyreceiver $! #以上一行产生的进程的进程号作为参数
Fi
"Go" shell script written by Tetris game