Data structure and implementation of Tetris

Source: Internet
Author: User

Recently, I have made some analysis on the implementation of Tetris in open-source QT, And I will record it by the way. This document complies with gnu gpl.

 

I always wanted to make my own games. Tetris or wuziqi should be examples that beginners want to complete. Recently I found some code about RIS, I found that the example in QT is better. It implements a good class with C ++, and I also used Win32's GDI to rewrite a version without QT. Here we record the implementation of tetrix in QT.

 

1. Class Structure:

 

Qt's tetrix is under examples/widgets/tetrix in its installation directory (I am using qt4.2.3 for Windows opensource mingw version ). There are two classes: ririxpiece and tetrixboard. Here, tetrixpiece defines various shape blocks in tetrix, and tetrixboard implements the implementation and logic of the entire game. To be honest, after reading the QT code for a few days, I found that using QT to write GUI is still very convenient. The modules inside are very clear, the code written is very beautiful, and the readability is extremely high. It is much clearer than the projects generated using the MFC wizard, and it saves a lot of effort to write code with Win32.

 

2. Data Structure:

 

Some Rix implementations have been found from codeguru and codeproject before the QT tetrix is selected. However, some graphics libraries (such as cximage) are not used ), the data structure definition is redundant. Of course, before that, I also thought about the implementation of its data structure. You can also think about how to define its data structure for the square inside?

 

My idea was to define a 4x4 matrix (simply using a two-dimensional array) and define several states to represent each graph. For example, to define a long bar image, we need such a two-dimensional array:

 

1 0 0 0

1 0 0 0

1 0 0 0

1 0 0 0

 

Here, 1 indicates that there is a graph, and 0 indicates that there is no image. In this way, we can write a simple image driver. After sending a two-dimensional array style to it, we can help to draw it out. Then, for a long graph, we need two such matrices. The square is better. Only one box is needed, but the Z shape and the T-shaped figure in it are represented by four such arrays. This implementation is feasible, but in the definition of its data structure, the Code requires a long static three-dimensional array to represent these images.

 

The implementation of the tetrix board should be simpler, but the logic control in it is complicated. It only needs a large matrix to store the state of the entire graphic area.

 

Of course, there are other representation methods that we will not discuss much. Let's take a look at the implementation in the QT example: tetrixpiece. h and tetrixpiece. cpp

 

/*************************************** *************************************
** Tetrixpiece. h

**
** Copyright (c) 2004-2007 trolltech asa. All rights reserved.
**
**************************************** ************************************/

# Ifndef tetrixpiece_h
# Define tetrixpiece_h

Enum tetrixshape {noshape, zshape, sshape, lineshape, tshape, squareshape,
Lshape, mirroredlshape };

Class ririxpiece
{
Public:
Tetrixpiece () {setshape (noshape );}

Void setrandomshape ();
Void setshape (tetrixshape shape );

Tetrixshape shape () const {return pieceshape ;}
Int X (INT index) const {return coords [Index] [0];}
Int y (INT index) const {return coords [Index] [1];}
Int Minx () const;
Int Maxx () const;
Int miny () const;
Int Maxy () const;
Tetrixpiece rotatedleft () const;
Tetrixpiece rotatedright () const;

PRIVATE:
Void setx (INT index, int X) {coords [Index] [0] = x ;}
Void sety (INT index, int y) {coords [Index] [1] = y ;}

Tetrixshape pieceshape;
Int coords [4] [2];
};

# Endif

/*************************************** *************************************

** Tetrixpiece. cpp

**
** Copyright (c) 2004-2007 trolltech asa. All rights reserved.
**
**************************************** ************************************/

# Include <qtcore>

# Include <stdlib. h>

# Include "tetrixpiece. H"

Void tetrixpiece: setrandomshape ()
{
Setshape (tetrixshape (qrand () % 7 + 1 ));
}

Void tetrixpiece: setshape (tetrixshape shape)
{
Static const int coordstable [8] [4] [2] = {
{0, 0}, {0, 0}, {0, 0}, {0, 0 }},
{0,-1}, {0, 0}, {-1, 0}, {-1, 1 }},
{0,-1}, {0, 0}, {1, 0}, {1, 1 }},
{0,-1}, {0, 0}, {0, 1}, {0, 2 }},
{-1, 0}, {0, 0}, {1, 0}, {0, 1 }},
{0, 0}, {1, 0}, {0, 1}, {1, 1 }},
{-1,-1}, {0,-1}, {0, 0}, {0, 1 }},
{1,-1}, {0,-1}, {0, 0}, {0, 1 }}
};

For (INT I = 0; I <4; I ++ ){
For (Int J = 0; j <2; ++ J)
Coords [I] [J] = coordstable [shape] [I] [J];
}
Pieceshape = shape;
}

Int tetrixpiece: Minx () const
{
Int min = coords [0] [0];
For (INT I = 1; I <4; ++ I)
Min = qmin (Min, coords [I] [0]);
Return min;
}

Int tetrixpiece: Maxx () const
{
Int max = coords [0] [0];
For (INT I = 1; I <4; ++ I)
Max = Qmax (max, coords [I] [0]);
Return Max;
}

Int tetrixpiece: miny () const
{
Int min = coords [0] [1];
For (INT I = 1; I <4; ++ I)
Min = qmin (Min, coords [I] [1]);
Return min;
}

