Learn Object-Oriented Programming In JavaScript by Creating Tetris (8)

Ravi da N.
4 min readMay 11, 2023

This time, we will try to use a closure that is one of the features of JavaScript, and increase the types of Minos that we can play with.

Here is a link to articles in this series: Previous Article / Next Article

Now it’s time to increase the types of Minos in our game. Since the following five Minos fit into 3 by 3 cells, we can display them with a few changes to our program.

First, we introduce the object gMinos as follows, which manages Minos. The following code fragment can be put anywhere you like, as long as it is before gGame.

const gMinos = new function() {
const _minos = [
new Mino('magenta', [1,0, 0,1, 1,1, 2,1]),
new Mino('blue' , [0,0, 0,1, 1,1, 2,1]),
new Mino('orange' , [2,0, 0,1, 1,1, 2,1]),
new Mino('green' , [1,0, 2,0, 0,1, 1,1]),
new Mino('red' , [0,0, 1,0, 1,1, 2,1]),
];

this.getNextMino = () => {
return _minos[Math.floor(Math.random() * 5)];
}
}

Next, by changing just two lines of gGame, we can see the above five types of Minos on the game field.

Please change two highlighted lines.
Z-Mino is appearing!

The reason for not being able to display I-Mino and O-Mino is due to the problem inherent in the highlighted lines of the program below.

Fig.1

The highlighted lines above can correctly calculate the coordinates after rotation only for Minos contained within 3 by 3 cells. If we want to calculate the coordinates for I-Mino correctly, the 3rd line from the top of the highlighted lines should be as follows.

We use a closure to solve this problem. A closure is the combination of a function with references to its surrounding state. A closure gives a function the ability to memorize values, so to speak.

We use the following closure in this case.
rotater3 works with blkpos8[idx] = 2 - blkpos8[idx + 1];.
rotater4 works with blkpos8[idx] = 3 - blkpos8[idx + 1];.

To give those functions to createRotaters in Mino, make the following changes to Mino. Please compare Fig.2 with Fig.1.

Fig.2
This is the same as Fig.1 above.

_minos in gMinos changes as follows.

const _minos = [
new Mino('magenta', [1,0, 0,1, 1,1, 2,1], rotater3),
new Mino('blue' , [0,0, 0,1, 1,1, 2,1], rotater3),
new Mino('orange' , [2,0, 0,1, 1,1, 2,1], rotater3),
new Mino('green' , [1,0, 2,0, 0,1, 1,1], rotater3),
new Mino('red' , [0,0, 1,0, 1,1, 2,1], rotater3),
new Mino('cyan' , [0,1, 1,1, 2,1, 3,1], rotater4),
];

Finally, let us turn to O-Mino. Since it does not rotate, we could assume that no changes need to be made to blkpos8 in highlighted lines in Fig.1. So all we have to do is to introduce rotater0 below, and to give it to the constructor of Mino.

function rotater0(blkpos8) {}

When summarizing the above, gMino is as follows.

const gMinos = new function() {
const rotater3 = createRotater(3);
const rotater4 = createRotater(4);

const _minos = [
new Mino('magenta', [1,0, 0,1, 1,1, 2,1], rotater3),
new Mino('blue' , [0,0, 0,1, 1,1, 2,1], rotater3),
new Mino('orange' , [2,0, 0,1, 1,1, 2,1], rotater3),
new Mino('green' , [1,0, 2,0, 0,1, 1,1], rotater3),
new Mino('red' , [0,0, 1,0, 1,1, 2,1], rotater3),
new Mino('cyan' , [0,1, 1,1, 2,1, 3,1], rotater4),
new Mino('yellow' , [1,0, 2,0, 1,1, 2,1], rotater0),
];

this.getNextMino = () => {
return _minos[Math.floor(Math.random() * 7)];
}

function createRotater(minoSize)
{
return (blkpos8) => {
for (let idx = 0; idx < 8; idx += 2) {
const old_x = blkpos8[idx];
blkpos8[idx] = minoSize - 1 - blkpos8[idx + 1];
blkpos8[idx + 1] = old_x;
}
}
}

function rotater0(blkpos8) {}
}

Now that we can handle all seven types of Minos, our program is finally starting to look like a Tetris program. I believe the program will be completed in the next article, so let’s definitely work together to finish it. Thanks for taking the time to read this article.

--

--

Ravi da N.

C++, C# developer. I'm happy to help so many people enjoy programming. I'd also like to share a lot of knowledge about the program!