rendered paste body/* TETRIS -- C** @author Clooth <CloothMail@Gmail.com>*/#include <conio.h>#include <stdio.h>#include <stdlib.h>/* MAIN GAME VARIABLES */#define SCREEN_WIDTH 10#define SCREEN_HEIGHT 20#define SCREEN_POSITION 20#define TYPES 19#define SIZE 4#define STARTSPEED 2000#define BLOCK_CHARACTER '[]'#define EMPTY_CHARACTER ' '#define BORDER '+'/* CONTROLS */#define LEFT 'z'#define RIGHT 'c'#define ROTATE 'm'#define END 'e'enum type{ square, horizontal_long, vertical_long, stair1, stair2, stair3, stair4, T_up, T_right, T_down, T_left, L1_up, L1_right, L1_down, L1_left, L2_up, L2_right, L2_down, L2_left};type modification[TYPES]={ square, horizontal_long, vertical_long, stair1, stair2, stair3, stair4, T_up, T_right, T_down, T_left, L1_up, L1_right, L1_down, L1_left, L2_up, L2_right, L2_down, L2_left};struct block{ int x[SIZE]; int y[SIZE]; type t;}; p;int stuck[SCREEN_WIDTH+1][SCREEN_HEIGHT+1];int points=0;/* Draw the borders around the game screen */void draw_borders(){ int i; for(i=1;i<=SCREEN_HEIGHT;i++) { gotoxy(SCREEN_POSITION+1,i); putch(BORDER); gotoxy(2*SCREEN_WIDTH+SCREEN_POSITION+2,i); putch(BORDER); } gotoxy(SCREEN_POSITION+1,SCREEN_HEIGHT+1); for(i=1;i<=2*SCREEN_WIDTH+2; i++) putch(BORDER);}/* Form the blocks */void block_form(block *p, int x, int y){ p->x[1]=x; p->y[1]=y; switch(p->t) { case square: p->x[0]=x-1; p->x[2]=x-1; p->x[3]=x; p->x[0]=y; p->y[2]=y+1; p->y[3]=y+1; break; case horizontal_long: p->x[0]=x-1; p->x[2]=x+1; p->x[3]=x+2; p->y[0]=y; p->y[2]=y; p->y[3]=y; break; case vertical_long: p->x[0]=x; p->x[2]=x; p->x[3]=x; p->y[0]=y-1; p->y[2]=y+1; p->y[3]=y+2; break; case stair1: p->x[0]=x-1; p->x[2]=x+1; p->x[3]=x; p->y[0]=y+1; p->y[2]=y; p->y[3]=y+1; break; case stair2: p->x[0]=x-1; p->x[2]=x-1; p->x[3]=x; p->y[0]=y-1; p->y[2]=y; p->y[3]=y+1; break; case stair3: p->x[0]=x-1; p->x[2]=x; p->x[3]=x+1; p->y[0]=y-1; p->y[2]=y-1; p->y[3]=y; break; case stair4: p->x[0]=x+1; p->x[2]=x+1; p->x[3]=x; p->y[0]=y-1; p->y[2]=y; p->[3]=y+1; break; case T_up: p->x[0]=x; p->x[2]=x-1 p->x[3]=x+1; p->y[0]=y-1; p->y[2]=y; p->y[3]=y; break; case T_right: p->x[0]=x; p->x[2]=x+1; p->x[3]=x; p->y[0]=y-1; p->y[2]=y; p->y[3]=y+1; break; case T_down: p->x[0]=x-1; p->x[2]=x+1; p->x[3]=x; p->y[0]=y; p->y[2]=y; p->y[3]=y+1; break; case T_left: p->x[0]=x; p->x[2]=x-1; p->x[3]=x; p->y[0]=y-1; p->y[2]=y; p->y[3]=y+1; break; case L1_up: p->x[0]=x; p->x[2]=x; p->x[3]=x+1; p->y[0]=y-1; p->y[2]=y+1; p->y[3]=y+1; break; case L1_right: p->x[0]=x-1; p->x[2]=x+1; p->x[3]=x-1; p->y[0]=y; p->y[2]=y; p->y[3]=y+1; break; case L1_down: p->x[0]=x-1; p->x[2]=x; p->x[3]=x; p->y[0]=y-1; p->y[2]=y-1; p->y[3]=y+1; break; case L1_left: p->x[0]=x+1; p->x[2]=x-1; p->x[3]=x+1; p->y[0]=y-1; p->y[2]=y; p->y[3]=y; break; case L2_up: p->x[0]=x; p->x[2]=x; p->x[3]=x-1; p->y[0]=y-1; p->y[2]=y+1; p->y[3]=y+1; break; case L2_right: p->x[0]=x-1; p->x[2]=x-1; p->x[3]=x+1; p->y[0]=y-1; p->y[2]=y; p->y[3]=y; break; case L2_down: p->x[0]=x; p->x[2]=x+1; p->x[3]=x; p->y[0]=y-1; p->y[2]=y-1; p->y[3]=y+1; break; case L2_left: p->x[0]=x-1; p->x[2]=x+1; p->x[3]=x+1; p->y[0]=y; p->y[2]=y; p->y[3]=y+1; break; }}/* There are 7 different blocks, and when we create a new one** to fall from the top, it can be any of these.*/void create_block(block *p){ switch(random(7)) { case 0: p->t=square; break; case 1: p->t=horizontal_long; break; case 2: p->t=stair1; break; case 3: p->t=stair3; break; case 4: p->t=T_up; break; case 5: p->t=L1_down; break; case 6: p->t=L2_down; break; } place_block(p, SCREEN_WIDTH/2,2);}/* delete_row() removes a full row from the game screen and** drops the rows above.*/void delete_row(int row){ int i,j; for(j=row; j>1; j--) for(i=1; i<=SCREEN_WIDTH; i++) { stuck[i][j]=stuck[i][j-1]; gotoxy(i*2+SCREEN_POSITION,j); if(stuck[i][j]) { putch(BLOCK_CHARACTER); putch(BLOCK_CHARACTER); } else { putch(EMPTY_CHARACTER); putch(EMPTY_CHARACTER); } } points+=10;}/* freeze() locks the dropping block */void freeze(block *p){ int i,j,full_row; for(i=0; i<SIZE; i++) stuck[p->x[i]][p->y[i]]=1; for(j=1; j<=SCREEN_HEIGHT; j++) { full_row=1; for(i=1; i<=SCREEN_WIDTH; i++) if(!stuck[i][j]) full_row=0; if(full_row) delete_row(j); }}/* collision() checks if the dropping block is touching already** existing blocks, aka has it bumped into something.*/void collision(block *p){ int i,touch=0; if(p->y[3]>SCREEN_HEIGHT) touch=1; else for(i=0; i<SIZE; i++) if(p->x[i]<1 || p->x[i]>SCREEN_WIDTH || stuck[p->x[i]][p->y[i]]) touch=1; return touch;}void show(block *p, int char){ int i; for(i=0; i<SIZE; i++) { gotoxy(p->x[i]*2+SCREEN_POSITION,p->y[i]); putch(char); putch(char); }}/* a block is lowered by 1 row each round.** In the same time, we check if it has** bumped into anything, if so we freeze** it.*/int lower_block(block *p){ int i; block temp_p=*p; show(p, EMPTY_CHARACTER); for(i=0; i<SIZE; i++) p->y[i]++; if(collision(p)) { *p=temp_p; show(p, BLOCK_CHARACTER); freeze(p); if(p->y[0]<=2) exit(1); return 1; } show(p, BLOCK_CHARACTER); return 0;}/* control_block() checks ie. that a block could not be** rotated if a part of it would go over the game** screen.*/void control_block(block *p, char command){ int i; block temp_p=*p; show(p, EMPTY_CHARACTER); switch(command) { case RIGHT: for(i=0; i<SIZE; i++) p->x[i]++; break; case LEFT: for(i=0; i<SIZE; i++) p->x[i]--; break; case ROTATE: p->t=modification[p->t]; place_block(p, p->x[1], p->y[1]); break; case END: exit(1); } if(collision(p)) *p=temp_p; show(p, BLOCK_CHARACTER);}void main(){ int i,j,touch,speed=STARTSPEED; randomize(); clrscr(); draw_borders(); for(j=0; j<=SCREEN_HEIGHT; j++) for(i=0; i<=SCREEN_WIDTH; i++) stuck[i][j]=0; while(1) { gotoxy(50,5); printf("SCORE: %5d", points); create_block(&p); i=0; touch=0; do { if(kbhit()) control_block(&p, getch()); if((i=(i+1)%speed)==0) touch=lower_block(&p); } while(!touch); points++; if(speed>1) speed--; }}