Int tetrixpiece: Maxy () const
{
Int max = coords [0] [1];
For (INT I = 1; I <4; ++ I)
Max = Qmax (max, coords [I] [1]);
Return Max;
}

Tetrixpiece: rotatedleft () const
{
If (pieceshape = squareshape)
Return * this;

Tetrixpiece result;
Result. pieceshape = pieceshape;
For (INT I = 0; I <4; ++ I ){
Result. setx (I, y (I ));
Result. sety (I,-X (I ));
}
Return result;
}

Tetrixpiece: rotatedright () const
{
If (pieceshape = squareshape)
Return * this;

Tetrixpiece result;
Result. pieceshape = pieceshape;
For (INT I = 0; I <4; ++ I ){
Result. setx (I,-y (I ));
Result. sety (I, X (I ));
}
Return result;
}
 

First, let's take a look at tetrixshape. This Enum defines some graph indexing methods. It is used to represent various types of images. We can find this static const int coordstable [8] [4] [2] In the setshape method. A static 3D array defines the real representation of each graph in the order of enum.

Then let's see how it is represented. Let's look for a zshape. Its definition is {0,-1}, {0, 0}, {-1, 0}, {-1, 1} is represented by a matrix.

0-1

0 0

-1 0

-1 1

 

This is obviously not as intuitive as we discussed above. I was confused when I looked at this data structure for a while. How does this matrix represent the Z image?

 

Only after learning about the member functions in this class and the implementation of tetrixboard can we understand that tetrixpiece uses four pairs of coordinates to represent a graph. You can see that no matter what type of image, it is actually composed of four blocks, so we can use four sets of coordinates to represent a graph.

Take a look at this zshape and follow the coordinates to get

-1 0 1

-1 *

0 **

1 *

 

Look, it's out of shape. In this two-dimensional array, the preceding represents the X coordinate, and the following represents the Y coordinate. After understanding this, The meanings of the following functions are better understood.

Int X (INT index) const {return coords [Index] [0];} // returns X of the index coordinate of the image
Int y (INT index) const {return coords [Index] [1];} // returns the Y coordinate of the graph's index
Int Minx () const; // minimum X coordinate value
Int Maxx () const; // maximum X coordinate value
Int miny () const; // min y coordinate
Int Maxy () const; // The four functions above the maximum y coordinate are used to determine the shape size of the graph when drawing the graph.
Tetrixpiece rotatedleft () const; // coordinates the coordinates to the left to the right.
Tetrixpiece rotatedright () const;

 

 

We have talked so much about tetrixpiece. With these things, it is easy to understand this example.

Here are some interesting things:

 

Void tetrixboard: drawsquare (qpainter & painter, int X, int y, tetrixshape shape)

This function is used to draw blocks. qpainter is similar to DC in DGI, and X and Y indicate on what coordinates to draw, finally, it shows the figure of the drawn square (this tetrix does not use different figures to represent the square ). You can see that there are two such static arrays in the source code. They are all defined in the member functions. One is the above coordstable, and the other is the colortable in the function. To tell the truth, I know little about C ++, but I don't know if such an implementation will have any bad things. But when and when to use it, I try to write the relevant code together, yes, my buddy.

 

Bool tetrixboard: trymove (const tetrixpiece & newpiece, int newx, int newy)

This function is used to move a graph. Given a try, it indicates that its return value is also very useful. It works when determining a similar collision, that is, it cannot be moved at will.

 

For (INT I = 0; I <4; ++ I ){
Int x = curx + curpiece. X (I );
Int y = Cury-curpiece. Y (I );
Drawsquare (painter, rect. Left () + x * squarewidth (),
Boardtop + (boardheight-y-1) * squareheight (),
Curpiece. shape ());
}
The code above is used to draw a graph. For each pair of coordinates, the values of X and Y are calculated. As we can see, it performs some calculations, it is mainly to re-calculate the coordinate origin, so that drawsquare can be completed in a proper order during painting. Here we also need to note that this set of coordinates is worth the size of X and Y coordinates by calculating max-min.
Take the preceding zshape as an example:

0-1

0 0

-1 0

-1 1


The program uses the following rules to calculate: max (x)-min (x) + 1 is the size of the X axis, that is, 0-(-1) + 1 = 2, max (y) -min (y) + 1 indicates the size of the Y axis, that is, 1-(-1) + 1 = 3.

Let's take a look at the situation when zshape is drawn: Suppose zshape has just fallen from the top.
Curx = boardwidth/2 + 1 = 10/2 + 1 = 6 // center
Cury = boardheight-1 + curpiece. miny () = 22-1 + (-1) = 22

X = curx + curpiece. X (I) = 5 [6]

Y = Cury-curpiece. Y (I) = 23 [22] [21]


Drawsquare (painter, rect. Left () + x * squarewidth (), // leftmost coordinate + x coordinate
Boardtop + (boardheight-y-1) * squareheight (), // The coordinate at the top of the curve + the correction graph at the relative top shows only one square.
Curpiece. shape ());



Another interesting Function

Tetrixshape & shapeat (int x, int y) {return Board [(y * boardwidth) + X];}

 

This function can be used as the left value of an expression, like: shapeat () = 3; I am not familiar with the c ++ syntax, but this is indeed the first time I met. Shapeat (1, 2) = 3;

Equivalent to board [(2 * boardwidth) + 1] = 3;

 

You can probably think of so many things to talk about. If you are interested, you can email me to discuss the things of tetrix.

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.