
After a fully featured C64 Tetris in assembler, the question arose, how far can you get with Lua and Pico8 with a sizecoded Tetris?
Here is an approach. The following features are supported:
_ Random new Tiles
_ 7 original Tiles
_ Controlling Tiles (not moving into the Border)
_ Rotating Tiles (not rotating into the Border)
_ Falling Tiles
_ Tile Background Collision
_ Testing full line
_ Score
_ Faster with the time
_ Minimal Graphics
All in one loop – Presentation & Management
Unlike in ’normal‘ programming – where the respective routines such as drawing and mangament are separated as far as possible in order to keep them understandable and maintainable – a radical integration was carried out here, which requires fewer characters.
The entire application takes place in the _draw() function. There is no separation between initialization, display and management. Everything is done in one go (all the fields are run through once, displayed, managed) with one variable: t. t is also the time variable. If t=0 it is initialized, if it is >0 the game starts. The variable is counted down, if it is 1, the block moves down one.

Playfield & Block
In principle, a distinction is made between the playfield and the block (position: n,m), whereby everything in the playfield is rendered at the end and the block is rendered above it. Consequently, there is a large loop across all fields of the playfield.
for i=0,13*20 do
x=i%13
y=i\13
v=f[i]
-- Routines for the playfield (handling and displaying)
-- Routines for the actual block (handling and displaying)
f[i]=v -- value of the field
end
Playfield
The playfield is stored linearly in the array f={} and then virtually decomposed again.
The playfield is initiated in the init block (t==0). The playfield is 11*20 (although it is clear that the width 11 is protected by Microsoft and may not actually be used).
The fields are initialized and the border is overwritten.
if(t<1)then
f[i]=0
if(y>18or x<1or x>11)f[i]=1
end
Background 0, border 1

The stones in the background are larger than 0 or 1 in the f array.

The objects are then drawn as characters in each frame in the large For Next Loop field. The bricks are drawn. The variable c depends on the field content and the current block is placed above it.
end?"\#1□",x*5,y*6,c+6
Finding and deleting complete lines and collapsing
One problem is finding and deleting lines. This is ensured by counting all values above 1.
if(v>1)g+=1 -- Hochzählen, falls der Wert grösser als 1 ist
If 11 come together, the line is filled and the flag l is set to one.
if(g>10)then
l=1s+=1
else
l=0
end
g=0
and in the next line the line above is set to -1.
if(l>0and x>0and x<12)f[i-13]=-1
All lines above this must now drop down. The routine generally only checks whether the field is -1.
if(v<0and y>0)v=f[i-13]f[i-13]=-1
Because this is applied to all fields, the entire field falls to the bottom. A row with -1 fields is then created at the top and these are permanently overwritten.
if(y<2)v=0
The controlled Block – Tile

The tiles are one of the biggest challenges. They are clearly defined, there are 7 of them and they can be rotated. For this reason, the tiles were first based on bits, converted into decimal numbers and then integrated and converted again. The rotations were also created by hand beforehand and also coded (in my opinion, programming rotation is no less challenging than using it directly).
Tiles – Forms
The tiles and their rotations were bit-coded and then integrated as Dec numbers. A routine then translates these into an array with 0/1. name: r = {}
0000
0010
0011
0001
0000
0000
0011
0110
Converted and integrated via Bin to Dec:
a={17476,61440,4369,15,51,51,51,51,198,2244,198,2244,198,612,198,612,54,1122,108,1122,550,3616,3208,142,3648,610,78,2248}
Conversion of the graphic back into a Lua array:
z=1,#a do k=a[z]for i=0,15do r[z*16-16+i]=k&0b1k=k>>1end end
Shifting through the integers.
Representation of the block
The block is located at position n,m. In the display, it overwrites the Color value. The current block+rotation is stored in the variable h.
z=x-n
w=y-m
if(z>-1 and z<4and w>-1and w<4)then
-- handling
-- display
c=h\4+2
end
In other words, a block always moves across the playing field. The playing field and highlighted the controlled block.

Block-Handling
In addition to the display, the management is also taken over. There are flags that are filled for the interaction (e, d and p). These are incremented if there is a collision to the left or right or in the entire block field. In addition, it is checked whether there could be a collision when falling (q=1).
if(f[i+13]>0and q<1)q=1
if(f[i+1]>0)d=0
if(f[i-1]>0)e=0
Falling the block & moving into the playfield
As soon as a collision occurs when falling, the q is set from 1 to 2 (below).
if(q==1)q=2
In the block in the large For-Next loop, the block is transferred to the playfield:
c=h\4+2
if(q>1)q=3v=c
and a new block is requested at random at the end of the draw function.
if(q>1)q=0m=0n=4h=flr(rnd(28))
Interaction
The interaction is handled at the end of the code by pressing a button. You can only move left and right if the flags e and d are really 0. You can only rotate if there are no collisions with the background in the entire block field (the simplest variant).
if(e>0and btnp(0))n-=1
if(d>0and btnp(1))n+=1
if(p<1and btnp(2))then
if(h%4>2)h-=4
h+=1
end
Rotating the stone simply counts up h and checks whether it has reached the 4th rotation and starts again from the beginning.
Pulling the stone downwards is actually just setting the time just before the next fall.
if(btnp(3))t=3
Conclusion
All in all, a very integrated code. Many things can hardly be made shorter in Lua, because the code simply takes up space and Tetris is actually quite a complicated game. Nevertheless, someone with a different approach will of course manage to write a shorter version.
The source code comprises 803 characters. Only by exporting it as ROM
„> export -T tetris.p8.rom“
the code is zipped again and is then „only“ 542 bytes long.
For example here a version in javascript under 512Bytes. More Javascript-Golfing you finde here >
Files
Code
The entire code looks like this:
t=0s=1f={}n=5m=1a={17476,61440,4369,15,51,51,51,51,198,2244,198,2244,198,612,198,612,54,1122,108,1122,550,3616,3208,142,3648,610,78,2248}r={}h=0q=0g=0l=0for z=1,#a do k=a[z]for i=0,15do r[z*16-16+i]=k&0b1k=k>>1end end
function _draw()cls()d=1e=1p=0for i=0,13*20do
x=i%13y=i\13if(t<1)then
f[i]=0if(y>18or x<1or x>11)f[i]=1
else
v=f[i]if(x<1)then
if(g>10)then
l=1s+=1
else
l=0
end
g=0end
if(v>1)g+=1
if(v<0and y>0)v=f[i-13]f[i-13]=-1
if(l>0and x>0and x<12)f[i-13]=-1
if(y<2)v=0
c=v
z=x-n
w=y-m
if(v<1)c=-6
if(z>-1 and z<4and w>-1and w<4)then
if(v>0)p=1
if(r[h*16+z+w*4]>0)then
c=h\4+2
if(q>1)q=3v=c
if(f[i+13]>0and q<1)q=1
if(f[i+1]>0)d=0
if(f[i-1]>0)e=0
end
end?"\#1□",x*5,y*6,c+6
f[i]=v
end
end?s
if(e>0and btnp(0))n-=1
if(d>0and btnp(1))n+=1
if(p<1and btnp(2))then
if(h%4>2)h-=4
h+=1
end
if(q>1)q=0m=0n=4h=flr(rnd(28))
if(q==1)q=2
if(btnp(3))t=3
t-=1
if(t<2)m+=1t=21-s
end