Code:
#include "primlib.h"
#include "pieces.inl"
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#define blockSize 15
#define boardWidth 15
#define boardHeight 25
#define interval 40000 /*time interval preventing from instant loop execution*/
int gamespace[boardWidth][boardHeight]; /*array used to store information about blocks*/
int counter_x, /*x-position counter*/
counter_y; /* y-position counter*/
int pivotX; /*counter used to find the horizontal position of pivot block in the pieces.inl definitions*/
int pivotY; /*counter used to find the vertical position of pivot block in the pieces.inl definitions*/
void draw(void); /*drawing grounded blocks*/
int check(int horizontal, int vertical, int rot_coordinate, int blockType);/*checks whether a move is possible, and draws appropriate variant*/
void groundSave(int horizontal, int vertical, int rot_coordinate, int blockType);/*memorizing blocks that hit the "ground"*/
int anim(int blockType);/*rotation and left/right/down movement(according to which key is pressed)*/
void check_delete(void); /*removing a row that is full*/
void gameover(void); /*when block reaches the top line of the gamespace, ends loop execution and displays GAME OVER */
int main()
{
int blockType,
randomBlock; /* randomBlock - randomized type of the next falling block */
if(initGraph())
exit(3);
/* generating seed for randomizing process */
srand(time(NULL));
/* Randomizing the type of the first block */
randomBlock=(int)(rand()%7);
/* Borders of the game field */
filledRect(((screenWidth()-1)-boardWidth*blockSize)/2-6,(screenHeight()-1)-blockSize*boardHeight,((screenWidth()-1)-boardWidth*blockSize)/2-1,screenHeight()-1,BLUE);
filledRect(((screenWidth()-1)+boardWidth*blockSize)/2+6,(screenHeight()-1)-blockSize*boardHeight,((screenWidth()-1)+boardWidth*blockSize)/2+1,screenHeight()-1,BLUE);
/* main loop */
while(1)
{
blockType=randomBlock;
/* Randomizing the upcoming type of block */
randomBlock=(int)(rand()%7);
/* creating animation for block, if any of them reaches top, returns 1 and finishes the game */
if(anim(blockType)==1)
{
gameover();
return 0;
}else if(anim(blockType)==2)
{
return 0;
}
/*removing a row that is full*/
check_delete();
}
}
/* ###################################################################### */
void draw(void) /*drawing grounded blocks*/
{
for(counter_x=0;counter_x<boardWidth;counter_x++)
for(counter_y=0;counter_y<boardHeight;counter_y++)
if(gamespace[counter_x][counter_y]!=0)
{
/*the filling of the grounded block*/
filledRect(((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*counter_x,(screenHeight()-1)-blockSize*(boardHeight-counter_y),((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*(counter_x+1),(screenHeight()-1)-blockSize*(boardHeight-(counter_y+1)),GREEN);
/*the border*/
rect(((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*counter_x,(screenHeight()-1)-blockSize*(boardHeight-counter_y),((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*(counter_x+1),(screenHeight()-1)-blockSize*(boardHeight-(counter_y+1)),BLUE);
}
}
/* ###################################################################### */
int check(int horizontal, int vertical, int rot_coordinate, int blockType)/*checks whether a move is possible, and draws appropriate variant*/
/*horizontal/vertical - current X/Y position of the falling block, rot_coordinate - initially 0, modified by player in 'anim' function by pressing SDLK_SPACE;
return 0 if the block is out of the gamespace
return 1 if the drawing is successful
return 2 if the space in the gamespace is occupied by other block*/
{
/* determining position of pivot block */
for(pivotX=0;pivotX<4;pivotX++)
for(pivotY=0;pivotY<4;pivotY++)
if(pieces[blockType][rot_coordinate][pivotY][pivotX]==2)
goto end;
end:
for(counter_x=0;counter_x<4;counter_x++)
for(counter_y=0;counter_y<4;counter_y++)
{
/* block position is unacceptable */
if((pieces[blockType][rot_coordinate][counter_y][counter_x]!=0)&&((horizontal-pivotX+counter_x>=boardWidth)||(horizontal-pivotX+counter_x<0))) return 0;
/* the place in the gamespace is occupied*/
if((pieces[blockType][rot_coordinate][counter_y][counter_x]!=0)&&(((vertical-pivotY+counter_y>=boardHeight))||(gamespace[horizontal-pivotX+counter_x][vertical-pivotY+counter_y]!=0))) return 2;
}
/* redrawing the internal area of the gamespace */
filledRect(((screenWidth()-1)-boardWidth*blockSize)/2,(screenHeight()-1)-blockSize*boardHeight,((screenWidth()-1)+boardWidth*blockSize)/2,screenHeight()-1,BLACK);
/* draw the content of the game field */
draw();
/* drawing the falling blocks*/
for(counter_x=0;counter_x<4;counter_x++)
for(counter_y=0;counter_y<4;counter_y++)
if(pieces[blockType][rot_coordinate][counter_y][counter_x]!=0)
{
filledRect(((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*(horizontal-pivotX+counter_x),(screenHeight()-1)-blockSize*(boardHeight-(vertical-pivotY+counter_y)),((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*(horizontal+counter_x-pivotX+1),(screenHeight()-1)-blockSize*(boardHeight-(vertical+counter_y-pivotY+1)),WHITE);
rect(((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*(horizontal-pivotX+counter_x),(screenHeight()-1)-blockSize*(boardHeight-(vertical-pivotY+counter_y)),((screenWidth()-1)-boardWidth*blockSize)/2+blockSize*(horizontal+counter_x-pivotX+1),(screenHeight()-1)-blockSize*(boardHeight-(vertical+counter_y-pivotY+1)),BLUE);
}
updateScreen();
return 1;
}
/* ###################################################################### */
void groundSave(int horizontal, int vertical, int rot_coordinate, int blockType)/*memorizing blocks that hit the "ground"*/
/* horizontal/vertical - current X/Y position of the falling block, rot_coordinate - initially 0, modified by player in 'anim' function by pressing SDLK_SPACE*/
{
/* looking for the position of the central module of the block */
for(pivotX=0;pivotX<4;pivotX++)
for(pivotY=0;pivotY<4;pivotY++)
if(pieces[blockType][rot_coordinate][pivotY][pivotX]==2)
/*Update of the gamespace array*/
for(counter_x=0;counter_x<4;counter_x++)
for(counter_y=0;counter_y<4;counter_y++)
if(pieces[blockType][rot_coordinate][counter_y][counter_x]!=0)
/*saving new elements into the ground array*/
gamespace[horizontal-pivotX+counter_x][vertical-pivotY+counter_y]=1;
}
/* ###################################################################### */
int anim(int blockType)/*rotation and left/right/down movement(according to which key is pressed)*/
/*returns 1 if the game cannot be continued; 0 otherwise*/
{
int KEY; /* KEY - variable being SDL code for the pressed button*/
int vertical=1, /* current Y position of the block, set to 1(top of the gamespace)*/
horizontal=boardWidth/2, /* current X position of the block(middle of the gamespace)*/
rotation=0, /*rotational parameter of the block*/
support; /* support - supporting counter of a loop */
if(check(horizontal,vertical,rotation,blockType)==2) return 1;
/*if satisfied, the gameover function is called*/
while(1)
{
support=0;
for (support=0;support<10;support++)
{
/* slowing down the loop execution */
usleep(interval);
/* the code of pressed button is ascribed to KEY */
KEY=pollkey();
switch (KEY)
{
/* pressing space, rotation of the block */
case SDLK_SPACE:
/*checking if it is possible to rotate*/
if((rotation==3)&&(check(horizontal,vertical+1,0,blockType)==1))
{
rotation=0;
}
else if((rotation!=3)&&(check(horizontal,++vertical,++rotation,blockType)!=1))
{
rotation--;
vertical--;
}
break;
/* pressing left arrow */
case SDLK_LEFT: if(check(--horizontal,vertical,rotation,blockType)!=1) horizontal++;
break;
/* pressing right arrow */
case SDLK_RIGHT: if(check(++horizontal,vertical,rotation,blockType)!=1) horizontal--;
break;
/* pressing down arrow - moving the block down instantly, and performing groundSave */
case SDLK_DOWN:
while(check(horizontal,++vertical,rotation,blockType)==1);
groundSave(horizontal,--vertical,rotation,blockType);
return 0;
break;
case SDLK_ESCAPE:
return 2;
break;
default:
break;
}
if (support==9)
{ /*when another move downwards isn't possible then it is saved by groundSave function*/
if(check(horizontal,++vertical,rotation,blockType)==2)
{
groundSave(horizontal,--vertical,rotation,blockType);
return 0;
}
}
}
}
return 0;
}
/* ###################################################################### */
void check_delete(void) /*removing a row that is full*/
{
/*decreaseX - support X-direction counter*/
/*decreaseY - support Y-direction counter*/
int decreaseX,decreaseY;
/* checks if any row is not full */
for(counter_y=1;counter_y<boardHeight;counter_y++)
{
for(counter_x=0;counter_x<boardWidth;counter_x++)
{
if(gamespace[counter_x][counter_y]==0) break;
}
/* modifying the gamespace array so that the data of any visible FULL row are substituted by the data of the one-above row and re-drawn immediately on the screen*/
if(counter_x==boardWidth)
{
for(decreaseY=counter_y;decreaseY>=0;decreaseY--)/*going through Y to the top*/
for(decreaseX=0;decreaseX<boardWidth;decreaseX++)
if(decreaseY!=0)
gamespace[decreaseX][decreaseY]=gamespace[decreaseX][decreaseY-1];
else
gamespace[decreaseX][decreaseY]=0;
}
}
}
/* ###################################################################### */
void gameover(void) /*when block reaches the top line of the gamespace, ends loop execution and displays GAME OVER */
{
filledRect(0,0,screenWidth()-1,screenHeight()-1,BLACK);
textout(250,100,"GAME OVER",WHITE);
updateScreen();
getkey();
}
/* ###################################################################### */