This is my first program for the QB64PE site.
Up to now, I have never written a falling-tiles program - the sort of thing one ought to write as a hobbyist. As there are copyright and trademark issues with Tetris, I certainly would not write a Tetris program! But I see that contributor vince has written a Tetris program, and mine is very very similar in behaviour. And he says that Tetris is the ultimate test of a programmer. So, it is with some satisfaction that I offer this program. It has no unique features, but it was a pleasure to code using the QB64 graphics features.
The pieces fall and can be moved left and right (L-, R- arrow keys), rotated (Up Arrow key), dropped (Down Arrow key or Space Bar). P to pause, Esc or Q to quit.
I noted that if you leave out the large number of code lines which I used to make the graphics images, I did not take up many more lines than vince's code. Doing the same job, after all, though I have not taken the trouble to see if the methods used have any distinct similarities.
Unzip the contents into a QB64 sub-folder.
There are two versions of the code. The main version is written for a full 1080 vertical resolution monitor. The second version is for screens with lower resolution.
Tettris.zip (Size: 20.18 KB / Downloads: 41)
![[Image: Tettris.jpg]](https://i.ibb.co/d4ZbnG15/Tettris.jpg)
Unzip the attachment and place the sub-folder in the QB64 directory.
v1.0
v1.1 (small)
Up to now, I have never written a falling-tiles program - the sort of thing one ought to write as a hobbyist. As there are copyright and trademark issues with Tetris, I certainly would not write a Tetris program! But I see that contributor vince has written a Tetris program, and mine is very very similar in behaviour. And he says that Tetris is the ultimate test of a programmer. So, it is with some satisfaction that I offer this program. It has no unique features, but it was a pleasure to code using the QB64 graphics features.
The pieces fall and can be moved left and right (L-, R- arrow keys), rotated (Up Arrow key), dropped (Down Arrow key or Space Bar). P to pause, Esc or Q to quit.
I noted that if you leave out the large number of code lines which I used to make the graphics images, I did not take up many more lines than vince's code. Doing the same job, after all, though I have not taken the trouble to see if the methods used have any distinct similarities.
Unzip the contents into a QB64 sub-folder.
There are two versions of the code. The main version is written for a full 1080 vertical resolution monitor. The second version is for screens with lower resolution.
Tettris.zip (Size: 20.18 KB / Downloads: 41)
![[Image: Tettris.jpg]](https://i.ibb.co/d4ZbnG15/Tettris.jpg)
Unzip the attachment and place the sub-folder in the QB64 directory.
v1.0
Code: (Select All)
'Tettris Program v1 5/9/25 by Magdha QB64 v2.0
'Thanks to https://blog.alexrinehart.net for input images
'Program requires HD 1080 vertical resolution monitor.
'Similar to a well-known tile manipulation program
'Get higher scores if you drop the pieces and as the game speeds up
'Piece Movement:
'Left/Right Arrow Keys, move left or right
'Up Arrow Key, rotate piece counter-clockwise
'Down Arrow Key or Space Bar, drop the piece
'P, Pause/unpause
'Esc or Q, Quit
CONST False = 0, True = NOT False
RANDOMIZE (TIMER)
'Declare arrays
'Shared Arrays Grid%%(), Array%%(), Offsets%%() are used in main code and in Function
DIM SHARED Grid%%(11, 21), Array%%(7, 3, 3, 3), Offsets%%(7, 3, 1)
DIM Squares&(7), Pieces&(7, 3), InPiece%%(3)
_TITLE ("Tettris v1.0")
'Define the working grid (10x20)
'Columns 0 & 11 and row 21 need to have non-zero value so that piece in play recognises boundaries
FOR M%% = 0 TO 21
Grid%%(0, M%%) = 8
Grid%%(11, M%%) = 8
NEXT M%%
FOR N%% = 0 TO 11
Grid%%(N%%, 21) = 8
NEXT N%%
'Define Arrays for the movement of pieces within the working grid
'Array%%() values will be used to populate Grid%%() when a piece is fixed to the grid
'Laborious manual input code required for all pieces, all orientations
'Array%%() dimensions are: Piece no., orientation, x-direction, y-direction
'O-Piece
Array%%(1, 0, 0, 0) = 1
Array%%(1, 0, 1, 0) = 1
Array%%(1, 0, 0, 1) = 1
Array%%(1, 0, 1, 1) = 1
'I-Piece
Array%%(2, 0, 0, 0) = 2
Array%%(2, 0, 1, 0) = 2
Array%%(2, 0, 2, 0) = 2
Array%%(2, 0, 3, 0) = 2
Array%%(2, 1, 0, 0) = 2
Array%%(2, 1, 0, 1) = 2
Array%%(2, 1, 0, 2) = 2
Array%%(2, 1, 0, 3) = 2
'T-piece
Array%%(3, 0, 0, 0) = 3
Array%%(3, 0, 1, 0) = 3
Array%%(3, 0, 2, 0) = 3
Array%%(3, 0, 1, 1) = 3
Array%%(3, 1, 0, 0) = 3
Array%%(3, 1, 0, 1) = 3
Array%%(3, 1, 0, 2) = 3
Array%%(3, 1, 1, 1) = 3
Array%%(3, 2, 0, 1) = 3
Array%%(3, 2, 1, 1) = 3
Array%%(3, 2, 2, 1) = 3
Array%%(3, 2, 1, 0) = 3
Array%%(3, 3, 1, 0) = 3
Array%%(3, 3, 1, 1) = 3
Array%%(3, 3, 1, 2) = 3
Array%%(3, 3, 0, 1) = 3
'S-Piece
Array%%(4, 0, 1, 0) = 4
Array%%(4, 0, 2, 0) = 4
Array%%(4, 0, 0, 1) = 4
Array%%(4, 0, 1, 1) = 4
Array%%(4, 1, 0, 0) = 4
Array%%(4, 1, 0, 1) = 4
Array%%(4, 1, 1, 1) = 4
Array%%(4, 1, 1, 2) = 4
'Z-Piece
Array%%(5, 0, 0, 0) = 5
Array%%(5, 0, 1, 0) = 5
Array%%(5, 0, 1, 1) = 5
Array%%(5, 0, 2, 1) = 5
Array%%(5, 1, 0, 1) = 5
Array%%(5, 1, 0, 2) = 5
Array%%(5, 1, 1, 0) = 5
Array%%(5, 1, 1, 1) = 5
'J-Piece
Array%%(6, 0, 0, 0) = 6
Array%%(6, 0, 1, 0) = 6
Array%%(6, 0, 2, 0) = 6
Array%%(6, 0, 2, 1) = 6
Array%%(6, 1, 0, 0) = 6
Array%%(6, 1, 1, 0) = 6
Array%%(6, 1, 0, 1) = 6
Array%%(6, 1, 0, 2) = 6
Array%%(6, 2, 0, 0) = 6
Array%%(6, 2, 0, 1) = 6
Array%%(6, 2, 1, 1) = 6
Array%%(6, 2, 2, 1) = 6
Array%%(6, 3, 1, 0) = 6
Array%%(6, 3, 1, 1) = 6
Array%%(6, 3, 1, 2) = 6
Array%%(6, 3, 0, 2) = 6
'L-Piece
Array%%(7, 0, 0, 0) = 7
Array%%(7, 0, 1, 0) = 7
Array%%(7, 0, 2, 0) = 7
Array%%(7, 0, 0, 1) = 7
Array%%(7, 1, 0, 0) = 7
Array%%(7, 1, 0, 1) = 7
Array%%(7, 1, 0, 2) = 7
Array%%(7, 1, 1, 2) = 7
Array%%(7, 2, 2, 0) = 7
Array%%(7, 2, 0, 1) = 7
Array%%(7, 2, 1, 1) = 7
Array%%(7, 2, 2, 1) = 7
Array%%(7, 3, 0, 0) = 7
Array%%(7, 3, 1, 0) = 7
Array%%(7, 3, 1, 1) = 7
Array%%(7, 3, 1, 2) = 7
'Define Position offsets
'These are the starting offset values, laboriously manually input code
'These offsets are used to centre the piece as close to column 5 as possible at start
'Offsets%%() dimensions are: Piece no., orientation, x- (0) or y- (1)
Offsets%%(2, 0, 0) = -1
Offsets%%(2, 1, 1) = -1
Offsets%%(3, 0, 0) = -1
Offsets%%(3, 1, 1) = -1
Offsets%%(3, 2, 0) = -1
Offsets%%(3, 2, 1) = -1
Offsets%%(3, 3, 0) = -1
Offsets%%(3, 3, 1) = -1
Offsets%%(4, 0, 0) = -1
Offsets%%(4, 1, 1) = -1
Offsets%%(5, 0, 0) = -1
Offsets%%(5, 1, 0) = -1
Offsets%%(6, 0, 0) = -1
Offsets%%(6, 1, 1) = -1
Offsets%%(6, 2, 0) = -1
Offsets%%(6, 2, 1) = -1
Offsets%%(6, 3, 0) = -1
Offsets%%(6, 3, 1) = -1
Offsets%%(7, 0, 0) = -1
Offsets%%(7, 1, 1) = -1
Offsets%%(7, 2, 0) = -1
Offsets%%(7, 2, 1) = -1
Offsets%%(7, 3, 0) = -1
Offsets%%(7, 3, 1) = -1
'Load Squares images and generate images for all pieces, all orientations
'These images are all hardware
TempImg& = _LOADIMAGE("O-Square.png", 32)
TempImg1& = _NEWIMAGE(100, 100, 32)
FOR N%% = 0 TO 1
FOR M%% = 0 TO 1
_PUTIMAGE (N%% * 50, M%% * 50)-(49 + N%% * 50, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
NEXT N%%
Pieces&(1, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 50, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(1) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("I-Square.png", 32)
TempImg1& = _NEWIMAGE(200, 50, 32)
FOR N%% = 0 TO 3
_PUTIMAGE (N%% * 50, 0)-(49 + N%% * 50, 49), TempImg&, TempImg1&
NEXT N%%
Pieces&(2, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 200, 32)
FOR M%% = 0 TO 3
_PUTIMAGE (0, M%% * 50)-(49, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
Pieces&(2, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 50, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(2) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("T-Square.png", 32)
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 50, 0)-(49 + N%% * 50, 49), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (50, 50)-(99, 99), TempImg&, TempImg1&
Pieces&(3, 0) = HardwareImage&(TempImg1&) 'They rotate counter-clockwise
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 50, 50)-(49 + N%% * 50, 99), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (50, 0)-(99, 49), TempImg&, TempImg1&
Pieces&(3, 2) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (0, M%% * 50)-(49, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (50, 50)-(99, 99), TempImg&, TempImg1&
Pieces&(3, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (50, M%% * 50)-(99, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (0, 50)-(49, 99), TempImg&, TempImg1&
Pieces&(3, 3) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 50, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(3) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("S-Square.png", 32)
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 1 TO 2
_PUTIMAGE (N%% * 50, 0)-(49 + N%% * 50, 49), TempImg&, TempImg1&
_PUTIMAGE ((N%% - 1) * 50, 50)-(49 + (N%% - 1) * 50, 99), TempImg&, TempImg1&
NEXT N%%
Pieces&(4, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 1 TO 2
_PUTIMAGE (0, (M%% - 1) * 50)-(49, 49 + (M%% - 1) * 50), TempImg&, TempImg1&
_PUTIMAGE (50, M%% * 50)-(99, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
Pieces&(4, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 50, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(4) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("Z-Square.png", 32)
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 1 TO 2
_PUTIMAGE (N%% * 50, 50)-(49 + N%% * 50, 99), TempImg&, TempImg1&
_PUTIMAGE ((N%% - 1) * 50, 0)-(49 + (N%% - 1) * 50, 49), TempImg&, TempImg1&
NEXT N%%
Pieces&(5, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 1 TO 2
_PUTIMAGE (50, (M%% - 1) * 50)-(99, 49 + (M%% - 1) * 50), TempImg&, TempImg1&
_PUTIMAGE (0, M%% * 50)-(49, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
Pieces&(5, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 50, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(5) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("J-Square.png", 32)
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 50, 0)-(49 + N%% * 50, 49), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (100, 50)-(149, 99), TempImg&, TempImg1&
Pieces&(6, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (50, M%% * 50)-(99, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (0, 100)-(49, 149), TempImg&, TempImg1&
Pieces&(6, 3) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 50, 50)-(49 + N%% * 50, 99), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (0, 0)-(49, 49), TempImg&, TempImg1&
Pieces&(6, 2) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (0, M%% * 50)-(49, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (50, 0)-(99, 49), TempImg&, TempImg1&
Pieces&(6, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 50, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(6) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("L-Square.png", 32)
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 50, 0)-(49 + N%% * 50, 49), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (0, 50)-(49, 99), TempImg&, TempImg1&
Pieces&(7, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (50, M%% * 50)-(99, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (0, 0)-(49, 49), TempImg&, TempImg1&
Pieces&(7, 3) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(150, 100, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 50, 50)-(49 + N%% * 50, 99), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (100, 0)-(149, 49), TempImg&, TempImg1&
Pieces&(7, 2) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(100, 150, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (0, M%% * 50)-(49, 49 + M%% * 50), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (50, 100)-(99, 149), TempImg&, TempImg1&
Pieces&(7, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(50, 50, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(7) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
'Load High Score
IF _FILEEXISTS("HiScore.txt") THEN
OPEN "HiScore.txt" FOR INPUT AS #1
INPUT #1, HiScore%
CLOSE #1
ELSE
HiScore% = 0
END IF
'Screen
'HD 1080 vertical resolution monitor required.
SCREEN _NEWIMAGE(1010, 1000, 32)
_SCREENMOVE 300, 20
_DEST 0
COLOR _RGB32(0, 0, 0), _RGB32(0, 85, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\Arial.ttf", 80, "Bold")
'Software images:
_PRINTSTRING (570, 50), "Next Piece:"
_PRINTSTRING (650, 550), "Score"
IF HiScore% > 0 THEN
_PRINTSTRING (560, 800), "High Score"
H$ = LTRIM$(STR$(HiScore%))
_PRINTSTRING (755 - LEN(H$) * 22, 890), H$
END IF
'Area Delineations
LINE (500, 0)-(510, 999), _RGB(180, 0, 0), BF
LINE (500, 400)-(1009, 410), _RGB(180, 0, 0), BF
'Initial Conditions
InPlay%% = True
Count%% = 0
SpeedCount& = 0
CountLimit%% = 30
SpeedBonus! = 1
DropBonus! = 1
Paused%% = False
AddPiece%% = False
GameOver%% = False
Score% = 0
'Set up first in-play piece and next piece
InPiece%%(0) = 1 + INT(7 * RND) 'Piece in play
InPiece%%(1) = 1 + INT(7 * RND) 'Next piece
InPiece%%(2) = 5 'Start column
InPiece%%(3) = 0 'Start row
Q%% = 0 'Orientation
'Loop for play
WHILE InPlay%%
_LIMIT 60
IF NOT GameOver%% THEN
IF NOT Paused%% THEN
Count%% = Count%% + 1
SpeedCount& = SpeedCount& + 1
IF SpeedCount& / 1800 = SpeedCount& \ 1800 AND CountLimit%% >= 2 THEN
'Speed increases every 30s
'As the vertical speed of the piece increases, the score for a complete row increases
CountLimit%% = CountLimit%% - 2
SpeedBonus! = 1 + (30 - CountLimit%%) / 20
END IF
IF Count%% >= CountLimit%% THEN 'CountLimit%% sets speed of fall
IF NOT CanMove%%(InPiece%%(0), Q%%, InPiece%%(2), InPiece%%(3) + 1) THEN
'Add piece to grid
AddPiece%% = True
DropBonus! = 1
ELSE
InPiece%%(3) = InPiece%%(3) + 1
END IF
Count%% = 0
END IF
END IF
K$ = INKEY$
'Use arrow keys & Spacebar to move piece.
IF K$ <> "" THEN
Drop%% = False
IF UCASE$(K$) = "Q" OR ASC(K$) = 27 THEN
InPlay%% = False
ELSEIF UCASE$(K$) = "P" THEN
'Pause
Paused%% = NOT Paused%%
ELSEIF K$ = " " AND NOT Paused%% THEN 'Space Bar
'Drop the piece
Drop%% = True
ELSEIF ASC(K$) = 0 AND NOT Paused%% THEN
SELECT CASE RIGHT$(K$, 1)
CASE "H" 'Up Arrow Key
'Rotate the piece
IF InPiece%%(0) > 1 THEN
Q1%% = Q%% + 1
SELECT CASE InPiece%%(0)
CASE 2, 4, 5
IF Q1%% > 1 THEN Q1%% = 0
CASE 3, 6, 7
IF Q1%% > 3 THEN Q1%% = 0
END SELECT
IF CanMove%%(InPiece%%(0), Q1%%, InPiece%%(2), InPiece%%(3)) THEN
Q%% = Q1%%
END IF
END IF
CASE "M" 'Right Arrow Key
'Move Right
IF CanMove%%(InPiece%%(0), Q%%, InPiece%%(2) + 1, InPiece%%(3)) THEN InPiece%%(2) = InPiece%%(2) + 1
CASE "K" 'Left Arrow Key
'Move Left
IF CanMove%%(InPiece%%(0), Q%%, InPiece%%(2) - 1, InPiece%%(3)) THEN InPiece%%(2) = InPiece%%(2) - 1
CASE "P" 'Down Arrow Key
'Drop the piece
Drop%% = True
END SELECT
END IF
IF Drop%% THEN
M%% = InPiece%%(3) + 1
MStart%% = M%%
WHILE Drop%% AND M%% <= 21
IF NOT CanMove%%(InPiece%%(0), Q%%, InPiece%%(2), M%%) THEN
InPiece%%(3) = M%% - 1
Drop%% = False
AddPiece%% = True
'The larger the distance of drop, the higher the score for a complete row
DropBonus! = 1 + (InPiece%%(3) + 1 - MStart%%) / 20
ELSE
M%% = M%% + 1
END IF
WEND
END IF
K$ = ""
END IF
IF AddPiece%% THEN
'Add the old piece to the grid
FOR M%% = 0 TO 3
FOR N%% = 0 TO 3
IF Array%%(InPiece%%(0), Q%%, N%%, M%%) <> 0 THEN Grid%%(InPiece%%(2) + Offsets%%(InPiece%%(0), Q%%, 0) + N%%, InPiece%%(3) + Offsets%%(InPiece%%(0), Q%%, 1) + M%%) = Array%%(InPiece%%(0), Q%%, N%%, M%%)
NEXT N%%
NEXT M%%
'Start new piece
InPiece%%(0) = InPiece%%(1)
InPiece%%(1) = 1 + INT(7 * RND)
InPiece%%(2) = 5
InPiece%%(3) = 0
Q%% = 0
AddPiece%% = False
Count%% = 0
IF NOT CanMove%%(InPiece%%(0), Q%%, InPiece%%(2), InPiece%%(3)) THEN
'New piece has nowhere to move
GameOver%% = True
ELSE
'Remove all filled lines and drop down - the essence of this game
ReDoFromStart%% = True
MStart%% = 20
WHILE ReDoFromStart%%
NoFull%% = 0
FOR N%% = 1 TO 10
IF Grid%%(N%%, MStart%%) <> 0 THEN NoFull%% = NoFull%% + 1
NEXT N%%
IF NoFull%% = 0 THEN
ReDoFromStart%% = False
ELSEIF NoFull%% = 10 THEN
Score% = Score% + CINT(10 * DropBonus! * SpeedBonus!)
Scan%% = True
M%% = MStart%%
WHILE Scan%%
NextLineFull%% = 0
FOR N%% = 1 TO 10
Grid%%(N%%, M%%) = Grid%%(N%%, M%% - 1)
NextLineFull%% = NextLineFull%% + Grid%%(N%%, M%% - 1)
NEXT N%%
IF NextLineFull%% = 0 THEN
Scan%% = False
ELSE
M%% = M%% - 1
END IF
WEND
ELSE
MStart%% = MStart%% - 1
END IF
WEND
END IF
END IF
END IF
'Display the score
COLOR _RGB32(0, 0, 0)
S$ = LTRIM$(STR$(Score%))
_PRINTSTRING (755 - LEN(S$) * 22, 640), S$ + " "
IF NOT GameOver%% THEN
'Display squares existing in grid
FOR M%% = 0 TO 20
FOR N%% = 1 TO 10
IF Grid%%(N%%, M%%) <> 0 THEN _PUTIMAGE ((N%% - 1) * 50, (M%% - 1) * 50), Squares&(Grid%%(N%%, M%%))
NEXT N%%
NEXT M%%
'Display the piece in play
_PUTIMAGE ((InPiece%%(2) - 1 + Offsets%%(InPiece%%(0), Q%%, 0)) * 50, (InPiece%%(3) - 1 + Offsets%%(InPiece%%(0), Q%%, 1)) * 50), Pieces&(InPiece%%(0), Q%%)
'Display the next piece
_PUTIMAGE (755 - 75 + Offsets%%(InPiece%%(1), 0, 0), 150), Pieces&(InPiece%%(1), 0)
ELSE
'Display Game Over Banner
COLOR _RGB32(100, 0, 0)
_PRINTSTRING (40, 200), "Game Over"
_PRINTSTRING (64, 400), "Press Any"
_PRINTSTRING (120, 500), "Key To"
_PRINTSTRING (140, 600), "Finish"
_PRINTSTRING (570, 50), " "
IF INKEY$ <> "" THEN InPlay%% = False
END IF
_DISPLAY
WEND
CLS
IF Score% > HiScore% THEN
HiScore% = Score%
OPEN "HiScore.txt" FOR OUTPUT AS #2
WRITE #2, HiScore%
CLOSE #2
END IF
SYSTEM
FUNCTION HardwareImage& (ImageName&)
HardwareImage& = _COPYIMAGE(ImageName&, 33)
_FREEIMAGE ImageName&
END FUNCTION
FUNCTION CanMove%% (P%%, QA%%, IPos%%, JPos%%)
'How this is used for Rotation, Sideways Movement & Downward Movement:
'Make temporary translation & see if any non-zero cells co-incide. If so, translation not allowed.
'Movement down, as above then stop and add.
'Drop, as above, trying each row intervening sequentially
I%% = 0
J%% = 0
ItsOK%% = True
WHILE ItsOK%% AND I%% <= 3
A%% = IPos%% + Offsets%%(P%%, QA%%, 0) + I%%
B%% = JPos%% + Offsets%%(P%%, QA%%, 1) + J%%
IF A%% >= 0 AND A%% <= 11 AND B%% >= 0 AND B%% <= 21 THEN
IF (Grid%%(A%%, B%%)) > 0 AND (Array%%(P%%, QA%%, I%%, J%%) > 0) THEN ItsOK%% = False
END IF
J%% = J%% + 1
IF J%% > 3 THEN
J%% = 0
I%% = I%% + 1
END IF
WEND
IF ItsOK%% THEN
CanMove%% = True
ELSE
CanMove%% = False
END IF
END FUNCTION
v1.1 (small)
Code: (Select All)
'Tettris Program v1 5/9/25 by Magdha QB64 v2.0
'Thanks to https://blog.alexrinehart.net for input images
'Smaller window version for non- HD 1080 vertical resolution monitor.
'Similar to a well-known tile manipulation program
'Get higher scores if you drop the pieces and as the game speeds up
'Piece Movement:
'Left/Right Arrow Keys, move left or right
'Up Arrow Key, rotate piece counter-clockwise
'Down Arrow Key or Space Bar, drop the piece
'P, Pause/unpause
'Esc or Q, Quit
CONST False = 0, True = NOT False
RANDOMIZE (TIMER)
'Declare arrays
'Shared Arrays Grid%%(), Array%%(), Offsets%%() are used in main code and in Function
DIM SHARED Grid%%(11, 21), Array%%(7, 3, 3, 3), Offsets%%(7, 3, 1)
DIM Squares&(7), Pieces&(7, 3), InPiece%%(3)
_TITLE ("Tettris v1.1")
'Define the working grid (10x20)
'Columns 0 & 11 and row 21 need to have non-zero value so that piece in play recognises boundaries
FOR M%% = 0 TO 21
Grid%%(0, M%%) = 8
Grid%%(11, M%%) = 8
NEXT M%%
FOR N%% = 0 TO 11
Grid%%(N%%, 21) = 8
NEXT N%%
'Define Arrays for the movement of pieces within the working grid
'Array%%() values will be used to populate Grid%%() when a piece is fixed to the grid
'Laborious manual input code required for all pieces, all orientations
'Array%%() dimensions are: Piece no., orientation, x-direction, y-direction
'O-Piece
Array%%(1, 0, 0, 0) = 1
Array%%(1, 0, 1, 0) = 1
Array%%(1, 0, 0, 1) = 1
Array%%(1, 0, 1, 1) = 1
'I-Piece
Array%%(2, 0, 0, 0) = 2
Array%%(2, 0, 1, 0) = 2
Array%%(2, 0, 2, 0) = 2
Array%%(2, 0, 3, 0) = 2
Array%%(2, 1, 0, 0) = 2
Array%%(2, 1, 0, 1) = 2
Array%%(2, 1, 0, 2) = 2
Array%%(2, 1, 0, 3) = 2
'T-piece
Array%%(3, 0, 0, 0) = 3
Array%%(3, 0, 1, 0) = 3
Array%%(3, 0, 2, 0) = 3
Array%%(3, 0, 1, 1) = 3
Array%%(3, 1, 0, 0) = 3
Array%%(3, 1, 0, 1) = 3
Array%%(3, 1, 0, 2) = 3
Array%%(3, 1, 1, 1) = 3
Array%%(3, 2, 0, 1) = 3
Array%%(3, 2, 1, 1) = 3
Array%%(3, 2, 2, 1) = 3
Array%%(3, 2, 1, 0) = 3
Array%%(3, 3, 1, 0) = 3
Array%%(3, 3, 1, 1) = 3
Array%%(3, 3, 1, 2) = 3
Array%%(3, 3, 0, 1) = 3
'S-Piece
Array%%(4, 0, 1, 0) = 4
Array%%(4, 0, 2, 0) = 4
Array%%(4, 0, 0, 1) = 4
Array%%(4, 0, 1, 1) = 4
Array%%(4, 1, 0, 0) = 4
Array%%(4, 1, 0, 1) = 4
Array%%(4, 1, 1, 1) = 4
Array%%(4, 1, 1, 2) = 4
'Z-Piece
Array%%(5, 0, 0, 0) = 5
Array%%(5, 0, 1, 0) = 5
Array%%(5, 0, 1, 1) = 5
Array%%(5, 0, 2, 1) = 5
Array%%(5, 1, 0, 1) = 5
Array%%(5, 1, 0, 2) = 5
Array%%(5, 1, 1, 0) = 5
Array%%(5, 1, 1, 1) = 5
'J-Piece
Array%%(6, 0, 0, 0) = 6
Array%%(6, 0, 1, 0) = 6
Array%%(6, 0, 2, 0) = 6
Array%%(6, 0, 2, 1) = 6
Array%%(6, 1, 0, 0) = 6
Array%%(6, 1, 1, 0) = 6
Array%%(6, 1, 0, 1) = 6
Array%%(6, 1, 0, 2) = 6
Array%%(6, 2, 0, 0) = 6
Array%%(6, 2, 0, 1) = 6
Array%%(6, 2, 1, 1) = 6
Array%%(6, 2, 2, 1) = 6
Array%%(6, 3, 1, 0) = 6
Array%%(6, 3, 1, 1) = 6
Array%%(6, 3, 1, 2) = 6
Array%%(6, 3, 0, 2) = 6
'L-Piece
Array%%(7, 0, 0, 0) = 7
Array%%(7, 0, 1, 0) = 7
Array%%(7, 0, 2, 0) = 7
Array%%(7, 0, 0, 1) = 7
Array%%(7, 1, 0, 0) = 7
Array%%(7, 1, 0, 1) = 7
Array%%(7, 1, 0, 2) = 7
Array%%(7, 1, 1, 2) = 7
Array%%(7, 2, 2, 0) = 7
Array%%(7, 2, 0, 1) = 7
Array%%(7, 2, 1, 1) = 7
Array%%(7, 2, 2, 1) = 7
Array%%(7, 3, 0, 0) = 7
Array%%(7, 3, 1, 0) = 7
Array%%(7, 3, 1, 1) = 7
Array%%(7, 3, 1, 2) = 7
'Define Position offsets
'These are the starting offset values, laboriously manually input code
'These offsets are used to centre the piece as close to column 5 as possible at start
'Offsets%%() dimensions are: Piece no., orientation, x- (0) or y- (1)
Offsets%%(2, 0, 0) = -1
Offsets%%(2, 1, 1) = -1
Offsets%%(3, 0, 0) = -1
Offsets%%(3, 1, 1) = -1
Offsets%%(3, 2, 0) = -1
Offsets%%(3, 2, 1) = -1
Offsets%%(3, 3, 0) = -1
Offsets%%(3, 3, 1) = -1
Offsets%%(4, 0, 0) = -1
Offsets%%(4, 1, 1) = -1
Offsets%%(5, 0, 0) = -1
Offsets%%(5, 1, 0) = -1
Offsets%%(6, 0, 0) = -1
Offsets%%(6, 1, 1) = -1
Offsets%%(6, 2, 0) = -1
Offsets%%(6, 2, 1) = -1
Offsets%%(6, 3, 0) = -1
Offsets%%(6, 3, 1) = -1
Offsets%%(7, 0, 0) = -1
Offsets%%(7, 1, 1) = -1
Offsets%%(7, 2, 0) = -1
Offsets%%(7, 2, 1) = -1
Offsets%%(7, 3, 0) = -1
Offsets%%(7, 3, 1) = -1
'Load Squares images and generate images for all pieces, all orientations
'These images are all hardware
TempImg& = _LOADIMAGE("O-Square.png", 32)
TempImg1& = _NEWIMAGE(60, 60, 32)
FOR N%% = 0 TO 1
FOR M%% = 0 TO 1
_PUTIMAGE (N%% * 30, M%% * 30)-(29 + N%% * 30, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
NEXT N%%
Pieces&(1, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 30, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(1) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("I-Square.png", 32)
TempImg1& = _NEWIMAGE(120, 30, 32)
FOR N%% = 0 TO 3
_PUTIMAGE (N%% * 30, 0)-(29 + N%% * 30, 29), TempImg&, TempImg1&
NEXT N%%
Pieces&(2, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 120, 32)
FOR M%% = 0 TO 3
_PUTIMAGE (0, M%% * 30)-(29, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
Pieces&(2, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 30, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(2) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("T-Square.png", 32)
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 30, 0)-(29 + N%% * 30, 29), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (30, 30)-(59, 59), TempImg&, TempImg1&
Pieces&(3, 0) = HardwareImage&(TempImg1&) 'They rotate counter-clockwise
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 30, 30)-(29 + N%% * 30, 59), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (30, 0)-(59, 29), TempImg&, TempImg1&
Pieces&(3, 2) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (0, M%% * 30)-(29, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (30, 30)-(59, 59), TempImg&, TempImg1&
Pieces&(3, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (30, M%% * 30)-(59, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (0, 30)-(29, 59), TempImg&, TempImg1&
Pieces&(3, 3) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 30, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(3) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("S-Square.png", 32)
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 1 TO 2
_PUTIMAGE (N%% * 30, 0)-(29 + N%% * 30, 29), TempImg&, TempImg1&
_PUTIMAGE ((N%% - 1) * 30, 30)-(29 + (N%% - 1) * 30, 59), TempImg&, TempImg1&
NEXT N%%
Pieces&(4, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 1 TO 2
_PUTIMAGE (0, (M%% - 1) * 30)-(29, 29 + (M%% - 1) * 30), TempImg&, TempImg1&
_PUTIMAGE (30, M%% * 30)-(59, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
Pieces&(4, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 30, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(4) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("Z-Square.png", 32)
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 1 TO 2
_PUTIMAGE (N%% * 30, 30)-(29 + N%% * 30, 59), TempImg&, TempImg1&
_PUTIMAGE ((N%% - 1) * 30, 0)-(29 + (N%% - 1) * 30, 29), TempImg&, TempImg1&
NEXT N%%
Pieces&(5, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 1 TO 2
_PUTIMAGE (30, (M%% - 1) * 30)-(59, 29 + (M%% - 1) * 30), TempImg&, TempImg1&
_PUTIMAGE (0, M%% * 30)-(29, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
Pieces&(5, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 30, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(5) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("J-Square.png", 32)
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 30, 0)-(29 + N%% * 30, 29), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (60, 30)-(129, 59), TempImg&, TempImg1&
Pieces&(6, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (30, M%% * 30)-(59, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (0, 60)-(29, 129), TempImg&, TempImg1&
Pieces&(6, 3) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 30, 30)-(29 + N%% * 30, 59), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (0, 0)-(29, 29), TempImg&, TempImg1&
Pieces&(6, 2) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (0, M%% * 30)-(29, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (30, 0)-(59, 29), TempImg&, TempImg1&
Pieces&(6, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 30, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(6) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
TempImg& = _LOADIMAGE("L-Square.png", 32)
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 30, 0)-(29 + N%% * 30, 29), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (0, 30)-(29, 59), TempImg&, TempImg1&
Pieces&(7, 0) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (30, M%% * 30)-(59, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (0, 0)-(29, 29), TempImg&, TempImg1&
Pieces&(7, 3) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(90, 60, 32)
FOR N%% = 0 TO 2
_PUTIMAGE (N%% * 30, 30)-(29 + N%% * 30, 59), TempImg&, TempImg1&
NEXT N%%
_PUTIMAGE (60, 0)-(129, 29), TempImg&, TempImg1&
Pieces&(7, 2) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(60, 90, 32)
FOR M%% = 0 TO 2
_PUTIMAGE (0, M%% * 30)-(29, 29 + M%% * 30), TempImg&, TempImg1&
NEXT M%%
_PUTIMAGE (30, 60)-(59, 129), TempImg&, TempImg1&
Pieces&(7, 1) = HardwareImage&(TempImg1&)
TempImg1& = _NEWIMAGE(30, 30, 32)
_PUTIMAGE , TempImg&, TempImg1&
Squares&(7) = HardwareImage&(TempImg1&)
_FREEIMAGE TempImg&
'Load High Score
IF _FILEEXISTS("HiScore.txt") THEN
OPEN "HiScore.txt" FOR INPUT AS #1
INPUT #1, HiScore%
CLOSE #1
ELSE
HiScore% = 0
END IF
'Screen
'HD 1080 vertical resolution monitor required.
SCREEN _NEWIMAGE(606, 600, 32)
_SCREENMOVE 180, 20
_DEST 0
COLOR _RGB32(0, 0, 0), _RGB32(0, 85, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\Arial.ttf", 48, "Bold")
'Software images:
_PRINTSTRING (342, 30), "Next Piece:"
_PRINTSTRING (390, 330), "Score"
IF HiScore% > 0 THEN
_PRINTSTRING (336, 480), "High Score"
H$ = LTRIM$(STR$(HiScore%))
_PRINTSTRING (453 - LEN(H$) * 13, 534), H$
END IF
'Area Delineations
LINE (300, 0)-(306, 599), _RGB(180, 0, 0), BF
LINE (300, 240)-(605, 246), _RGB(180, 0, 0), BF
'Initial Conditions
InPlay%% = True
Count%% = 0
SpeedCount& = 0
CountLimit%% = 30
SpeedBonus! = 1
DropBonus! = 1
Paused%% = False
AddPiece%% = False
GameOver%% = False
Score% = 0
'Set up first in-play piece and next piece
InPiece%%(0) = 1 + INT(7 * RND) 'Piece in play
InPiece%%(1) = 1 + INT(7 * RND) 'Next piece
InPiece%%(2) = 5 'Start column
InPiece%%(3) = 0 'Start row
Q%% = 0 'Orientation
'Loop for play
WHILE InPlay%%
_LIMIT 60
IF NOT GameOver%% THEN
IF NOT Paused%% THEN
Count%% = Count%% + 1
SpeedCount& = SpeedCount& + 1
IF SpeedCount& / 1800 = SpeedCount& \ 1800 AND CountLimit%% >= 2 THEN
'Speed increases every 30s
'As the vertical speed of the piece increases, the score for a complete row increases
CountLimit%% = CountLimit%% - 2
SpeedBonus! = 1 + (30 - CountLimit%%) / 20
END IF
IF Count%% >= CountLimit%% THEN 'CountLimit%% sets speed of fall
IF NOT CanMove%%(InPiece%%(0), Q%%, InPiece%%(2), InPiece%%(3) + 1) THEN
'Add piece to grid
AddPiece%% = True
DropBonus! = 1
ELSE
InPiece%%(3) = InPiece%%(3) + 1
END IF
Count%% = 0
END IF
END IF
K$ = INKEY$
'Use arrow keys & Spacebar to move piece.
IF K$ <> "" THEN
Drop%% = False
IF UCASE$(K$) = "Q" OR ASC(K$) = 27 THEN
InPlay%% = False
ELSEIF UCASE$(K$) = "P" THEN
'Pause
Paused%% = NOT Paused%%
ELSEIF K$ = " " AND NOT Paused%% THEN 'Space Bar
'Drop the piece
Drop%% = True
ELSEIF ASC(K$) = 0 AND NOT Paused%% THEN
SELECT CASE RIGHT$(K$, 1)
CASE "H" 'Up Arrow Key
'Rotate the piece
IF InPiece%%(0) > 1 THEN
Q1%% = Q%% + 1
SELECT CASE InPiece%%(0)
CASE 2, 4, 5
IF Q1%% > 1 THEN Q1%% = 0
CASE 3, 6, 7
IF Q1%% > 3 THEN Q1%% = 0
END SELECT
IF CanMove%%(InPiece%%(0), Q1%%, InPiece%%(2), InPiece%%(3)) THEN
Q%% = Q1%%
END IF
END IF
CASE "M" 'Right Arrow Key
'Move Right
IF CanMove%%(InPiece%%(0), Q%%, InPiece%%(2) + 1, InPiece%%(3)) THEN InPiece%%(2) = InPiece%%(2) + 1
CASE "K" 'Left Arrow Key
'Move Left
IF CanMove%%(InPiece%%(0), Q%%, InPiece%%(2) - 1, InPiece%%(3)) THEN InPiece%%(2) = InPiece%%(2) - 1
CASE "P" 'Down Arrow Key
'Drop the piece
Drop%% = True
END SELECT
END IF
IF Drop%% THEN
M%% = InPiece%%(3) + 1
MStart%% = M%%
WHILE Drop%% AND M%% <= 21
IF NOT CanMove%%(InPiece%%(0), Q%%, InPiece%%(2), M%%) THEN
InPiece%%(3) = M%% - 1
Drop%% = False
AddPiece%% = True
'The larger the distance of drop, the higher the score for a complete row
DropBonus! = 1 + (InPiece%%(3) + 1 - MStart%%) / 20
ELSE
M%% = M%% + 1
END IF
WEND
END IF
K$ = ""
END IF
IF AddPiece%% THEN
'Add the old piece to the grid
FOR M%% = 0 TO 3
FOR N%% = 0 TO 3
IF Array%%(InPiece%%(0), Q%%, N%%, M%%) <> 0 THEN Grid%%(InPiece%%(2) + Offsets%%(InPiece%%(0), Q%%, 0) + N%%, InPiece%%(3) + Offsets%%(InPiece%%(0), Q%%, 1) + M%%) = Array%%(InPiece%%(0), Q%%, N%%, M%%)
NEXT N%%
NEXT M%%
'Start new piece
InPiece%%(0) = InPiece%%(1)
InPiece%%(1) = 1 + INT(7 * RND)
InPiece%%(2) = 5
InPiece%%(3) = 0
Q%% = 0
AddPiece%% = False
Count%% = 0
IF NOT CanMove%%(InPiece%%(0), Q%%, InPiece%%(2), InPiece%%(3)) THEN
'New piece has nowhere to move
GameOver%% = True
ELSE
'Remove all filled lines and drop down - the essence of this game
ReDoFromStart%% = True
MStart%% = 20
WHILE ReDoFromStart%%
NoFull%% = 0
FOR N%% = 1 TO 10
IF Grid%%(N%%, MStart%%) <> 0 THEN NoFull%% = NoFull%% + 1
NEXT N%%
IF NoFull%% = 0 THEN
ReDoFromStart%% = False
ELSEIF NoFull%% = 10 THEN
Score% = Score% + CINT(10 * DropBonus! * SpeedBonus!)
Scan%% = True
M%% = MStart%%
WHILE Scan%%
NextLineFull%% = 0
FOR N%% = 1 TO 10
Grid%%(N%%, M%%) = Grid%%(N%%, M%% - 1)
NextLineFull%% = NextLineFull%% + Grid%%(N%%, M%% - 1)
NEXT N%%
IF NextLineFull%% = 0 THEN
Scan%% = False
ELSE
M%% = M%% - 1
END IF
WEND
ELSE
MStart%% = MStart%% - 1
END IF
WEND
END IF
END IF
END IF
'Display the score
COLOR _RGB32(0, 0, 0)
S$ = LTRIM$(STR$(Score%))
_PRINTSTRING (453 - LEN(S$) * 13, 384), S$ + " "
IF NOT GameOver%% THEN
'Display squares existing in grid
FOR M%% = 0 TO 20
FOR N%% = 1 TO 10
IF Grid%%(N%%, M%%) <> 0 THEN _PUTIMAGE ((N%% - 1) * 30, (M%% - 1) * 30), Squares&(Grid%%(N%%, M%%))
NEXT N%%
NEXT M%%
'Display the piece in play
_PUTIMAGE ((InPiece%%(2) - 1 + Offsets%%(InPiece%%(0), Q%%, 0)) * 30, (InPiece%%(3) - 1 + Offsets%%(InPiece%%(0), Q%%, 1)) * 30), Pieces&(InPiece%%(0), Q%%)
'Display the next piece
_PUTIMAGE (453 - 45 + Offsets%%(InPiece%%(1), 0, 0), 90), Pieces&(InPiece%%(1), 0)
ELSE
'Display Game Over Banner
COLOR _RGB32(100, 0, 0)
_PRINTSTRING (24, 120), "Game Over"
_PRINTSTRING (38, 240), "Press Any"
_PRINTSTRING (72, 300), "Key To"
_PRINTSTRING (84, 360), "Finish"
_PRINTSTRING (342, 30), " "
IF INKEY$ <> "" THEN InPlay%% = False
END IF
_DISPLAY
WEND
CLS
IF Score% > HiScore% THEN
HiScore% = Score%
OPEN "HiScore.txt" FOR OUTPUT AS #2
WRITE #2, HiScore%
CLOSE #2
END IF
SYSTEM
FUNCTION HardwareImage& (ImageName&)
HardwareImage& = _COPYIMAGE(ImageName&, 33)
_FREEIMAGE ImageName&
END FUNCTION
FUNCTION CanMove%% (P%%, QA%%, IPos%%, JPos%%)
'How this is used for Rotation, Sideways Movement & Downward Movement:
'Make temporary translation & see if any non-zero cells co-incide. If so, translation not allowed.
'Movement down, as above then stop and add.
'Drop, as above, trying each row intervening sequentially
I%% = 0
J%% = 0
ItsOK%% = True
WHILE ItsOK%% AND I%% <= 3
A%% = IPos%% + Offsets%%(P%%, QA%%, 0) + I%%
B%% = JPos%% + Offsets%%(P%%, QA%%, 1) + J%%
IF A%% >= 0 AND A%% <= 11 AND B%% >= 0 AND B%% <= 21 THEN
IF (Grid%%(A%%, B%%)) > 0 AND (Array%%(P%%, QA%%, I%%, J%%) > 0) THEN ItsOK%% = False
END IF
J%% = J%% + 1
IF J%% > 3 THEN
J%% = 0
I%% = I%% + 1
END IF
WEND
IF ItsOK%% THEN
CanMove%% = True
ELSE
CanMove%% = False
END IF
END FUNCTION


