#! / bin / bash
# TETRIS GAME
# $ ID $
#
# Copyright (c) xhchen
# All rights reserved.
#
# $ Log $
#
# Color definition
CRED = 1
CGreen = 2
Cyellow = 3
CBLUE = 4
Cfuchsia = 5
Ccyan = 6
CWHITE = 7
ColORTABLE = ($ CRED $ CGREEN $ CYELLOW $ CFUE $ CFUCHSIA $ CCYAN $ CWHITE)
# Location and size
Ileft = 3
ITOP = 2
((ItRayeft = Ileft 2)))
((straytop = ITOP 1)))
((straywidth = 10)))
((strayheight = 15))
# Color setting
CBORDER = $ cgreen
Cscore = $ cfuchsia
Cscorevalue = $ ccyan
#control signal
# Change the game Use two processes, one for receiving input, one for game flow and display interface;
# When the current person receives a button, the back and so on, the latter is notified by sending the Signal to the latter.
Sigrotate = 25
SigLeft = 26
Sigright = 27
Sigdown = 28
SigalLDown = 29
SiGexit = 30
# 七 中 不同 方 方 定
# By rotating, there may be several styles of each block 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 2 2 2 0 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 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 1 1 2 1 0 1 1 0 1 1 1 2)
# All of them definitions in the Box variable
Box = ($ {Box0 [@]} $ {box1 [@]} $ {box3 [@]} $ {box4 [@]} $ {box5 [@]} $ {box6 [@]} $ { ]})
# Various squares of various squares
Countbox = (1 2 2 2 4 4 4)
# Offset in various squares re-box arrays
OFFSETBOX = (0 1 3 5 7 11 15)
# Each time to increase the score required to accumulate
Iscoreeachleevel = 50 #be Greater Than 7
# 运 运 数据 数据
SIG = 0 # received Signal
ISCORE = 0 # 000
Ilevel = 0 # speed level
Boxnew = () # 新 新 块 块 位置 位置
CBOXNEW = 0 # color of new drops
IBOXNewType = 0 # Novetical Categories
IBOXNEWROTATE = 0 # rotation angle of the new drops
Boxcur = () # The location definition of the current square
CBOXCUR = 0 # Current square color
iBoxCurtype = 0 # Type IBoxCurrotate = 0 # Current square rotation angle
Boxcurx = -1 # Current block X coordinate position
BoxCURY = -1 # Current block Y coordinate position
IMAP = () # Background block diagram
# Initialize all background squares to -1, indicating that there is no block
For ((i = 0; i #How to receive the main function of the input process Function RunasKeyReceiver () { Local Piddisplayer Key Akey Sig Cesc Stty piddisplayer = $ 1 Akey = (0 0 0) CESC = `echo -ne" / 33 "` CSPACE = `Echo -ne" / 40 "` # Save Terminal Properties. When the terminal key is read in the read -s, the attributes of the terminal will be temporarily changed. # If the program is unfortunate in Read -S, it may cause the terminal to be confusing. # Require terminal attribute when the program exits. Stty = `stty -g` # Capture exit signal TRAP "MyExit;" INT TERM TRAP "MyExitnosub;" $ SIGEXIT # Hidden cursor echo -ne "/ 33 [? 25L" While [[1]] DO # Read input. Note -s does not return, -n reads a character to return immediately 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"]]; the Sig = $ SIGLEFT # <向 左键> Elif [[$ key == "c"]]; then sig = $ sigright # Fi Elif [[$ key == "W" || $ key == "w"]]; the Sig = $ sigrotate #w, w Elif [[$ key == "S" || $ key == "s"]]; the Sig = $ sigdown #s, s Elif [[$ key == "a" || $ key == "a"]]; the number = $ sigleft #a, a Elif [[$ key == "D" || $ key == "D"]]; Then Sig = $ sigright #d, Delif [["[$ key]" == "[]"]]; the SIG = $ SIGALLDOWN # Spacebar Elif [[$ key == "q" || $ key == "q"]] #q, q THEN MyExit Fi IF [$ SIG! = 0]]]]]]] THEN # Send a message to another process KILL - $ SIG $ PIDDISPLAYER Fi DONE } # 退 退 Function myexitnosub () { Local Y # Restore Terminal Attributes Stty $ stty ((y = ITOP ItrayHeight 4))) # Display cursor echo -e "/ 33 [? 25h / 33 [$ {y}; 0H" exit } Function myexit () { # 通 显示 Display process needs to exit KILL - $ SiGexit $ PIDISPLAYER MyExitnosub } # Handle the main function of display and game flow Function RunasDisplayer () { Local Sigthis Initdraw # Mount various signal processing functions Trap "SIG = $ SIGROTATE;" $ SIGROTATE TRAP "SIG = $ SIGLEFT;" $ SIGLEFT TRAP "SIG = $ sigright;" $ SIGRIGHT TRAP "SIG = $ sigdown;" $ SIGDOWN Trap "SIG = $ sigalldown;" $ SIGALLDOWN TRAP "Showexit;" $ SIGEXIT While [[1]] DO # Different from the current speed level Ilevel, set the number of times the corresponding loop For ((i = 0; i <21 - ilevel; i )) DO Usleep 20000 Sigthis = $ SIG SIG = 0 # Depending on whether the SIG variable determines whether the corresponding signal is accepted IF ((sigthis == sigrotate); then boxrotate; # Elif ((sigthis == sigleft); the boxleft; # 移 一 列 Elif ((sigthis == sigright)); the BoxRight; # 一 一 列 Elif ((sigthis == sigdown); the BoxDown; # fallen Elif ((sigthis == sigalldown); the boxalldown; # fallen to the end Fi DONE #kill - $ SIGDOWN $$ Boxdown # drops DONE } #Boxmove (y, x), can test whether the blocks in the movement into (x, y), return 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> = strayheight || x <0 || x> = straywidth)) THEN # 到 wall Return 1 Fi IF ($ {IMAP [Y * ItRaywidth x]}! = -1))) THEN # 到 的 有 有 有 有 有 有 Return 1 Fi DONE Return 0; } # Put the squares in the current move in the background square, # And calculate new scores and speed levels. (Ie, the square falls to the bottom) Function Box2map () { Local J i x y xp yp line # Put the squares in the current move in the background block For ((j = 0; j <8; j = 2)) DO ((i = j 1))) ((y = $ {boxcur [$ j]} boxcury))) ((x = $ {Boxcur [$ I]} boxcurx)) ((i = y * straywidth x)))) IMAP [$ I] = $ CBOXCUR DONE # 消 消 可 行 行 Line = 0 For ((j = 0; j DO For ((i = j itraywidth - 1; i> = j; i -)) DO IF (($ {IMAP [$ I]} == -1)); Then Break; Fi DONE IF ((i> = j)); the continue; fi ((Line ))) For ((i = j - 1; i> = 0; i -))) DO ((x = i itraywidth))) IMAP [$ x] = $ {IMAP [$ I]} DONE For ((i = 0; i DO IMAP [$ I] = - 1 DONE DONE IF ((line == 0)); the return; Fi # Calculate the score and speed level according to the number of lines of the elimination ((x = ILEFT ItrayWidth * 2 7)))))) ((Y = ITOP 11))) ((Iscore = line * 2 - 1)))) # Display new score Echo -ne "/ 33 [1M / 33 [3 $ {CSCoreValue} m / 33 [$ {y}; $ {x} h $ {iscore} IF (ISCORE% Iscoreeachlevel THEN IF ((Ilevel <20)) THEN ((iLEVEL ))) ((y = ITOP 14))) # Show new speed level echo -ne "/ 33 [3 $ {cscorevalue} m / 33 [$ {y}; $ {x} h $ {ilevel}" Fi Fi echo -ne "/ 33 [0m" # Re-display the background block for ((y = 0; y DO ((YP = Y ItRaytop 1))) ((XP = ItRayeft 1)))) ((i = y * straywidth) Echo -ne "/ 33 [$ {yp}; $ {xp} h" For ((x = 0; x DO ((j = i x)))) IF ($ {IMAP [$ j]} == -1)))) THEN echo -ne "" Else Echo -ne "/ 33 [1M / 33 [7M / 33 [3 $ {IMAP [$ J]} m / 33 [4 $ {IMAP [$ J]} M [] / 33 [0M" Fi DONE DONE } # 倒 一 行 Function BoxDown () { Local y ((Y = BoxCury 1) #nioted Y coordinate If Boxmove $ y $ boxcurx # testing can be dropped THEN s = "` drawcurbox 0` "# 抹 块 块 ((BoxCury = Y)) S = "$ s`drawcurbox 1`" # Show new drops behind Echo -ne $ s Else # 走 到 儿, if you can't fall Box2map # puts the blocks in the current move to the background block Randombox # Generate new blocks 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 = $ itHeyheight # Calculate how much it takes to drop For ((j = 0; j <8; j = 2)) DO ((i = j 1))) ((y = $ {boxcur [$ j]} boxcury))) ((x = $ {Boxcur [$ I]} boxcurx)) For ((k = y 1; k DO ((i = k * straywidth x))) IF ($ {IMAP [$ I]}! = -1)); the Break; Fi DONE ((k - = y 1))))) IF (($ IDOWN> $ K)); Then iDown = $ K; FI DONE s = `drawcurbox 0` # Wipe the old square ((BoxCury = iDown))) s = $ s`drawcurbox 1` # Shows the new drops after the new drops Echo -ne $ s Box2map # puts the blocks in the current move to the background block Randombox # Generate new blocks } # 方块 Function Boxrotate () { Local iCount ITESTROTATE BOXTEST J I Sicount = $ {CountBox [$ IBoxCurtype]} # The current number of styles that can be generated by rotation # Calculate new style after rotation ((ITESTROTATE = IBoxCurrotate 1))) IF ((ITESTROTATE> = iCount))) THEN ((ITESTROTATE = 0))) Fi # Update to a new style, save old style (but not) 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 # Is there a spatial place after the rotation 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 # Can't rotate, or continue to use old style For ((j = 0; j <8; j )) DO Boxcur [$ j] = $ {boxtest [$ j]} DONE Fi } #Drawcurbox (bdraw), drawing the blocks in the current move, BDRAW is 1, draw, BDRAW is 0, erase the square. Function drawcurbox () { Local I J T BDRAW SBOX S BDRAW = $ 1 s = "" IF ((BDRAW == 0)))) THEN Sbox = "/ 40/40" Else sbox = "[]" S = $ S "/ 33 [1M / 33 [7M / 33 [3 $ {CBoxCur} m / 33 [4 $ {cboxcur} M" Fi For ((j = 0; j <8; j = 2)) DO ((i = straytop 1 $ {Boxcur [$ j]} boxcury)))) ((T = ItRayeft 1 2 * (BoxCurx $ {Boxcur [$ J 1]}))))))) # / 33 [y; XH, cursor to (x, y) S = $ S "/ 33 [$ {i}; $ {t} h $ {sbox}" DONE s = $ s "/ 33 [0m" echo -n $ s } # Update new square Function randombox () { Local i J t # Update the current mobile block Iboxcurtype = $ {iboxnewtype} Iboxcurrotate = $ {iboxnewrotate} CBoxcur = $ {CBoxnew} For ((j = 0; j <$ {boxnew [@]}; j )) Boxcur [$ j] = $ {boxnew [$ j]} DONE # Display the current movement IF (($ {# boxcur [@]} == 8))))) THEN # Calculate the current square which is "take" from the top For ((j = 0, t = 4; j <8; j = 2))) DO IF ($ {Boxcur [$ J]} 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]} DONE ((BoxCurx = (straywidth - 1 - i - t) / 2)) # Display the current movement Echo -ne `drawcurbox 1` # If the square is coming out, 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 "/ 33 [$ {i}; $ {t} h" DONE # Randomly generate new squares ((iBoxNewType = random% $ {OFFSETBOX [@]})) ((iBoxNewrotate = Random% $ {Countbox [$ IBOXNEWTYPE]})) For ((j = 0, i = ($ {OFFSETBOX [$ IBOXNEWTYPE) * 8; J <8; J , i )))))) DO Boxnew [$ j] = $ {box [$ i]}; DONE ((CBOXNEW = $ {ColORTABLE [Random% $ {# colorTable [@]}]}) # Show the square pre-displayed on the right Echo -ne "/ 33 [1M / 33 [7M / 33 [3 $ {CBOXNEW} m / 33 [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 "/ 33 [$ {}; $ {t} h []" DONE echo -ne "/ 33 [0m" } # Initial drawing Function initdraw () { Clear Randombox # randomly generates square, then there is a faster in the right pre-display window. Randombox # Create blocks, the squares in the right pre-display window are updated, the original block will start falling LOCAL I T1 T2 T3 # Display Border echo -ne "/ 33 [1m" echo -ne "/ 33 [3 $ {cborder} m / 33 [4 $ {cborder} m" ((t2 = ILEFT 1))) ((T3 = ILEFT ITRAYWIDTH * 2 3)))) For ((i = 0; i DO ((T1 = i ITOP 2))) Echo -ne "/ 33 [$ {t1}; $ {t2} h || Echo -ne "/ 33 [$ {t1}; $ {t3} h ||" DONE ((T2 = ITOP ItrayHeight 2))) For ((i = 0; i DO ((t1 = i * 2 Ileft 1))) Echo -ne "/ 33 [$ i straytop}; $ {t1} h ==" echo -ne "/ 33 [$ {t2}; $ {t1} h ==" DONE echo -ne "/ 33 [0m" # Display "Score" and "Level" words echo -ne "/ 33 [1m" ((T1 = ILEFT ITRAYWIDTH * 2 7)))) ((T2 = ITOP 10))) Echo -ne "/ 33 [3 $ {cscore} m / 33 [$ {t2}; $ {t1} hscore" ((t2 = ITOP 11))) Echo -ne "/ 33 [3 $ {cscorevalue} m / 33 [$ {t2}; $ {t1} h $ {iscore} ((T2 = ITOP 13))) Echo -ne "/ 33 [3 $ {cscore} m / 33 [$ {t2}; $ {t1} hlease" ((T2 = ITOP 14))) Echo -ne "/ 33 [3 $ {cscorevalue} m / 33 [$ {t2}; $ {t1} h $ {ilevel}" echo -ne "/ 33 [0m" } # Display GameOver when exiting! Function showexit () { Local Y ((y = strayheight straytop 3))))) Echo -e "/ 33 [$ {y}; 0hgameover! / 33 [0m" exit } #Game main program start here. IF [[$ 1! = "--show"]]] THEN Bash $ 0 --SHOW & # Running this program again with parameters - SHOW RunaskeyReceiver $! # The process number of the process generated by the above line as a parameter exit Else # When you find a parameter -show, run the display function RunasDisplayer exit Fi