C language to achieve tetris source code
- 2020-06-07 04:51:59
- OfStack
This article has Shared the C language for you to realize the tetris specific code, for your reference, the specific content is as follows
GitHub: [C language] to achieve tetris source code
Head.h
#ifndef _HEAD_H_
#define _HEAD_H_
#include<graphics.h>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define _CRT_SECURE_NO_WARNINGS 1
// The parameters associated with the interface
#define WALL_SQUARE_WIDTH 10 // The width of the enclosing block
#define xWALL_SQUARE_NUM 30 //x The number of squares in the axial direction
#define yWALL_SQUARE_WIDTH 46 //y The number of squares in the axial direction
#define GAME_WALL_WIDTH (WALL_SQUARE_WIDTH*xWALL_SQUARE_NUM) // Width of play area 300
#define GAME_WALL_HTGH (WALL_SQUARE_WIDTH*yWALL_SQUARE_WIDTH) // Height of play area 460
#define WINDOW_WIDTH 480 // Total window width of the game 480
#define WINDOW_HIGH 460 // Total game window height 460
// Defines the parameters associated with Tetris
#define ROCK_SQUARE_WIDTH (2*WALL_SQUARE_WIDTH) // Tetris is twice the size of the wall 20
#define xROCK_SQUARE_NUM ((GAME_WALL_WIDTH -20)/ROCK_SQUARE_WIDTH) // The game area x Number of blocks on axis: 14
#define yROCK_SQUARE_NUM ((GAME_WALL_HTGH -20)/ROCK_SQUARE_WIDTH) // The game area y Number of blocks on axis: 22
// Defines the actions associated with moving a square
#define DIRECT_UP 3
#define DIRECT_DOWN 2
#define DIRECT_LEFT -1
#define DIRECT_RIGHT 1
/* The data structure - The linear table ( Struct array )*/
typedef struct ROCK
{
// Used to represent the shape of a square ( every 1 A byte is 8 And with each 4 Bits represent inside the box 1 line )
unsigned short rockShapeBits;
int nextRockIndex; // Under the 1 Three squares, index in an array
} RockType;
// The position of the square in the graphics window ( The positioning 4*4 The upper-left corner coordinates of the block )
typedef struct LOCATE
{
int left;
int top;
} RockLocation_t;
// The global variable - The status description of the game board ( That is, where are the squares on the current interface )
//0 That means no, 1 Said a ( Two more rows and two more columns 1 A fence, easy to judge whether the box can move )
int game_board[yROCK_SQUARE_NUM + 2][xROCK_SQUARE_NUM + 2] = { 0 };
int game_socres = 0; // The global score
// Put tetris on 19 I'm going to put the class in the array
int rockTypeNum = 19;
RockType RockArray[19] = { (0, 0) };
// The location of the squares in the preview area
RockLocation_t preRockLocation = {GAME_WALL_WIDTH+70,70};
// The location of the initializer block is generated each time
RockLocation_t initRockLocation = { (WALL_SQUARE_WIDTH + 100), WALL_SQUARE_WIDTH };
// The location of the score
// Functions in individual files
// Draw the interface and draw the squares Draw.h In the
void DrawGameWindow();
void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed);
// Initialize the Init The source file
void InitGame();
//game.h
void PlayGame();
bool IsGameOver();
#endif
Draw.h
#include"Head.h"
// Draw the game interface
void DrawGameWindow()
{
// So let's draw the fence
setcolor(BLUE);
setlinestyle(PS_SOLID,NULL,0);
setfillcolor(BLUE);
// Draw the upper and lower walls
for (int x = WALL_SQUARE_WIDTH; x <= GAME_WALL_WIDTH; x += WALL_SQUARE_WIDTH)
{
fillrectangle(x - WALL_SQUARE_WIDTH, 0, x, WALL_SQUARE_WIDTH); // on
fillrectangle(x - WALL_SQUARE_WIDTH, GAME_WALL_HTGH - WALL_SQUARE_WIDTH, x, GAME_WALL_HTGH);// Under the
}
// Draw the left and right walls
for (int y = WALL_SQUARE_WIDTH; y <= GAME_WALL_HTGH; y += WALL_SQUARE_WIDTH)
{
fillrectangle(0, y, WALL_SQUARE_WIDTH, y + WALL_SQUARE_WIDTH);// On the left
fillrectangle(GAME_WALL_WIDTH - WALL_SQUARE_WIDTH, y, GAME_WALL_WIDTH, y + WALL_SQUARE_WIDTH);// right
}
// Let me draw the statistical score on the right hand side and all that stuff
// Let me draw the dividing line
setcolor(WHITE);
setlinestyle(PS_DASH,2);
line(GAME_WALL_WIDTH + 20, 0, GAME_WALL_WIDTH + 20, GAME_WALL_HTGH);
// Set the font
LOGFONT font;
gettextstyle(&font);
settextstyle(18, 0, _T(" Song typeface "));
font.lfQuality = ANTIALIASED_QUALITY;// Set the output to anti-aliasing
//1 Display preview shape
outtextxy(GAME_WALL_WIDTH + 80, 30, _T(" preview "));
outtextxy(GAME_WALL_WIDTH + 80, 170, _T(" score "));
outtextxy(GAME_WALL_WIDTH + 65, 250, _T(" Instructions for "));
outtextxy(GAME_WALL_WIDTH + 40, 290, _T("w a s d Control the direction "));
outtextxy(GAME_WALL_WIDTH + 40, 335, _T(" The blank space suspended "));
// According to score
setcolor(RED);
outtextxy(GAME_WALL_WIDTH + 90, 200, '0');
}
// Displays the number in the game area rockIdx The square
void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed)
{
int color;// The fill color of the square
int lineColor = WHITE;// The color of the line
int boardFalg = 0;
int xRock = 0;
int yRock = 0;
unsigned short rockCode = RockArray[rockIdx].rockShapeBits;
// if displayed for true If so, set the cube color to white . game_board The corresponding position is set to 1 ;
// if displayed for false If so, set the cube color to black . game_board The corresponding position is set to 0 ;
displayed ? (color = RED, boardFalg = 1) : (color = BLACK,lineColor = BLACK, boardFalg = 0);
setcolor(lineColor);
setfillcolor(color);
setlinestyle(PS_SOLID);// I'm going to make it solid,
xRock = LocatePtr->left;
yRock = LocatePtr->top;
int count = 0;// every 4 The offset of coordinates is recorded
unsigned short mask = 1;
for (int i = 1; i <= 16; ++i)
{
mask = 1 << (16 - i);
if ((rockCode & mask) != 0) // If not for 0 If you do that, you draw little squares
{
fillrectangle(xRock , yRock, xRock + ROCK_SQUARE_WIDTH, yRock + ROCK_SQUARE_WIDTH);
}
if (i % 4 == 0) // A newline
{
yRock = yRock + ROCK_SQUARE_WIDTH;
xRock = xRock = LocatePtr->left;
}
else
{
xRock += ROCK_SQUARE_WIDTH;
}
}
}
Init.h
#include"Head.h"
static void ShapeStrToBit(unsigned char *rockShapeStr, unsigned short& rockShapeBit);
static void ReadRcok();
void InitGame()
{
// Initializes the global game version and the boundary 1
for (int i = 0; i < xROCK_SQUARE_NUM + 2; i++)
{
game_board[0][i] = 1; // The upper boundary
game_board[yROCK_SQUARE_NUM + 1][i] = 1; // Under the border
}
for (int i = 0; i < yROCK_SQUARE_NUM + 2; i++)
{
game_board[i][0] = 1 ; // The left border
game_board[i][xROCK_SQUARE_NUM + 1] = 1; // The right boundary
}
// Read Tetris
ReadRcok();
}
// Read the shape of the box from the file to store to rockArray In the
void ReadRcok()
{
FILE* fp = fopen("RockShape.ini","r");
if (NULL == fp)
{
printf(" Failed to open file \n");
return;
}
unsigned char readBuf[1024]; //fp Read a string readbuf In the
unsigned short rockShapeBit = 0;// Store square shape, occupy 16 bits
unsigned char rockShapeStr[16];// Storing block strings
int ShapeStrIdx = 0;
int rockNum = 0;// Count the number of squares and store the array of squares RockArray The subscript
int rocknext = 0;// Down in the array of squares 1 A shape
int rockShapeStart = 0;// with 1 Shape of type
while (true)
{
size_t readSize = fread(readBuf, 1, 1024, fp);
if (readSize == 0)
break;
// To deal with readbuf
for (size_t idx = 0; idx < readSize; ++idx)
{
// Store the character to rockShapeStr In the
while (ShapeStrIdx < 16 && idx < readSize)
{
if (readBuf[idx] == '@' || readBuf[idx] == '#')
{
rockShapeStr[ShapeStrIdx] = (unsigned char)readBuf[idx];
++ShapeStrIdx;
}
++idx; // may idx == readSize the
if (readBuf[idx] == '*')// On the modification 1 Times square next value
{
idx += 5;
RockArray[--rockNum].nextRockIndex = rockShapeStart;
rockNum++;
rockShapeStart = rockNum;
rocknext = rockShapeStart ;
}
}
// Maybe not
if (ShapeStrIdx < 16)
{
break;
}
else // fill shapestr
{
ShapeStrIdx = 0;// buy 0
// will rockShapeStr to rockShapeBit
ShapeStrToBit(rockShapeStr, rockShapeBit);
rocknext++;
RockArray[rockNum].rockShapeBits = rockShapeBit;
RockArray[rockNum].nextRockIndex = rocknext;
rockNum++;
}
}
}
fclose(fp);
}
// The string that will be read from the file ( The length defaults to 16) Converted to unsigned short
void ShapeStrToBit(unsigned char *rockShapeStr, unsigned short& rockShapeBit)
{
rockShapeBit = 0;
for (size_t idx = 0; idx < 16; ++idx)
{
if (rockShapeStr[idx] == '@') //1
{
rockShapeBit |= (1 << (16 - idx - 1));
}
// # for 0 It doesn't need to be dealt with
}
}
game.h
#include"Head.h"
#define _CRT_SECURE_NO_WARNINGS 1
bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction);
void SetGameBoardFlag(int rockIdx, RockLocation_t* curRockLocation);
void UserHitKeyBoard(char userHit, int* RockIndex, RockLocation_t* curRockLocation);
void FullLine();
void UpdateSocres(int scores);
void DelCurLine(int rowIdx);
bool IsGameOver();
void PlayGame()
{
char userHit = 0;// User taps on keyboard
int curRockIndex = 0;// Current square rockArray The subscript
int nextRockIndex = 0;// The next time
RockLocation_t curRockLocation;
curRockLocation.left = initRockLocation.left;
curRockLocation.top = initRockLocation.top;
DWORD oldtime = 0;
srand((unsigned int)time(NULL));
curRockIndex = rand() % rockTypeNum;
nextRockIndex = rand() % rockTypeNum;
// Draws the preview area initialization box
// Displays the square shape in the initial position and preview area
DisplayRock(curRockIndex, &initRockLocation, 1);
DisplayRock(nextRockIndex, &preRockLocation, 1);
bool moveAbled = false;
while (true)
{
// Determines whether the current square falls to the ground ( Decide if you can go down ) : If you land , Determine if the row is full , And then decide whether to end the game, change game_board , Draw the next initialization box and generate a new preview box
//
moveAbled = MoveAble(curRockIndex, &curRockLocation, DIRECT_DOWN);
if (!moveAbled) // Judge whether the landing, can not move down means landing
{
// Modify the game_board The value of the
SetGameBoardFlag(curRockIndex, &curRockLocation);
FullLine();
if (IsGameOver())
{
MessageBox(NULL, _T(" Game over "), _T("GAME OVER"), MB_OK);
exit(0);
}
// Start preparing for the next build module
DisplayRock(nextRockIndex, &preRockLocation, false);// Erase old squares
curRockIndex = nextRockIndex;
nextRockIndex = rand() % rockTypeNum; // Generate a new preview box
DisplayRock(curRockIndex, &initRockLocation, 1);
DisplayRock(nextRockIndex, &preRockLocation, 1);
FlushBatchDraw();
// Modify the curRockLocation The value of the
curRockLocation.left = initRockLocation.left;
curRockLocation.top = initRockLocation.top;
}
if (kbhit()) // If I hit the keyboard Just handle the button
{
userHit = getch();
UserHitKeyBoard(userHit, &curRockIndex, &curRockLocation);
}
// There is no It automatically moves down 1 A unit of : Can't use else Because maybe the buttons aren't up, down, left, right
DWORD newtime = GetTickCount();
if (newtime - oldtime >= (unsigned int)(300) && moveAbled == TRUE)
{
oldtime = newtime;
DisplayRock(curRockIndex, &curRockLocation, false);
curRockLocation.top += ROCK_SQUARE_WIDTH; // whereabouts 1 "
}
//AutomaticDownMove(curRockIndex, &curRockLocation);
// Draw a new square
DisplayRock(curRockIndex, &curRockLocation, 1);
FlushBatchDraw();
Sleep(20);
}
}
// Response time to keyboard commands
void UserHitKeyBoard(char userHit, int* RockIndex, RockLocation_t* curRockLocation)
{
switch (userHit)
{
case 'W':
case 'w':// write
if (MoveAble(RockArray[*RockIndex].nextRockIndex, curRockLocation, DIRECT_UP))
{
DisplayRock(*RockIndex, curRockLocation, false);
*RockIndex = RockArray[*RockIndex].nextRockIndex;
}
break;
case 'S':
case 's':// left
if (MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN))
{
DisplayRock(*RockIndex, curRockLocation, false);
curRockLocation->top += 2 * (ROCK_SQUARE_WIDTH);
if (!MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN))
{
curRockLocation->top -= ROCK_SQUARE_WIDTH;
}
}
break;
case 'A':
case 'a': // please
if (MoveAble(*RockIndex, curRockLocation, DIRECT_LEFT))
{
DisplayRock(*RockIndex, curRockLocation, false);
curRockLocation->left -= ROCK_SQUARE_WIDTH;
}
break;
case 'D':
case 'd': // -
if (MoveAble(*RockIndex, curRockLocation, DIRECT_RIGHT))
{
DisplayRock(*RockIndex, curRockLocation, FALSE);
curRockLocation->left += ROCK_SQUARE_WIDTH;
}
break;
case ' ': // suspended
while (1)
{
userHit = getch();
if (userHit == ' ')
break;
}
break;
default:
break;
}
}
// Determine if the row is full, eliminate the row, and then calculate the score
void FullLine()
{
bool linefull = true;
int idx = yROCK_SQUARE_NUM;// From the last 1 Look up the row 22
int count = 0;
while (count != xROCK_SQUARE_NUM ) // With a blank line 14
{
linefull = true;
count = 0;
for (int i = 1; i <= xROCK_SQUARE_NUM; ++i)
{
if (game_board[idx][i] == 0)
{
linefull = false;
count++;
}
}
if (linefull) // Full row, eliminates current row, updates score
{
DelCurLine(idx);
game_socres += 3;
UpdateSocres(game_socres);
idx++;// Because we're going to subtract 1
}
idx--;
}
}
void UpdateSocres(int scores)
{
setcolor(RED);
TCHAR s[10];
_stprintf(s, _T("%d"), scores);
outtextxy(GAME_WALL_WIDTH + 90, 200, s);
}
// Eliminate the current row
void DelCurLine(int rowIdx)
{
// Erases the current row
setcolor(BLACK);
setfillcolor(BLACK);
for (int i = 1; i < xROCK_SQUARE_NUM; ++i)
{
fillrectangle(WALL_SQUARE_WIDTH + (i - 1)*ROCK_SQUARE_WIDTH, (rowIdx - 1)*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH,
WALL_SQUARE_WIDTH + i*ROCK_SQUARE_WIDTH, rowIdx*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH);
}
// Move the top one down
int cnt = 0;
while (cnt != xROCK_SQUARE_NUM) // Until it comes across an empty line
{
cnt = 0;
for (int i = 1; i <= xROCK_SQUARE_NUM; i++)
{
game_board[rowIdx][i] = game_board[rowIdx - 1][i];
// Erase the top 1 line
setcolor(BLACK);
setfillcolor(BLACK);
fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx - 1) - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx - 1));
// Show the following 1 line
if (game_board[rowIdx][i] == 1)
{
setcolor(WHITE);
setfillcolor(RED);
fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx);
}
if (game_board[rowIdx][i] == 0)
cnt++; // statistical 1 Line is Is space
}//for
rowIdx--;
}
}
// Is it possible to move squares
bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction)
{
int mask;
int rockX;
int rockY;
rockX = currentLocatePtr->left;
rockY = currentLocatePtr->top;
mask = (unsigned short)1 << 15;
for (int i = 1; i <= 16; i++)
{
// As opposed to the mask 1 the That's the point on the square
if ((RockArray[rockIndex].rockShapeBits & mask) != 0)
{
// Decide whether to move or not ( Scan for the location you are about to move Whether there is overlap with the fence set )
// If it was up ( That is, roll deformation )
if (f_direction == DIRECT_UP)
{
// Because in this case, I'm passing in the bottom 1 The shape of the square, so we directly judge whether the location of the square has been occupied
// To determine the 1 A square
if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] == 1)
return false;
}
// If it's moving down
else if (f_direction == DIRECT_DOWN)
{
if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 2]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] == 1)
return false;
}
else // If you're moving left and right
{ //f_direction the DIRECT_LEFT for -1 . DIRECT_RIGHT for 1 , so just add f_direction You can tell.
if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1 + f_direction] == 1)
return false;
}
}
// every 4 time A newline Turn to the next 1 Rows continue
i % 4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = currentLocatePtr->left)
: rockX += ROCK_SQUARE_WIDTH;
mask >>= 1;
}
return true;
}
// To a game game_board Set the flag to indicate that it has been occupied
void SetGameBoardFlag(int rockIdx, RockLocation_t* curRockLocation)
{
int mask;
int rockX;
int rockY;
rockX = curRockLocation->left;
rockY = curRockLocation->top;
mask = (unsigned int)1 << 15;
for (int i = 1; i <= 16; i++)
{
// As opposed to the mask 1 the That's the point on the square
if ((RockArray[rockIdx].rockShapeBits & mask) != 0)
{
game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] = 1;
}
// every 4 time A newline Turn to the next 1 Rows continue to draw
i % 4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = curRockLocation->left)
: rockX += ROCK_SQUARE_WIDTH;
mask >>= 1;
}
}
// Decide if the game is over
bool IsGameOver()
{
bool topLineHaveRock = false;// Is there a square in the top row
bool bottomLineHaveRock = false;
for (int i = 1; i < xROCK_SQUARE_NUM; ++i)
{
if (game_board[1][i] == 1)
topLineHaveRock = true;
if (game_board[yROCK_SQUARE_NUM][i] == 1)
bottomLineHaveRock = true;
}
if (bottomLineHaveRock && topLineHaveRock)
return true;
else
return false;
}
main.cpp
#include"Head.h"
#include"Draw.h"
#include"Init.h"
#include"game.h"
int main()
{
initgraph(WINDOW_WIDTH,WINDOW_HIGH);
DrawGameWindow();
// use API The function modifies the window name
HWND hWnd = GetHWnd();
SetWindowText(hWnd, _T(" Tetris "));
InitGame();
PlayGame();
getchar();
closegraph();
system("pause");
return 0;
}
Configuration file: ES30en.ini
@###
@###
@@##
####
@@@#
@###
####
####
@@##
#@##
#@##
####
##@#
@@@#
####
####
****
#@##
#@##
@@##
####
@###
@@@#
####
####
@@##
@###
@###
####
@@@#
##@#
####
####
****
#@##
@@@#
####
####
@###
@@##
@###
####
@@@#
#@##
####
####
#@##
@@##
#@##
####
****
#@##
@@##
@###
####
@@##
#@@#
####
####
****
@###
@@##
#@##
####
#@@#
@@##
####
####
****
@###
@###
@###
@###
@@@@
####
####
####
****
@@##
@@##
####
####
****
For more articles on Tetris, please click here to view the special topic: Tetris.