#! /Bin/bash
# Tetris Game
#10.21.2003 xhchen <xhchen@winbond.com.tw>
# Color definition
CRed = 1
CGreen = 2
CYellow = 3
CBlue = 4
CFuchsia = 5
CCyan = 6
CWhite = 7
ColorTable = ($ cRed $ cGreen $ cYellow $ cBlue $ cFuchsia $ cCyan $ cWhite)
# Position 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 the other for the game process and display interface;
# When the former receives buttons such as upper, lower, and left buttons, it sends a signal notification to the latter.
SigRotate = 25
SigLeft = 26
SigRight = 27
SigDown = 28
SigAllDown = 29
SigExit = 30
# Definitions of blocks in section 7
# By rotating, the display style of each square may be several
Box0 = (0 0 0 1 1 0 1)
Box1 = (0 2 1 2 2 3 2 1 0 1 1 1 2 1 3)
Box2 = (0 0 0 1 1 1 1 2 0 1 1 1 1 2 0)
Box3 = (0 1 0 2 1 0 1 1 0 1 0 1 1 1 2 1)
Box4 = (0 1 0 2 1 1 1 1 1 1 1 1 1 2 2 2 2 0 1 1 2 0 2 1 0 1 0 1 1 1 1 1 2)
Box5 = (0 1 1 1 1 2 2 2 1 1 1 1 1 2 2 0 0 0 0 1 1 1 2 1 0 2 1 1 1 1 2)
Box6 = (0 1 1 1 1 2 2 1 1 1 1 1 1 2 2 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 2)
# Put all the definitions of squares in the box variable
Box = ($)
# Number of possible styles after rotation of various squares
CountBox = (1 2 2 2 4 4 4)
# Offsets in box arrays after various squares
OffsetBox = (0 1 3 5 7 11 15)
# The score to be accumulated for every speed increase
IScoreEachLevel = 50 # be greater than 7
# Runtime data
Sig = 0 # Received signal
IScore = 0 # total score
ILevel = 0 # speed level
BoxNew = () # location definition of the new falling Square
CBoxNew = 0 # color of the new falling Square
IBoxNewType = 0 # type of new falling Blocks
IBoxNewRotate = 0 # Rotation Angle of the new falling Square
BoxCur = () # location definition of the current square
CBoxCur = 0 # color of the current square
IBoxCurType = 0 # type of the current cube
IBoxCurRotate = 0 # Rotation Angle of the current square
BoxCurX =-1 # x coordinate position of the current square
BoxCurY =-1 # y coordinate position of the current square
IMap = () # background bar chart
# Initialize all background squares as-1, indicating no squares
For (I = 0; I <iTrayHeight * iTrayWidth; I ++); do iMap [$ I] =-1; done
# Main Function for receiving input processes
Function runaskeycycler ()
{
Local pidDisplayer key aKey sig cESC sTTY
PidDisplayer =
AKey = (0 0 0)
CESC = 'echo-ne ""'
CSpace = 'echo-ne ""'
# Save terminal properties. When read-s reads the terminal key, the properties of the terminal are temporarily changed.
# If the program is unfortunately killed during read-s, terminal confusion may occur,
# Terminal attributes must be restored when the program exits.
STTY = 'stty-G'
# Capture exit Signals
Trap "MyExit;" INT TERM
Trap "MyExitNoSub;" $ sigExit
# Hide the cursor
Echo-ne "[? 25l"
While (1 ))
Do
# Read input. Note-s does not show back,-n returns immediately after reading a character
Read-s-n 1 key
AKey [0] = $
AKey [1] = $
AKey [2] = $ key
Sig = 0
# Determine the Input key
If [[$ key = $ cESC & $ = $ cESC]
Then
# ESC key
MyExit
Elif [[$ ==$ cESC & $ = "["]
Then
If [[$ key = "A"]; then sig = $ sigRotate # <up key>
Elif [[$ key = "B"]; then sig = $ sigDown # <down key>
Elif [[$ key = "D"]; then sig = $ sigLeft # <left arrow>
Elif [[$ key = "C"]; then sig = $ sigRight # <right-click>
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,
Elif [[$ key = "D" | $ key = "d"]; then sig = $ sigRight # D, d
Elif [["[$ key]" = "[]"]; then sig = $ sigAllDown # Space key
Elif [[$ key = "Q" | $ key = "q"] # Q, q
Then
MyExit
Fi
If [[$ sig! = 0]
Then
# Send messages to another process
Kill-$ sig $ pidDisplayer
Fi
Done
}
# Restore before exiting
Function MyExitNoSub ()
{
Local y
# Restore terminal properties
Stty $ sTTY
(Y = iTop + iTrayHeight + 4 ))
# Show the cursor
Echo-e "[? 25 h [$; 0 H"
Exit
}
Function MyExit ()
{
# The Notification display process needs to exit
Kill-$ sigExit $ pidDisplayer
MyExitNoSub
}
# Main functions for Processing Display and game Processes
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
# Set the number of cycles based on the current speed level iLevel
For (I = 0; I <21-iLevel; I ++ ))
Do
Sleep 0.02
SigThis = $ sig
Sig = 0
# Determine whether the signal is received based on the sig variable
If (sigThis = sigRotate); then BoxRotate; # rotate
Elif (sigThis = sigLeft); then BoxLeft; # Move a column left
Elif (sigThis = sigRight); then BoxRight; # shift one column to the right
Elif (sigThis = sigDown); then BoxDown; # Drop a row
Elif (sigThis = sigAllDown); then BoxAllDown; # whereabouts to the end
Fi
Done
# Kill-$ sigDown $
BoxDown # Drop a row
Done
}
# BoxMove (y, x) to test whether to move the square in the movement to the position (x, y). If the return value is 0, the return value is OK. If the return value is 0, the return value is OK.
Function BoxMove ()
{
Local j I x y xTest yTest
YTest =
XTest =
For (j = 0; j <8; j + = 2 ))
Do
(I = j + 1 ))
(Y = $ + yTest ))
(X = $ + xTest ))
If (y <0 | y> = iTrayHeight | x <0 | x> = iTrayWidth ))
Then
# Hitting the wall
Return 1
Fi
If ($ {iMap [y * iTrayWidth + x]}! =-1 ))
Then
# Hit other existing Blocks
Return 1
Fi
Done
Return 0;
}
# Place the square in the current movement to the back