Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use shell script to write Tetris games

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces how to use shell script to write Tetris games, the article is very detailed, has a certain reference value, interested friends must read it!

Paste the following code into an empty Shell script file and run it in Bash!

The code is as follows:

#! / bin/bash

# Tetris Game

# 10.21.2003 xhchen

# APP declaration

APP_NAME= "${0,000,500 * [\\ /]}"

APP_VERSION= "1. 0"

# Color definition

CRed=1

CGreen=2

CYellow=3

CBlue=4

CFuchsia=5

CCyan=6

CWhite=7

ColorTable= ($cRed $cGreen $cYellow $cBlue $cFuchsia $cCyan $cWhite)

# location and size

ILeft=3

ITop=2

((iTrayLeft = iLeft + 2))

((iTrayTop = iTop + 1))

((iTrayWidth = 10))

((iTrayHeight = 15))

# Color Settings

CBorder=$cGreen

CScore=$cFuchsia

CScoreValue=$cCyan

# Control signal

# change the game to use two processes, one for receiving input and one for the game flow and display interface

# when the current user receives the up and down keys, notify the latter by sending signal to the latter.

SigRotate=25

SigLeft=26

SigRight=27

SigDown=28

SigAllDown=29

SigExit=30

# definition of different squares in # 7

# by rotation, there may be several styles for the display of each square

Box0= (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 1 1 1 2 0 1 1 0 1 1 2 0)

Box3= (0 1 0 2 1 0 1 0 1 0 1 1 1 2 1)

Box4= (0 1 0 2 1 1 1 0 1 1 1 2 2 2 0 1 1 1 2 0 2 1 0 1 0 1 1 1 12)

Box5= (0 1 1 1 2 1 2 1 0 1 1 1 2 2 2000 0 0 1 1 1 0 2 1 0 1 1 1 12)

Box6= (0 1 1 1 2 2 1 1 0 1 1 1 2 2 1 0 1 1 0 1 1 2 1 0 1 0 1 1 1 12)

# all the definitions of squares are put in the box variable

Box= (${box0 [@]} ${box1 [@]} ${box2 [@]} ${box3 [@]} ${box4 [@]} ${box5 [@]} ${box6 [@]})

# number of possible styles after rotation of various squares

CountBox= (1 2 2 2 4 4 4)

# offset of various squares in the box array

OffsetBox= (0 1 3 5 7 11 15)

# points accumulated for each increase in speed level

IScoreEachLevel=50 # be greater than 7

# Runtime data

Sig=0 # received signal

IScore=0 # Total score

ILevel=0 # speed class

BoxNew= () # the location definition of the newly fallen square

CBoxNew=0 # the color of the newly fallen square

IBoxNewType=0 # types of newly fallen squares

IBoxNewRotate=0 # rotation angle of the newly fallen square

BoxCur= () # the location definition of the current square

CBoxCur=0 # Color of the current square

IBoxCurType=0 # the category of the current square

IBoxCurRotate=0 # rotation angle of the current square

BoxCurX=-1 # the x coordinate position of the current square

BoxCurY=-1 # the y coordinate position of the current square

IMap= () # background square chart

# initialize all background squares as-1, which means there are no squares

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

# hit the wall

Return 1

Fi

If ((${iMap [y * iTrayWidth + x]}! =-1))

Then

# bumped into other existing squares

Return 1

Fi

Done

Return 0

}

# put the currently moving square into the background box

# and calculate the new score and speed level. (that is, once the square falls to the bottom)

Function Box2Map ()

{

Local j i x y xp yp line

# put the currently moving square into the background box

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; iMurt -))

Do

If ((${iMap [$I]} =-1)); then break; fi

Done

If ((I > = j)); then continue; fi

((line++))

For ((I = j-1; I > = 0; iMel -))

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` # erase the old square

((boxCurY + = iDown))

Slots $s`DrawCurBox 1` # shows the square after the new drop

Echo-ne $s

Box2Map # pastes the currently moving square to the background square

RandomBox # generates new squares

}

# rotate the square

Function BoxRotate ()

{

Local iCount iTestRotate boxTest j i s

ICount=$ {countBox [$iBoxCurType]} # the number of styles that the current square can be rotated to produce

# calculate the new style after rotation

((iTestRotate = iBoxCurRotate + 1))

If ((iTestRotate > = iCount))

Then

((iTestRotate = 0))

Fi

# Update to the new style and save the old style (but not shown)

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 iTunes ${boxCur [$j]}; fi

If ((${boxCur [$j]} < t)); then tasking ${boxCur [$j]}; fi

Done

((boxCurX = (iTrayWidth-1-I-t) / 2))

# display the currently moved square

Echo-ne `DrawCurBox 1`

# if there is no place to put the square as soon as it comes out, Game over!

If! BoxMove $boxCurY $boxCurX

Then

Kill-$sigExit ${PPID}

ShowExit

Fi

Fi

# clear the pre-displayed square on the right

For ((j = 0; j < 4; jacks +))

Do

((I = iTop + 1 + j))

((t = iLeft + 2 * iTrayWidth + 7))

Echo-ne "\ 033 [${I}; ${t} H"

Done

# randomly generate new squares

((iBoxNewType = RANDOM% ${# offsetBox [@]}))

((iBoxNewRotate = RANDOM% ${countBox [$iBoxNewType]}))

For ((j = 0, I = (${offsetBox [$iBoxNewType]} + $iBoxNewRotate) * 8; j < 8; jacks, iTunes +)

Do

BoxNew [$j] = ${box [$I]}

Done

((cBoxNew = ${colorTable [RANDOM% ${# colorTable [@]}]}))

# display the pre-displayed square on the right

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"

}

# initial drawing

Function InitDraw ()

{

Clear

RandomBox # randomly generates squares, and the square in the right preview window is faster.

RandomBox # randomly generates squares, the squares in the right pre-display window are updated, and the original squares will begin to fall

Local i t1 t2 t3

# display border

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; iTunes +))

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; iTunes +))

Do

(T1 = I * 2 + iLeft + 1))

Echo-ne "\ 033 [${iTrayTop}; ${T1} hinge ="

Echo-ne "\ 033 [${T2}; ${T1} hinge ="

Done

Echo-ne "\ 033 [0m"

# display 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"

}

# display GameOVer when exiting!

Function ShowExit ()

{

Local y

((y = iTrayHeight + iTrayTop + 3))

Echo-e "\ 033 [${y}; 0HGameOver!\ 033 [0m"

Exit

}

# display usage.

Function Usage

{

Cat

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report