zoukankan      html  css  js  c++  java
  • shell脚本俄罗斯方块游戏

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

    代码如下:

      1 #!/bin/bash
      2  
      3 # Tetris Game
      4 # 10.21.2003 xhchen<[email]xhchen@winbond.com.tw[/email]>
      5  
      6 #APP declaration
      7 APP_NAME="${0##*[\/]}"
      8 APP_VERSION="1.0"
      9  
     10  
     11 #颜色定义
     12 cRed=1
     13 cGreen=2
     14 cYellow=3
     15 cBlue=4
     16 cFuchsia=5
     17 cCyan=6
     18 cWhite=7
     19 colorTable=($cRed $cGreen $cYellow $cBlue $cFuchsia $cCyan $cWhite)
     20  
     21 #位置和大小
     22 iLeft=3
     23 iTop=2
     24 ((iTrayLeft = iLeft + 2))
     25 ((iTrayTop = iTop + 1))
     26 ((iTrayWidth = 10))
     27 ((iTrayHeight = 15))
     28  
     29 #颜色设置
     30 cBorder=$cGreen
     31 cScore=$cFuchsia
     32 cScoreValue=$cCyan
     33  
     34 #控制信号
     35 #改游戏使用两个进程,一个用于接收输入,一个用于游戏流程和显示界面;
     36 #当前者接收到上下左右等按键时,通过向后者发送signal的方式通知后者。
     37 sigRotate=25
     38 sigLeft=26
     39 sigRight=27
     40 sigDown=28
     41 sigAllDown=29
     42 sigExit=30
     43  
     44 #七中不同的方块的定义
     45 #通过旋转,每种方块的显示的样式可能有几种
     46 box0=(0 0 0 1 1 0 1 1)
     47 box1=(0 2 1 2 2 2 3 2 1 0 1 1 1 2 1 3)
     48 box2=(0 0 0 1 1 1 1 2 0 1 1 0 1 1 2 0)
     49 box3=(0 1 0 2 1 0 1 1 0 0 1 0 1 1 2 1)
     50 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)
     51 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)
     52 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)
     53 #所有其中方块的定义都放到box变量中
     54 box=(${box0[@]} ${box1[@]} ${box2[@]} ${box3[@]} ${box4[@]} ${box5[@]} ${box6[@]})
     55 #各种方块旋转后可能的样式数目
     56 countBox=(1 2 2 2 4 4 4)
     57 #各种方块再box数组中的偏移
     58 offsetBox=(0 1 3 5 7 11 15)
     59  
     60 #每提高一个速度级需要积累的分数
     61 iScoreEachLevel=50        #be greater than 7
     62  
     63 #运行时数据
     64 sig=0                #接收到的signal
     65 iScore=0        #总分
     66 iLevel=0        #速度级
     67 boxNew=()        #新下落的方块的位置定义
     68 cBoxNew=0        #新下落的方块的颜色
     69 iBoxNewType=0        #新下落的方块的种类
     70 iBoxNewRotate=0        #新下落的方块的旋转角度
     71 boxCur=()        #当前方块的位置定义
     72 cBoxCur=0        #当前方块的颜色
     73 iBoxCurType=0        #当前方块的种类
     74 iBoxCurRotate=0        #当前方块的旋转角度
     75 boxCurX=-1        #当前方块的x坐标位置
     76 boxCurY=-1        #当前方块的y坐标位置
     77 iMap=()                #背景方块图表
     78  
     79 #初始化所有背景方块为-1, 表示没有方块
     80 for ((i = 0; i < iTrayHeight * iTrayWidth; i++)); do iMap[$i]=-1; done
     81  
     82  
     83 #接收输入的进程的主函数
     84 function RunAsKeyReceiver()
     85 {
     86         local pidDisplayer key aKey sig cESC sTTY
     87  
     88         pidDisplayer=$1
     89         aKey=(0 0 0)
     90  
     91         cESC=`echo -ne "33"`
     92         cSpace=`echo -ne "40"`
     93  
     94         #保存终端属性。在read -s读取终端键时,终端的属性会被暂时改变。
     95         #如果在read -s时程序被不幸杀掉,可能会导致终端混乱,
     96         #需要在程序退出时恢复终端属性。
     97         sTTY=`stty -g`
     98  
     99         #捕捉退出信号
    100         trap "MyExit;" INT TERM
    101         trap "MyExitNoSub;" $sigExit
    102  
    103         #隐藏光标
    104         echo -ne "33[?25l"
    105  
    106  
    107         while :
    108         do
    109                 #读取输入。注-s不回显,-n读到一个字符立即返回
    110                 read -s -n 1 key
    111  
    112                 aKey[0]=${aKey[1]}
    113                 aKey[1]=${aKey[2]}
    114                 aKey[2]=$key
    115                 sig=0
    116  
    117                 #判断输入了何种键
    118                 if [[ $key == $cESC && ${aKey[1]} == $cESC ]]
    119                 then
    120                         #ESC键
    121                         MyExit
    122                 elif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]
    123                 then
    124                         if [[ $key == "A" ]]; then sig=$sigRotate        #<向上键>
    125                         elif [[ $key == "B" ]]; then sig=$sigDown        #<向下键>
    126                         elif [[ $key == "D" ]]; then sig=$sigLeft        #<向左键>
    127                         elif [[ $key == "C" ]]; then sig=$sigRight        #<向右键>
    128                         fi
    129                 elif [[ $key == "W" || $key == "w" ]]; then sig=$sigRotate        #W, w
    130                 elif [[ $key == "S" || $key == "s" ]]; then sig=$sigDown        #S, s
    131                 elif [[ $key == "A" || $key == "a" ]]; then sig=$sigLeft        #A, a
    132                 elif [[ $key == "D" || $key == "d" ]]; then sig=$sigRight        #D, d
    133                 elif [[ "[$key]" == "[]" ]]; then sig=$sigAllDown        #空格键
    134                 elif [[ $key == "Q" || $key == "q" ]]                        #Q, q
    135                 then
    136                         MyExit
    137                 fi
    138  
    139                 if [[ $sig != 0 ]]
    140                 then
    141                         #向另一进程发送消息
    142                         kill -$sig $pidDisplayer
    143                 fi
    144         done
    145 }
    146  
    147 #退出前的恢复
    148 function MyExitNoSub()
    149 {
    150         local y
    151  
    152         #恢复终端属性
    153         stty $sTTY
    154         ((y = iTop + iTrayHeight + 4))
    155  
    156         #显示光标
    157         echo -e "33[?25h33[${y};0H"
    158         exit
    159 }
    160  
    161  
    162 function MyExit()
    163 {
    164         #通知显示进程需要退出
    165         kill -$sigExit $pidDisplayer
    166  
    167         MyExitNoSub
    168 }
    169  
    170  
    171 #处理显示和游戏流程的主函数
    172 function RunAsDisplayer()
    173 {
    174         local sigThis
    175         InitDraw
    176  
    177         #挂载各种信号的处理函数
    178         trap "sig=$sigRotate;" $sigRotate
    179         trap "sig=$sigLeft;" $sigLeft
    180         trap "sig=$sigRight;" $sigRight
    181         trap "sig=$sigDown;" $sigDown
    182         trap "sig=$sigAllDown;" $sigAllDown
    183         trap "ShowExit;" $sigExit
    184  
    185         while :
    186         do
    187                 #根据当前的速度级iLevel不同,设定相应的循环的次数
    188                 for ((i = 0; i < 21 - iLevel; i++))
    189                 do
    190                         sleep 0.02
    191                         sigThis=$sig
    192                         sig=0
    193  
    194                         #根据sig变量判断是否接受到相应的信号
    195                         if ((sigThis == sigRotate)); then BoxRotate;        #旋转
    196                         elif ((sigThis == sigLeft)); then BoxLeft;        #左移一列
    197                         elif ((sigThis == sigRight)); then BoxRight;        #右移一列
    198                         elif ((sigThis == sigDown)); then BoxDown;        #下落一行
    199                         elif ((sigThis == sigAllDown)); then BoxAllDown;        #下落到底
    200                         fi
    201                 done
    202                 #kill -$sigDown $$
    203                 BoxDown        #下落一行
    204         done
    205 }
    206  
    207  
    208 #BoxMove(y, x), 测试是否可以把移动中的方块移到(x, y)的位置, 返回0则可以, 1不可以
    209 function BoxMove()
    210 {
    211         local j i x y xTest yTest
    212         yTest=$1
    213         xTest=$2
    214         for ((j = 0; j < 8; j += 2))
    215         do
    216                 ((i = j + 1))
    217                 ((y = ${boxCur[$j]} + yTest))
    218                 ((x = ${boxCur[$i]} + xTest))
    219                 if (( y < 0 || y >= iTrayHeight || x < 0 || x >= iTrayWidth))
    220                 then
    221                         #撞到墙壁了
    222                         return 1
    223                 fi
    224                 if ((${iMap[y * iTrayWidth + x]} != -1 ))
    225                 then
    226                         #撞到其他已经存在的方块了
    227                         return 1
    228                 fi
    229         done
    230         return 0;
    231 }
    232  
    233  
    234 #将当前移动中的方块放到背景方块中去,
    235 #并计算新的分数和速度级。(即一次方块落到底部)
    236 function Box2Map()
    237 {
    238         local j i x y xp yp line
    239  
    240         #将当前移动中的方块放到背景方块中去
    241         for ((j = 0; j < 8; j += 2))
    242         do
    243                 ((i = j + 1))
    244                 ((y = ${boxCur[$j]} + boxCurY))
    245                 ((x = ${boxCur[$i]} + boxCurX))
    246                 ((i = y * iTrayWidth + x))
    247                 iMap[$i]=$cBoxCur
    248         done
    249  
    250         #消去可被消去的行
    251         line=0
    252         for ((j = 0; j < iTrayWidth * iTrayHeight; j += iTrayWidth))
    253         do
    254                 for ((i = j + iTrayWidth - 1; i >= j; i--))
    255                 do
    256                         if ((${iMap[$i]} == -1)); then break; fi
    257                 done
    258                 if ((i >= j)); then continue; fi
    259  
    260                 ((line++))
    261                 for ((i = j - 1; i >= 0; i--))
    262                 do
    263                         ((x = i + iTrayWidth))
    264                         iMap[$x]=${iMap[$i]}
    265                 done
    266                 for ((i = 0; i < iTrayWidth; i++))
    267                 do
    268                         iMap[$i]=-1
    269                 done
    270         done
    271  
    272         if ((line == 0)); then return; fi
    273  
    274         #根据消去的行数line计算分数和速度级
    275         ((x = iLeft + iTrayWidth * 2 + 7))
    276         ((y = iTop + 11))
    277         ((iScore += line * 2 - 1))
    278         #显示新的分数
    279         echo -ne "33[1m33[3${cScoreValue}m33[${y};${x}H${iScore}         "
    280         if ((iScore % iScoreEachLevel < line * 2 - 1))
    281         then
    282                 if ((iLevel < 20))
    283                 then
    284                         ((iLevel++))
    285                         ((y = iTop + 14))
    286                         #显示新的速度级
    287                         echo -ne "33[3${cScoreValue}m33[${y};${x}H${iLevel}        "
    288                 fi
    289         fi
    290         echo -ne "33[0m"
    291  
    292  
    293         #重新显示背景方块
    294         for ((y = 0; y < iTrayHeight; y++))
    295         do
    296                 ((yp = y + iTrayTop + 1))
    297                 ((xp = iTrayLeft + 1))
    298                 ((i = y * iTrayWidth))
    299                 echo -ne "33[${yp};${xp}H"
    300                 for ((x = 0; x < iTrayWidth; x++))
    301                 do
    302                         ((j = i + x))
    303                         if ((${iMap[$j]} == -1))
    304                         then
    305                                 echo -ne "  "
    306                         else
    307                                 echo -ne "33[1m33[7m33[3${iMap[$j]}m33[4${iMap[$j]}m[]33[0m"
    308                         fi
    309                 done
    310         done
    311 }
    312  
    313  
    314 #下落一行
    315 function BoxDown()
    316 {
    317         local y s
    318         ((y = boxCurY + 1))        #新的y坐标
    319         if BoxMove $y $boxCurX        #测试是否可以下落一行
    320         then
    321                 s="`DrawCurBox 0`"        #将旧的方块抹去
    322                 ((boxCurY = y))
    323                 s="$s`DrawCurBox 1`"        #显示新的下落后方块
    324                 echo -ne $s
    325         else
    326                 #走到这儿, 如果不能下落了
    327                 Box2Map                #将当前移动中的方块贴到背景方块中
    328                 RandomBox        #产生新的方块
    329         fi
    330 }
    331  
    332 #左移一列
    333 function BoxLeft()
    334 {
    335         local x s
    336         ((x = boxCurX - 1))
    337         if BoxMove $boxCurY $x
    338         then
    339                 s=`DrawCurBox 0`
    340                 ((boxCurX = x))
    341                 s=$s`DrawCurBox 1`
    342                 echo -ne $s
    343         fi
    344 }
    345  
    346 #右移一列
    347 function BoxRight()
    348 {
    349         local x s
    350         ((x = boxCurX + 1))
    351         if BoxMove $boxCurY $x
    352         then
    353                 s=`DrawCurBox 0`
    354                 ((boxCurX = x))
    355                 s=$s`DrawCurBox 1`
    356                 echo -ne $s
    357         fi
    358 }
    359  
    360  
    361 #下落到底
    362 function BoxAllDown()
    363 {
    364         local k j i x y iDown s
    365         iDown=$iTrayHeight
    366  
    367         #计算一共需要下落多少行
    368         for ((j = 0; j < 8; j += 2))
    369         do
    370                 ((i = j + 1))
    371                 ((y = ${boxCur[$j]} + boxCurY))
    372                 ((x = ${boxCur[$i]} + boxCurX))
    373                 for ((k = y + 1; k < iTrayHeight; k++))
    374                 do
    375                         ((i = k * iTrayWidth + x))
    376                         if (( ${iMap[$i]} != -1)); then break; fi
    377                 done
    378                 ((k -= y + 1))
    379                 if (( $iDown > $k )); then iDown=$k; fi
    380         done
    381  
    382         s=`DrawCurBox 0`        #将旧的方块抹去
    383         ((boxCurY += iDown))
    384         s=$s`DrawCurBox 1`        #显示新的下落后的方块
    385         echo -ne $s
    386         Box2Map                #将当前移动中的方块贴到背景方块中
    387         RandomBox        #产生新的方块
    388 }
    389  
    390  
    391 #旋转方块
    392 function BoxRotate()
    393 {
    394         local iCount iTestRotate boxTest j i s
    395         iCount=${countBox[$iBoxCurType]}        #当前的方块经旋转可以产生的样式的数目
    396  
    397         #计算旋转后的新的样式
    398         ((iTestRotate = iBoxCurRotate + 1))
    399         if ((iTestRotate >= iCount))
    400         then
    401                 ((iTestRotate = 0))
    402         fi
    403  
    404         #更新到新的样式, 保存老的样式(但不显示)
    405         for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
    406         do
    407                 boxTest[$j]=${boxCur[$j]}
    408                 boxCur[$j]=${box[$i]}
    409         done
    410  
    411         if BoxMove $boxCurY $boxCurX        #测试旋转后是否有空间放的下
    412         then
    413                 #抹去旧的方块
    414                 for ((j = 0; j < 8; j++))
    415                 do
    416                         boxCur[$j]=${boxTest[$j]}
    417                 done
    418                 s=`DrawCurBox 0`
    419  
    420                 #画上新的方块
    421                 for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
    422                 do
    423                         boxCur[$j]=${box[$i]}
    424                 done
    425                 s=$s`DrawCurBox 1`
    426                 echo -ne $s
    427                 iBoxCurRotate=$iTestRotate
    428         else
    429                 #不能旋转,还是继续使用老的样式
    430                 for ((j = 0; j < 8; j++))
    431                 do
    432                         boxCur[$j]=${boxTest[$j]}
    433                 done
    434         fi
    435 }
    436  
    437  
    438 #DrawCurBox(bDraw), 绘制当前移动中的方块, bDraw为1, 画上, bDraw为0, 抹去方块。
    439 function DrawCurBox()
    440 {
    441         local i j t bDraw sBox s
    442         bDraw=$1
    443  
    444         s=""
    445         if (( bDraw == 0 ))
    446         then
    447                 sBox="4040"
    448         else
    449                 sBox="[]"
    450                 s=$s"33[1m33[7m33[3${cBoxCur}m33[4${cBoxCur}m"
    451         fi
    452  
    453         for ((j = 0; j < 8; j += 2))
    454         do
    455                 ((i = iTrayTop + 1 + ${boxCur[$j]} + boxCurY))
    456                 ((t = iTrayLeft + 1 + 2 * (boxCurX + ${boxCur[$j + 1]})))
    457                 #033[y;xH, 光标到(x, y)处
    458                 s=$s"33[${i};${t}H${sBox}"
    459         done
    460         s=$s"33[0m"
    461         echo -n $s
    462 }
    463  
    464  
    465 #更新新的方块
    466 function RandomBox()
    467 {
    468         local i j t
    469  
    470         #更新当前移动的方块
    471         iBoxCurType=${iBoxNewType}
    472         iBoxCurRotate=${iBoxNewRotate}
    473         cBoxCur=${cBoxNew}
    474         for ((j = 0; j < ${#boxNew[@]}; j++))
    475         do
    476                 boxCur[$j]=${boxNew[$j]}
    477         done
    478  
    479  
    480         #显示当前移动的方块
    481         if (( ${#boxCur[@]} == 8 ))
    482         then
    483                 #计算当前方块该从顶端哪一行""出来
    484                 for ((j = 0, t = 4; j < 8; j += 2))
    485                 do
    486                         if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
    487                 done
    488                 ((boxCurY = -t))
    489                 for ((j = 1, i = -4, t = 20; j < 8; j += 2))
    490                 do
    491                         if ((${boxCur[$j]} > i)); then i=${boxCur[$j]}; fi
    492                         if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
    493                 done
    494                 ((boxCurX = (iTrayWidth - 1 - i - t) / 2))
    495  
    496                 #显示当前移动的方块
    497                 echo -ne `DrawCurBox 1`
    498  
    499                 #如果方块一出来就没处放,Game over!
    500                 if ! BoxMove $boxCurY $boxCurX
    501                 then
    502                         kill -$sigExit ${PPID}
    503                         ShowExit
    504                 fi
    505         fi
    506  
    507  
    508  
    509         #清除右边预显示的方块
    510         for ((j = 0; j < 4; j++))
    511         do
    512                 ((i = iTop + 1 + j))
    513                 ((t = iLeft + 2 * iTrayWidth + 7))
    514                 echo -ne "33[${i};${t}H        "
    515         done
    516  
    517         #随机产生新的方块
    518         ((iBoxNewType = RANDOM % ${#offsetBox[@]}))
    519         ((iBoxNewRotate = RANDOM % ${countBox[$iBoxNewType]}))
    520         for ((j = 0, i = (${offsetBox[$iBoxNewType]} + $iBoxNewRotate) * 8; j < 8; j++, i++))
    521         do
    522                 boxNew[$j]=${box[$i]};
    523         done
    524  
    525         ((cBoxNew = ${colorTable[RANDOM % ${#colorTable[@]}]}))
    526  
    527         #显示右边预显示的方块
    528         echo -ne "33[1m33[7m33[3${cBoxNew}m33[4${cBoxNew}m"
    529         for ((j = 0; j < 8; j += 2))
    530         do
    531                 ((i = iTop + 1 + ${boxNew[$j]}))
    532                 ((t = iLeft + 2 * iTrayWidth + 7 + 2 * ${boxNew[$j + 1]}))
    533                 echo -ne "33[${i};${t}H[]"
    534         done
    535         echo -ne "33[0m"
    536 }
    537  
    538  
    539 #初始绘制
    540 function InitDraw()
    541 {
    542         clear
    543         RandomBox        #随机产生方块,这时右边预显示窗口中有方快了
    544         RandomBox        #再随机产生方块,右边预显示窗口中的方块被更新,原先的方块将开始下落
    545         local i t1 t2 t3
    546  
    547         #显示边框
    548         echo -ne "33[1m"
    549         echo -ne "33[3${cBorder}m33[4${cBorder}m"
    550  
    551         ((t2 = iLeft + 1))
    552         ((t3 = iLeft + iTrayWidth * 2 + 3))
    553         for ((i = 0; i < iTrayHeight; i++))
    554         do
    555                 ((t1 = i + iTop + 2))
    556                 echo -ne "33[${t1};${t2}H||"
    557                 echo -ne "33[${t1};${t3}H||"
    558         done
    559  
    560         ((t2 = iTop + iTrayHeight + 2))
    561         for ((i = 0; i < iTrayWidth + 2; i++))
    562         do
    563                 ((t1 = i * 2 + iLeft + 1))
    564                 echo -ne "33[${iTrayTop};${t1}H=="
    565                 echo -ne "33[${t2};${t1}H=="
    566         done
    567         echo -ne "33[0m"
    568  
    569  
    570         #显示"Score""Level"字样
    571         echo -ne "33[1m"
    572         ((t1 = iLeft + iTrayWidth * 2 + 7))
    573         ((t2 = iTop + 10))
    574         echo -ne "33[3${cScore}m33[${t2};${t1}HScore"
    575         ((t2 = iTop + 11))
    576         echo -ne "33[3${cScoreValue}m33[${t2};${t1}H${iScore}"
    577         ((t2 = iTop + 13))
    578         echo -ne "33[3${cScore}m33[${t2};${t1}HLevel"
    579         ((t2 = iTop + 14))
    580         echo -ne "33[3${cScoreValue}m33[${t2};${t1}H${iLevel}"
    581         echo -ne "33[0m"
    582 }
    583  
    584  
    585 #退出时显示GameOVer!
    586 function ShowExit()
    587 {
    588         local y
    589         ((y = iTrayHeight + iTrayTop + 3))
    590         echo -e "33[${y};0HGameOver!33[0m"
    591         exit
    592 }
    593  
    594  
    595 #显示用法.
    596 function Usage
    597 {
    598         cat << EOF
    599 Usage: $APP_NAME
    600 Start tetris game.
    601  
    602   -h, --help              display this help and exit
    603       --version           output version information and exit
    604 EOF
    605 }
    606  
    607  
    608 #游戏主程序在这儿开始.
    609 if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    610         Usage
    611 elif [[ "$1" == "--version" ]]; then
    612         echo "$APP_NAME $APP_VERSION"
    613 elif [[ "$1" == "--show" ]]; then
    614         #当发现具有参数--show时,运行显示函数
    615         RunAsDisplayer
    616 else
    617         bash $0 --show&        #以参数--show将本程序再运行一遍
    618         RunAsKeyReceiver $!        #以上一行产生的进程的进程号作为参数
    619 fi
  • 相关阅读:
    Server Tomcat v8.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
    用户画像——“打标签”
    python replace函数替换无效问题
    python向mysql插入数据一直报TypeError: must be real number,not str
    《亿级用户下的新浪微博平台架构》读后感
    【2-10】标准 2 维表问题
    【2-8】集合划分问题(给定要分成几个集合)
    【2-7】集合划分问题
    【2-6】排列的字典序问题
    【2-5】有重复元素的排列问题
  • 原文地址:https://www.cnblogs.com/winfu/p/6065534.html
Copyright © 2011-2022 走看看