# Thread: how to make sure that my blocks stop when it reaches the border? tetris

1. ## how to make sure that my blocks stop when it reaches the border? tetris

I've got some ideas on how to stop the blocks but i do not know how to put them into codes. because moving to the left, i have to -cln so when the cln reach -1, i'll +1 to the cln again so that it remains at the same place. i've been racking my brains on this but still cant come up with the codes. I also need some help on the rotating.

Code:
```#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define ROW 15
#define COLUMN 15

void gameboard(char b[ROW][COLUMN])
{
int r, c;

for(r = -1; r <= ROW; r++)
{
for(c = -1; c  <= COLUMN; c++)
{

if(r == -1 || r == ROW || c == -1 || c == COLUMN)
{
putchar('*');
putchar(' ');
}
else
{
putchar(b[r][c]);
putchar(' ');
}
}

putchar('\n');
}
}

void assignblocks(char b[ROW][COLUMN])
{
int rol,col;
srand( (unsigned) time(NULL));

for (col = 6;col<9;col++)

{
b[0][col] = rand()%2;
if (b[0][col] == 1)
{
b[0][col]= 'X';
}

}
printf("\n");

for (col = 6;col<9;col++)
{
b[1][col] = rand()%2;
if (b[1][col] == 1)
{
b[1][col]= 'X';

}
}
b[1][7]='X';
printf("\n");

for (col = 6;col<9;col++)
{
b[2][col] = rand()%2;
if (b[2][col] == 1)
{
b[2][col] = 'X';
}
}
}

void movement (char b[ROW][COLUMN])
{
char input;
int rw,cln;

do
{
fflush(stdin);
scanf("%c",&input);

if (input == '4')
{
for (rw=0;rw<16;rw++)
for (cln=0;cln<16;cln++)
if (b[rw][cln] == 'X')
{
b[rw][cln-1]='X';
b[rw][cln]=' ';
}
}

if (input == '6')
for (rw=15;rw>-1;rw--)
for (cln=15;cln>-1;cln--)
if (b[rw][cln] == 'X')
{
b[rw][cln+1]='X';
b[rw][cln]=' ';
}

if (input == '8')
for (rw=15;rw>-1;rw--)
for (cln=15;cln>-1;cln--)

if (b[rw][cln] == 'X')
{
b[rw+1][cln]='X';
b[rw][cln]=' ';
}
if (input == '2')
{

}

}while(input != '2' && input != '4' && input != '6' && input != '8');

}

int main(void)
{
char box[ROW][COLUMN];
char name[20] ="AAA" ;
int x,y;
bool end = false;

printf("*************Tetris Game*************\n");
scanf("%s", &name);
printf("Player Name:%s\n", name);

for(x=0; x<16; x++)
{
for(y=0; y<16; y++)
{
box[x][y] = ' ';
}
}

assignblocks(box);

do
{
printf("\n\n*************Tetris Game*************\n");
printf("Player Name:%s\n", name);

gameboard(box);

movement(box);

}while (end == false);

return 0;
}```

2. Stop doing this

Code:
`fflush(stdin);`

Code:
`scanf(" %c",&input); /* Note the space before the %c */`
which will ignore the white space (i.e., the newline character) left in the input buffer.

3. Let me start by saying that I admire your enthusiasm. I don't want to discourage you at all, but Tetris is not a trivial game to program. I will say that it is unlikely that you will create a Tetris game with your current code. Visually, you're not off to a bad start, but structurally, your code is not conducive to the developmental growth required to implement all the nuances of a Tetris game.

For instance, the pieces should be a separate entity from the game board. As it stands, the game board array is just updated with X's, and piece movement consists of checking the current game board array and changing element values under certain conditions. What happens when the piece hits the bottom? How are you going to "store" the stopped piece and create a new one at the top, with this code implementation?

Each piece that enters the game board should be represented by an object separate from the game board (structures would be good for this task). It should contain the X/Y coordinates of each piece segment in the piece. There should be a separate function to "blit" the piece, based on the coordinates of its segments, onto a copy of the game board. The actual game board array should not be updated, but merely a copy of it for printing. This way, when the piece moves, you don't need to update the game board array - you merely update the coordinates of the piece segements and "blit" it again before printing. Only when a piece stops should it be added to the actual game board array, because now it is "part of the background."

With this setup, when a move is entered, you can just test the X/Y coordinate of each segment of the current piece to see if the move is allowed (i.e. to see if the piece reaches the left, right, or bottom border). There should be no need to reference the game board array for this kind of test.

Also, rotating a piece with your current code would be a hideous nightmare to implement, way more difficult than it's worth. Again, with each piece as a "separate entity," you only have to adjust the X/Y coordinates of each segment of the piece for rotation, and not have to touch the game board array at all.

