欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

shell脚本编写俄罗斯方块

程序员文章站 2022-07-05 08:19:34
网上看到的一个用linux的shell脚本写的俄罗斯方块。共享一下。 原作者信息在脚本的注释中有。 下载地址:点击下载 代码: #!/bin/bash...

网上看到的一个用linux的shell脚本写的俄罗斯方块。共享一下。

原作者信息在脚本的注释中有。

下载地址:点击下载

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 

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