当前位置: 移动技术网 > 网络运营>服务器>Linux > shell脚本编写俄罗斯方块

shell脚本编写俄罗斯方块

2018年08月08日  | 移动技术网网络运营  | 我要评论
网上看到的一个用linux的shell脚本写的俄罗斯方块。共享一下。 原作者信息在脚本的注释中有。 下载地址:点击下载 代码: #!/bin/bash

网上看到的一个用linux的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 stty 
  
    piddisplayer=$1 
    akey=(0 0 0) 
  
    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 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    #<向上键> 
            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 != 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不同,设定相应的循环的次数 
        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), 测试是否可以把移动中的方块移到(x, y)的位置, 返回0则可以, 1不可以 
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; 
} 
  
  
#将当前移动中的方块放到背景方块中去, 
#并计算新的分数和速度级。(即一次方块落到底部) 
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 
        #走到这儿, 如果不能下落了 
        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 
  
    #更新到新的样式, 保存老的样式(但不显示) 
    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 
        #不能旋转,还是继续使用老的样式 
        for ((j = 0; j < 8; j++)) 
        do 
            boxcur[$j]=${boxtest[$j]} 
        done 
    fi 
} 
  
  
#drawcurbox(bdraw), 绘制当前移动中的方块, bdraw为1, 画上, bdraw为0, 抹去方块。 
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, 光标到(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 
        #计算当前方块该从顶端哪一行"冒"出来 
        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 = 20; 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    #随机产生方块,这时右边预显示窗口中有方快了 
    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==" 
    done 
    echo -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" ]]; then 
    usage 
elif [[ "$1" == "--version" ]]; then 
    echo "$app_name $app_version" 
elif [[ "$1" == "--show" ]]; then 
    #当发现具有参数--show时,运行显示函数 
    runasdisplayer 
else 
    bash $0 --show&    #以参数--show将本程序再运行一遍 
    runaskeyreceiver $!    #以上一行产生的进程的进程号作为参数 
fi 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网