Cloning the mechanics of NES Tetris — a few questions

Thread in 'Research & Development' started by furious programming, 6 Aug 2021.

  1. I'm working on my new Tetris project, which will ultimately implement the piece control mechanics, compatible with the NES version. Most things are fine to implement, but some are difficult to translate and implement in a modern language. Mainly because I'm not an expert in neither Assembly nor game development for this console. I don't understand two things related to the main mechanics — one is for the fall of the pieces and the other is for the generator. For now, let's focus on the first. Thank you for any help.


    While writing my code, I mainly use the article Applying Artificial Intelligence to Nintendo Tetris. In the Dropping Tetriminos section, the code responsible for the falling of pieces is described. The first thing is one of the conditions that test the pressed buttons. I marked this fragment below in the picture:

    buttons.png

    What exactly does this condition mean? Which buttons exactly must be pressed and which must be released for this condition to be met? Should there be a distinction between pressed and just pressed?


    The second problem is that FallTimer is zeroed in this example, but not incremented anywhere. The only reference to incrementing is in the short paragraph below this snippet:
    Unfortunately, I am not able to determine myself where to do it. In many places I can insert an incrementation and the gravity will work properly, but the soft-drop will be permanent — if I press the down arrow and keep it pressed, the soft-drop will not expire until the arrow is released (it will not expire after locking the piece, so the next spawned piece will be soft-dropped immediately).

    Does anyone know where this counter is to be incremented and what conditions must be met to perform the incrementation?
     
  2. Anyway, no matter — I will implement the fall of pieces in my own way, soft-drop and hard-drop too, because it's too easy to waste the time translating assembly. So there was the second problem related to the generation of bricks, which I am not able to deal with myself yet.


    I currently have an LFSR implemented which works fine — it generates consecutive numbers according to the original. However, I have a problem with understanding exactly how picking the next piece works. As a template, I use the code from the Picking Tetriminos section. I have marked the instructions for which I have questions:

    generator.png

    My conclusions below.

    The Index variable is single-byte, and its increment by the value of the SpawnCount is supposed to loop this counter when its value exceeds 255. Looping probably will not affect the modulo result anyway, so I can use multibyte counter — I will check this later.

    As I understand, SpawnID contains the Tetrimino type and is intended to be initialized at the start of the game with a value pointing to the T-Piece. On the other hand, SpawnTable is an array that contains as many arrays as there are Tetrimino types, and each sub-array contains 8 Tetrimino identifiers.

    Did I get something wrong?


    My question is — how do I declare such an array in a normal programming language such as C/C++, Pascal or Java? This looks like a two-dimensional array, though there is a pseudo-code in the comment of this code treating it as one-dimensional:

    spawn table.png

    Since SpawnTable contains both columns and rows (it seems to be two-dimensional):

    table.png

    it takes two indices to get a value from it. So what is the second index?
     
    Last edited: 6 Aug 2021
  3. According to what I found in the TetrisNESDisasm project, it turns out that SpawnTable is a one-dimensional array after all. It's just a sequence of eight bytes with Tetrimino orientations:

    spawntable.png

    This data is declared in the main.asm unit.

    Considering that in my project I store the Tetrimino ID and its orientation in two separate variables, the whole thing is simply using modulo from the seed as the ID of the new piece. And in case of drawing the same piece or wrong ID, it is enough for LFSR to generate a new seed, execute modulo and use the result as a new Tetrimino ID.

    I am very disappointed that this is how it is done in the original game. I expected this algorithm to be a bit more advanced, and here it turns out to be much more primitive than I thought. I'm not surprised that the game keeps generating shitty sequences over and over again. ;)

    Ok, I already know how this RNG works. Problem solved.
     
    Last edited: 9 Aug 2021

Share This Page