Again, my goal is not to discourage you - in fact, it's to help prevent yourself from getting discouraged if this doesn't go the way you intended. Regardless of whether you "succeed" with this game as it stands, or not, you're gaining experience and getting valuable practice, so there is definitely some benefit either way.

4. ok.. made them into structure... so far Im doing the checking for collision only for the block going down. but results is something weird.

Code:
```#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define ROW 15
#define COLUMN 15

typedef struct
{
char sblock;
char pblock;
}block;

void gameboard(block b[ROW][COLUMN])
{
int r, c;

for(r = -1; r <= ROW; r++)
{
for(c = -1; c  <= COLUMN; c++)
{
if(r == -1 || r == ROW || c == -1 || c == COLUMN)
{
putchar('*');
putchar(' ');
}
else
{
if (b[r][c].sblock=='X')
putchar(b[r][c].sblock);
else if (b[r][c].pblock=='X')
putchar(b[r][c].pblock);
else
putchar(b[r][c].sblock);
putchar(' ');
}
}

putchar('\n');
}
}

void assignblocks(block b[ROW][COLUMN])
{
int rol,col;
srand( (unsigned) time(NULL));

for (col = 6;col<9;col++)

{
b[0][col].sblock = rand()%2;
if (b[0][col].sblock == 1)
{
b[0][col].sblock= 'X';
}

}
printf("\n");

for (col = 6;col<9;col++)
{
b[1][col].sblock = rand()%2;
if (b[1][col].sblock == 1)
{
b[1][col].sblock= 'X';

}
}
b[1][7].sblock='X';
printf("\n");

for (col = 6;col<9;col++)
{
b[2][col].sblock = rand()%2;
if (b[2][col].sblock == 1)
{
b[2][col].sblock = 'X';
}
}
}

void movement (block b[ROW][COLUMN])
{
char input;
int rw,cln;

do
{
scanf(" %c",&input);

if (input == '4')
{
for (rw=0;rw<16;rw++)
for (cln=0;cln<16;cln++)
if (b[rw][cln].sblock == 'X')
{
b[rw][cln-1].sblock='X';
b[rw][cln].sblock=' ';
}
}

if (input == '6')
for (rw=15;rw>-1;rw--)
for (cln=15;cln>-1;cln--)
if (b[rw][cln].sblock == 'X')
{
b[rw][cln+1].sblock='X';
b[rw][cln].sblock=' ';
}

if (input == '8')
for (rw=15;rw>-1;rw--)
for (cln=15;cln>-1;cln--)

if (b[rw][cln].sblock == 'X')
{
b[rw+1][cln].sblock='X';
b[rw][cln].sblock=' ';
}
if (b[15][cln].sblock=='X') /*here i will put the 'X' into the p.block so that it does not interfere with the moving when i have another block.*/

{
b[rw][cln].sblock=' ';
b[rw][cln].pblock='X';
printf("ok");
}

if (input == '2')
{

}

}while(input != '2' && input != '4' && input != '6' && input != '8');

}

int main(void)
{
block box[ROW][COLUMN];
char name[20] ="AAA" ;
int x,y;
bool end = false;

printf("*************Tetris Game*************\n");
scanf("%s", &name);
printf("Player Name:%s\n", name);
printf("ok\n");
for(x=0; x<15; x++)
{
for(y=0; y<15; y++)
{
box[x][y].sblock = ' ';
box[x][y].pblock = ' ';
}
}

assignblocks(box);

do
{
printf("\n\n*************Tetris Game*************\n");
printf("Player Name:%s\n", name);

gameboard(box);

movement(box);

}while (end == false);

return 0;
}```

5. I think you haven't understood Matticus' main point:

Originally Posted by Matticus
Each piece that enters the game board should be represented by an object separate from the game board (structures would be good for this task).
As far as I understand your code, you have still just one big gameboard and no separate pieces.

Originally Posted by Alexius Lim
so far Im doing the checking for collision only for the block going down. but results is something weird.
You need to be more specific than "results is something weird" if you want some help.

Bye, Andreas

6. Can i ask how long have u been into programming C?

7. i've started learning C about a year ago.

But I've written my first small programs in BASIC on a C64, so I know a little bit about programming in general.

Bye, Andreas

8. In the movement function, at least, you're off by at least 1 in your loops. You've got block box[ROW][COLUMN], but then you hard code boundaries for some reason.

Code:
```for (rw=0;rw<16;rw++)
for (cln=0;cln<16;cln++)
if (b[rw][cln].sblock == 'X')
{
b[rw][cln-1].sblock='X';
b[rw][cln].sblock=' ';
}```
if ROW and COLUMN are 15, then where ever you've hard coded or set a variable so that it winds up being 15 or more, it will be out of bounds. Use the ROW and COLUMN constants in these loops - that's why you defined them. For example,

Code:
```for(rw = ROW - 1; rw >= 0; --rw)
for(cln = COLUMN - 1; cln >= 0; --cln)
or

for(rw = 0; rw < ROW; ++rw)
for(cln = 0; cln < COLUMN; ++cln)```

9. You have not implemented the advice regarding coordinates - it was suggested that your struct should contain xPos and yPos valriables. Also in your main() function move the loops into a seperate InitBoard() function

10. May i know how you write the code for tetris?
I have no idea how to start.

11. This is your second post on someone else's thread. If you have a specific question, perhaps you'd be best off starting your own new thread.

If you have no idea how to even start the code for Tetris, then you are not ready for this challenge yet.

12. can you show me how and where should i make changes? cause i dont really know how to change the codes if i were to add the xPos yPos variables.

13. Originally Posted by Alexius Lim
can you show me how and where should i make changes? cause i dont really know how to change the codes if i were to add the xPos yPos variables.
I'd create a struct for the falling block, and rather than some random block pattern, maybe a few specific patterns - cube, line, angle, etc

Code:
```typedef struct
{
int shape; // current block dropping
int state; // what the block is doing - init, drop, collide, etc
int row;   // starting row
int col;   // starting col
int max_w; // max width of dropping block
int max_h; // max height of dropping block

} object;

void updateBox(char b[MAX_ROW][MAX_COL], object *);
// prototype for manipulating object in box```
if you declare your box and a separate object, you should be able to track its movement within the box and determine whether or not it has hit something.

14. Originally Posted by ronin
I'd create a struct for the falling block, and rather than some random block pattern, maybe a few specific patterns - cube, line, angle, etc
Code:
```char blockI[4][4] = { { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, };
char blockJ[4][4] = { { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, };
char blockL[4][4] = { { 1, 0, 0, 0 }, { 1, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, };
char blockO[4][4] = { { 1, 1, 0, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, };
char blockS[4][4] = { { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, };
char blockT[4][4] = { { 1, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, };
char blockZ[4][4] = { { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, }```
ok, i have this. but where should i put them? declare as a global variable? and how do i use the structure u declared?

15. I find this topic fascinating. I didn't have time to test it very much, but I was thinking along the lines of below for dropping blocks. I'm in a bit of a rush, so please excuse the formatting from pasting.

Code:
```#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

#define MAX_COL 15
#define MAX_ROW 15
#define MAX_W    4
#define MAX_H    4

enum SHAPES { CUBE, LINE, ANGLE, MIRROR };

typedef struct
{
int row;
int col;
int shape;
int max_w;
int max_h;
char block[MAX_H][MAX_W];

} object;

void initObject(object *);
void updateObject(object *);
void drawBox(char b[MAX_ROW][MAX_COL], object *);

int main(void)
{
object obj = { 0 };
char box[MAX_ROW][MAX_COL] = { { 0 } };
time_t t1, t2;

srand((unsigned)time(0));

initObject(&obj);

for(;;)
{
updateObject(&obj);
drawBox(box, &obj);

t1 = time(0);

do { t2 = time(0); } while(t1 + 1 > t2);
}

getchar();
return 0;
}

void initObject(object *tmp)
{
/* cube   line  angle  mirror
XXXX   XXXX   XXXX  X
XXXX             X  XXXX
XXXX             X  XXXX
XXXX             X     X
*/

tmp->shape = rand() % 4;
tmp->row   = 0;

if(tmp->shape == LINE)
tmp->max_h = 1;
else
tmp->max_h = MAX_H;

tmp->max_w = MAX_W;
tmp->col = (MAX_COL - tmp->max_w) / 2;   // center in box
memset(tmp->block, ' ', MAX_W * MAX_H); // clear the block

// set shape

if(tmp->shape == CUBE)
memset(tmp->block, 'X', 16);
else if(tmp->shape == LINE)
memset(tmp->block, 'X', 4);
else if(tmp->shape == ANGLE)
{
memset(tmp->block, 'X', 4);
memcpy(tmp->block + 1, "   X   X   X", 12);
}
else if(tmp->shape == MIRROR)
{
memset(tmp->block, 'X', 1);
memset(tmp->block + 1, 'X', 8);
memcpy(tmp->block + 3, "   X", 4);
}
}

void updateObject(object *tmp)
{
if(tmp->row + tmp->max_h == MAX_ROW)
initObject(tmp);
else
++tmp->row;
}

void drawBox(char b[MAX_ROW][MAX_COL], object *tmp)
{
int i, j, l=0, m;

memset(b, 0, MAX_ROW * MAX_COL);

for(i = tmp->row; i < tmp->row + tmp->max_h; ++i)
{
m = 0;

for(j = tmp->col; j < tmp->col + tmp->max_w; ++j)
{
b[i][j] = tmp->block[l][m];
++m;
}

++l;
}

for(i=0; i < MAX_ROW; ++i)
{
for(j=0; j < MAX_COL; ++j)
putchar(b[i][j]);

putchar('\n');
}
}```