-
Notifications
You must be signed in to change notification settings - Fork 4
Tetris code comment
This is an exploration of the tetris.r3 code Pablo wrote.
Full path in the repository: https://github.com/phreda4/r3d4/blob/master/r3/games/tetris.r3
The version below was captured on 25JUL2020.
I will write comments below each block of code.
To the reader: I expect you have looked at the documentation a bit. Let us know where you are lost in the below text so that we can improve it. Thanks!
| teris r3
| PHREDA 2020
|-------------------
Lines that begin with the vertical bar | prefix are comments.
They are ignored by the interpreter/compiler UNLESS they are formatted in a special way. There are no such special comments in this source file, you can find some in main.r3 at the root of the distribution, look for lines that start with |WIN|, |LIN|..
See that typo in the first comment? You can make a pull request :)
^r3/lib/gui.r3
Here, another prefix is introduced: the ^ character.
It lets you import words that are defined in other files.
For example, in gui.r3 the word whin is defined with two colons :: instead of a single one.
This means that when gui.r3 is imported in another r3 file, the whin word is made available.
The enables the creation of modules that comprise words for specific aspects: gui, math, dated, etc..
The gui module contains graphical user interface related functionality.
^r3/lib/rand.r3
The rand module contain random numbers related functionality.
#tablero * 800 | 10 * 20 * 4
New prefix: the # character defines variables.
For tetris we need to keep track of what has been drawn where.
This variable contains space for a 2d array of 10 * 20 which is the dimension of the grid in which the game is played.
It is an array of 800 bytes.
#colores 0 $ffff $ff $ff8040 $ffff00 $ff00 $ff0000 $800080
colores is another variable that contains a list of colors encoded in RGB hex format.
0 is black
$ff is blue
etc..
#figuras
1 5 9 13
1 5 9 8
1 5 9 10
0 1 5 6
1 2 4 5
1 4 5 6
0 1 4 5
tetris is played with specific shapes. They all comprise 4 blocks (tetraminoes).
The list above contains 7 blocks of 4 numbers. The first piece is: 1 5 9 13.
Spoiler warning: hint 1
It is not about the bits in each value.Spoiler warning: hint 2
Another hint, look at this table:
col1 | col2 | col3 | col3 |
---|---|---|---|
0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 |
Spoiler warning: solution
Okay, here is the solution. Let's take this piece: 1 4 5 6
col1 | col2 | col3 | col3 |
---|---|---|---|
■ | |||
■ | ■ | ■ | |
This is how each piece is encoded!
#rota>
8 4 0 0
9 5 1 13
10 6 2 0
0 7 0 0
Now for the rotation!
In the game, when you press the UP key, the piece that is in play rotates.
So each piece has 4 orientations but above we encoded only one of them.
We therefore need a way to calculate piece rotations.
Spoiler warning: hint 1
It looks like rota> defines a 4 by 4 grid..Spoiler warning: hint 2
Let's take the numbered grid we showed earlier:
col1 | col2 | col3 | col3 |
---|---|---|---|
0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 |
Now let's put the numbers in rota> in a similar grid:
col1 | col2 | col3 | col3 |
---|---|---|---|
8 | 4 | 0 | 0 |
9 | 5 | 1 | 13 |
10 | 6 | 2 | 0 |
0 | 7 | 0 | 0 |
Spoiler warning: hint 3
The 4 by 4 grid encodes a mapping for each block to its rotated position..Spoiler warning: Solution
The center of rotation is position 5 in the grid. Rotation is counter-clockwise.To know how a block from a piece is rotated, take its value and look up in rota> what its rotated position is:
col1 | col2 | col3 | col3 |
---|---|---|---|
0 ➡️ 8 | 1 ➡️ 4 | 2 ➡️ 0 | 3 ➡️ 0 |
4 ➡️ 9 | 5 ➡️ 5 | 6 ➡️ 1 | 7 ➡️ 13 |
8 ➡️ 10 | 9 ➡️ 6 | 10 ➡️ 2 | 11 ➡️ 0 |
12 ➡️ 0 | 13 ➡️ 7 | 14 ➡️ 0 | 15 ➡️ 0 |
Example, the "L" piece which is encoded as 1 5 9 10 becomes 4 5 6 2. When drawn:
col1 | col2 | col3 | col3 |
---|---|---|---|
■ | |||
■ | ■ | ■ | |
In the context of the game, there is an issue with one of the pieces. Can you find it? Then make a pull request :)
#suma
$000 $001 $002 $003
$100 $101 $102 $103
$200 $201 $202 $203
$300 $301 $302 $303
#jugador 0 0 0 0
The current piece is encoded in the 4 values associated to jugador
#jugadors 0
#jugadorc 0
jugadorc contains the color of the current piece, ie one of the values in colores defined above
#puntos 0
#proxima 0
defines what piece will be played after the current one
#velocidad 300
defines the speed at which the current piece is falling
:tab2pant | n -- y x
dup $ff and 4 << 50 +
swap 8 >> 4 << 100 +
;
:ficha | x y --
2dup op
over 15 + over pline
over 15 + over 15 + pline
over over 15 + pline
pline poli ;
:dibuja_ficha | y x -- y x
a@+ 0? ( drop ; ) 'ink !
2dup or tab2pant ficha ;
:dibuja_tablero
'tablero >a
0 ( $1400 <?
1 ( 11 <?
dibuja_ficha
1 + ) drop
$100 + ) drop ;
:r>j
dup @ 2 << 'rota> + @ swap ;
:rota>_ficha
'jugador r>j !+ r>j !+ r>j !+ r>j ! ;
:j2t
2 << 'suma + @ jugadors + ;
:j2f
j2t
tab2pant
ficha ;
:dibuja_jugador
jugadorc 'ink !
'jugador @+ j2f @+ j2f @+ j2f @ j2f ;
:dpf
2 << 'suma + @ 15 + tab2pant ficha ;
:dibuja_prox
proxima dup 2 << 'colores + @ 'ink !
1 - 4 << 'figuras +
@+ dpf @+ dpf @+ dpf @ dpf ;
:rand1.7 | -- rand1..7
( rand dup 16 >> xor $7 and 0? drop ) ;
:nueva_ficha
proxima
'jugador
over 1 - 4 << 'figuras +
4 move | dst src cnt
2 << 'colores + @ 'jugadorc !
5 'jugadors !
rand1.7 'proxima !
;
:coord2f | coord -- realcoord
dup $f and 1 - | x
swap 8 >> 10 * +
2 << 'tablero + ;
:check | pos -- 0/pos
$1400 >? ( drop 0 ; )
dup coord2f @ 1? ( 2drop 0 ; ) drop
$ff and
0? ( drop 0 ; )
10 >? ( drop 0 ; )
;
:colision | suma -- sumareal ; 0 encontro colision
'jugador
@+ j2t pick2 + check 0? ( nip nip ; ) drop
@+ j2t pick2 + check 0? ( nip nip ; ) drop
@+ j2t pick2 + check 0? ( nip nip ; ) drop
@ j2t over + check 0? ( nip ; ) drop
;
:rcolision | -- 0/1
'jugador
@+ 2 << 'rota> + @ j2t check 0? ( nip ; ) drop
@+ 2 << 'rota> + @ j2t check 0? ( nip ; ) drop
@+ 2 << 'rota> + @ j2t check 0? ( nip ; ) drop
@ 2 << 'rota> + @ j2t check ;
:j2tt
j2t coord2f jugadorc swap ! ;
#combo
#combop 0 40 100 300 1200
:bajalinea |
'tablero dup 40 + swap a> pick2 - 2 >> move>
-1 'velocidad +!
4 'combo +! ;
:testlinea
'combop 'combo !
'tablero >a
0 ( $1400 <?
0 1 ( 11 <?
a@+ 1? ( rot 1 + rot rot ) drop
1 + ) drop
10 =? ( bajalinea ) drop
$100 + ) drop
combo @ 'puntos +!
;
:fija
'jugador @+ j2tt @+ j2tt @+ j2tt @ j2tt
testlinea
nueva_ficha
;
:logica
$100 colision 0? ( drop fija ; )
'jugadors +!
;
:mueve
colision 'jugadors +! ;
:rotar
rcolision 0? ( drop ; ) drop
rota>_ficha ;
#ntime
#dtime
:juego
cls home
$ff00 'ink !
20 20 atxy "Tetris R3" print
$444444 'ink !
128 70 286 96 fillrect
166 326 62 96 fillrect
$ffffff 'ink !
360 100 atxy puntos "%d" print
dibuja_tablero
dibuja_jugador
dibuja_prox
msec dup ntime - 'dtime +! 'ntime !
dtime velocidad >? ( dup velocidad - 'dtime !
logica
) drop
key
>esc< =? ( exit )
<dn> =? ( 250 'dtime +! )
<ri> =? ( 1 mueve )
<le> =? ( -1 mueve )
<up> =? ( rotar )
drop ;
:inicio
0 'puntos !
300 'velocidad !
msec 'ntime ! 0 'dtime !
rerand
rand1.7 'proxima !
'juego onshow
;
: inicio ;
The single colon followed by a space has a special meaning: it is the 'boot' location. This is where the execution of the program starts.
When you run this program, this word is located and 'inicio' is the first word that is executed.