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.


Related articles: