Tetris in 542 bytes Lua code in Pico-8 (Sizecoding)

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
Dieser Beitrag wurde unter Uncategorized veröffentlicht. Setze ein Lesezeichen auf den Permalink.