You are on page 1of 23

/*

===============================================================================
=============================
Name
: tetris.c
Author
: Rafael David Quirino
Version
: 1.0
Date
: January, 02 / 2014
Copyright : Copyright (c) 2014 Rafael David Quirino
Description : Tetris
-----Compiling and execution
----------------------This implementation requires two libraries: pthread e ncurses.
Make sure to get both installed on your system.
Open a terminal, go to the folder wich contains the source code.
+---------------------------------------------+
* To compile type the following instruction: | gcc tetris.c -o tet
ris -lpthread -lncurses |
+---------------------------------------------+
+----------+
* To execute type the following instruction: | ./tetris |
+----------+
References : No reference was used in this implementation.
===============================================================================
=============================
*/
//===========================
// Libraries
//===========================
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <curses.h>
#include <pthread.h>
//===========================
//==============================================================================
====
// System constants
//==============================================================================
====
// Readability constants ---------------------------------#define START
0
#define QUIT
1
#define
#define
#define
#define

VERTICAL
HORIZONTAL
CLOCKWISE
COUNTERCLOCKWISE

0
1
0
1

#define
#define
#define
#define

UP
RIGHT
DOWN
LEFT

0
1
2
3

#define PATH
#define WALL
#define BLOCK

0
1
2

#define RUNNING
#define FINISHED
#define PAUSED

0
1
2

#define
#define
#define
#define
#define
#define
#define

80
112
81
113
119
87
10

DOWN_CASE_P
UP_CASE_P
DOWN_CASE_Q
UP_CASE_Q
DOWN_CASE_W
UP_CASE_W
ENTER

#define ONE_SECOND
1000000
//--------------------------------------------------------// Configuration constants
#define FASTEST
#define VERY_FAST
#define FAST
#define NORMAL
#define SLOW
#define VERY_SLOW

-------------------------------15
10
6
4
2
1

#define FPS
#define SPEED
#define DEFAULT_DIRECTION

60
NORMAL
COUNTERCLOCKWISE

#define ROWS
#define COLUMNS

24
16

#define PLAYER_BOARD_SIZE 38
#define BLOCK_MAX_SIZE
12
#define NAME_MAX_SIZE
25
#define GAME_OVER_BLINKS
3
//--------------------------------------------------------// Calculated constants ----------------------------------#define FIELD_MAX_SIZE
ROWS*COLUMNS
//--------------------------------------------------------// Printing constants ------------------------------------// Cells ----------------------------------char* PATH_CELL
= " ";
char* WALL_CELL
= "# ";
char* BLOCK_CELL
= "@ ";
//-----------------------------------------// Message strings
// Messages for the player board-----------char* PLAYER_NAME_STRING
= "Player:";
char* SPEED_STRING
= "Speed :";
char* TIME_STRING
= "Time :";
char* SCORE_STRING
= "Score :";
//-----------------------------------------// Notification messages ------------------char* PAUSE_STRING
= "PAUSE";

char* ON_PAUSE_STRING
= "Press p or P to resume";
char* OFF_PAUSE_STRING
= "Press p or P to pause";
char* GAME_OVER_STRING
= "__ GAME OVER __";
char* START_STRING
= "Press <Enter> to start";
char* QUIT_STRING
= "Press <Enter> to quit";
//-----------------------------------------//--------------------------------------------------------//==============================================================================
====
//==============================================================================
====
// System data structures
//==============================================================================
====
typedef struct{
int x;
int y;
}Position;
typedef struct{
int hour;
int minute;
int second;
}RunTime;
typedef struct{
int size;
Position body[BLOCK_MAX_SIZE];
}Block;
typedef struct{
int constructed_size;
Position constructed[FIELD_MAX_SIZE];
Block current_block;
}Field;
typedef struct{
char* name;
int score;
}Player;
typedef struct{
int status;
int speed;
int blocks_number;
RunTime run_time;
Field field;
Player player;
}Match;
typedef struct{
}Game;
//==============================================================================
====
//==============================================================================
====
// System functions prototype (interface)

//==============================================================================
====
// Initializing and finishing system special functions (ncurses) -----------------void init();
void end();
//--------------------------------------------------------------------------------// Game structures initializing functions (constructors) -------------------------void create_run_time(RunTime*);
void create_block(Block* block);
void create_field(Field*,Block*);
void create_player(Player*,char*);
void create_match(Match*,Player*,Field*,RunTime*,int);
void create_entire_match(Match*,Player*,Field*,Block*,RunTime*,char*,int);
//--------------------------------------------------------------------------------// General auxiliar functions ----------------------------------------------------void print_repeteadly(char*,int);
int contains(int[],int,int);
int how_many_digits(int);
int string_length(char*);
int get_max(int[],int);
int get_min(int[],int);
//--------------------------------------------------------------------------------// Game specific auxiliar functions ----------------------------------------------void tick_time(RunTime*);
int time_to_seconds(RunTime);
RunTime seconds_to_time(int);
void copy_block(Block*,Block);
void set_position(Position*,int,int);
int get_width();
int get_height();
int get_inner_board_size();
int get_speed(Match);
int get_player_rate();
char* get_screen_cell(int);
char* get_speed_string(int);
char* get_confirmation_message(int);
int is_finished(Match);
int is_paused(Match);
int is_wall(Position);
int is_out_of_bounds(Position);
int is_included(Position[],Position,int);
int is_constructed(Field,Position);
int has_block(Block,Position);
void positions_to_array(Position[],Position,Position,int[]);
void block_positions_to_array(Block,Position,int[]);
void array_to_positions(Position[],Position,Position,int[]);
void array_to_block_positions(Block*,Position,int[]);
Position get_block_position(Block);
Position get_array_indexes(Position[],int);
Position null_position();
//--------------------------------------------------------------------------------// Game behavior functions -----------------------------------------------------

---Block get_random_block();
void update_match_status(Match*,int);
void update_player_score(Match*);
void update_current_block(Field*,Block);
void update_block_positions(Block*,int,int);
void remove_constructed_line(Field*,int);
int rotate_block(Field*,int);
int move_block(Field*,int,int);
int move_block_horizontally(Field*,int);
int move_block_vertically(Field*);
int valid_position(Field,Position);
int build(Field*);
int explode(Field*);
// TODO
//--------------------------------------------------------------------------------// Game control functions --------------------------------------------------------void play_match(Match*);
void start_match(Match*,char*,int);
void start_game();
//--------------------------------------------------------------------------------// Threads functions -------------------------------------------------------------void *screen_thread(void*);
void *run_time_thread(void*);
void *block_thread(void*);
void *player_thread(void*);
void *pause_thread(void*);
//--------------------------------------------------------------------------------// Threads control functions -----------------------------------------------------void init_running_match_threads(Match*);
void end_running_match_threads();
void init_pause_animation(Match*);
void end_pause_animation();
//--------------------------------------------------------------------------------// Graphics functions ------------------------------------------------------------void run_start_animation(Match);
void run_pause_animation(Match*);
void run_match_over_animation(Match);
void render_confirmation(Match,int);
void render_pause();
void render_messages(char*,int);
void render_match_board_player_name(int,int,char*);
void render_match_board_border(int,int);
void render_match_board_empty_line(int,int);
void render_match_board_run_time(RunTime,int,int);
void render_match_board(Match);
void render_match_screen(Match,int,char*);
void render_set_up_match_screen(char*,int*);
//--------------------------------------------------------------------------------//==============================================================================
====

// Threads declaration -----------------------------------------------------------pthread_t run_time_t, screen_t, player_t, block_t, pause_t;


//--------------------------------------------------------------------------------//==============================================================================
====
// System functions implementation
//==============================================================================
====
// System main function ----------------------------------------------------------int main()
{
srand(time(NULL));
init();
start_game();
end();
}
//--------------------------------------------------------------------------------// Initializing and finishing system special functions (ncurses) -----------------void init()
{
initscr();
// Initializing curses.h screen functions
start_color();
// Make colors use possible
noecho();
// Make pressed keys invisible
curs_set(0);
// Make the cursor invisible
keypad(stdscr,TRUE);
// Activate function keys
// Color pairs -------------------------------init_pair(1,COLOR_WHITE,COLOR_BLACK);
init_pair(2,COLOR_BLACK,COLOR_WHITE);
//--------------------------------------------bkgd(COLOR_PAIR(1));
}
void end()
{
endwin();
exit(0);
}
//--------------------------------------------------------------------------------// Game structures initializing functions (constructors) -------------------------void create_run_time(RunTime* run_time)
{
run_time->hour
= 0;
run_time->minute = 0;
run_time->second = 0;
}
void create_block(Block* block)
{

int i;
block->size = 0;
for(i=0; i<BLOCK_MAX_SIZE; i++)
block->body[i] = null_position();
}
void create_field(Field* field, Block* block)
{
int i;
field->constructed_size = 0;
for(i=0; i<FIELD_MAX_SIZE; i++)
field->constructed[i] = null_position();
update_current_block(field,(*block));
}
void create_player(Player* player, char* name)
{
player->name = (char*)name;
player->score = 0;
}
void create_match(Match* match, Player* player,
Field* field, RunTime* run_time,
int speed)
{
update_match_status(match,RUNNING);
match->blocks_number = 0;
match->speed
= speed;
match->run_time
= (*run_time);
match->field
= (*field);
match->player
= (*player);
}
void create_entire_match(Match* match, Player* player,
Field* field, Block* block, RunTime* run_time,
char* player_name, int match_speed)
{
create_run_time(run_time);
create_block(block);
create_field(field,block);
create_player(player,player_name);
create_match(match,player,field,run_time,match_speed);
}
//--------------------------------------------------------------------------------// General auxiliar functions ----------------------------------------------------void print_repeteadly(char* string, int run_times)
{
int i;
for(i=0; i<run_times; i++) printw("%s",string);
}
int contains(int array[], int size, int number)
{
int i;
for(i=0; i<size; i++)
if(array[i] == number) return TRUE;
return FALSE;

}
int how_many_digits(int number)
{
int count_signal = FALSE, aux = abs(number), result = 1;
if(number<0) result++;
while(aux/10 != 0){
result++;
aux = aux/10;
}
return result;
}
int string_length(char* string)
{
int lenght = 0;
while(string[lenght] != '\0'){lenght++;}
return lenght;
}
int get_max(int array[], int size)
{
int i, max = array[0];
for(i=1; i<size; i++)
if(array[i] > max) max = array[i];
return max;
}
int get_min(int array[], int size)
{
int i, min = array[0];
for(i=1; i<size; i++)
if(array[i] < min) min = array[i];
return min;
}
//--------------------------------------------------------------------------------// Game specific auxiliar functions ----------------------------------------------void tick_time(RunTime* t)
{
int time_in_seconds = time_to_seconds(*t);
(*t) = seconds_to_time(++time_in_seconds);
}
int time_to_seconds(RunTime t)
{
return t.hour*3600+t.minute*60+t.second;
}
RunTime seconds_to_time(int time_in_seconds)
{
RunTime t;
int seconds = time_in_seconds;
t.hour = seconds/3600;
seconds = seconds%3600;
t.minute = seconds/60;
seconds = seconds%60;
t.second = seconds;

return t;
}
void copy_block(Block* to, Block from)
{
int i;
to->size = from.size;
for(i=0; i<from.size; i++)
set_position(&to->body[i],from.body[i].x,from.body[i].y);
}
void set_position(Position* position, int x, int y)
{
position->x = x;
position->y = y;
}
int get_width()
{
return COLUMNS;
}
int get_height()
{
return ROWS;
}
int get_inner_board_size()
{
return PLAYER_BOARD_SIZE-2;
}
int get_speed(Match match)
{
return match.speed;
}
int get_player_rate()
{
return 100;
}
char* get_screen_cell(int constant)
{
char* cell;
switch(constant){
case PATH: cell = PATH_CELL;
break;
case WALL: cell = WALL_CELL;
break;
case BLOCK: cell = BLOCK_CELL;
break;
default:
cell = PATH_CELL;
break;
}
return cell;
}
char* get_speed_string(int constant)
{

char* string;
switch(constant){
case VERY_FAST:
break;
case FAST:
break;
case NORMAL:
break;
case SLOW:
break;
case VERY_SLOW:
break;
default:
break;
}
return string;

string = "Very fast";


string = "Fast";
string = "Normal";
string = "Slow";
string = "Very slow";
string = "Undefined";

}
char* get_confirmation_message(int type)
{
char* message;
switch(type){
case QUIT:
message = QUIT_STRING;
break;
case START: message = START_STRING;
break;
default:
message = "UNDEFINED!";
break;
}
return message;
}
int is_finished(Match match)
{
int flag = FALSE;
if(match.status == FINISHED) flag = TRUE;
return flag;
}
int is_paused(Match match)
{
int flag = FALSE;
if(match.status == PAUSED) flag = TRUE;
return flag;
}
int is_wall(Position pos)
{
int flag = FALSE;
if(pos.x==0||pos.x==ROWS-1||pos.y==0||pos.y==COLUMNS-1)
flag = TRUE;
return flag;
}
int is_out_of_bounds(Position pos)
{
int flag = FALSE;
if(pos.x<1||pos.x>ROWS-2||pos.y<1||pos.y>COLUMNS-2)
flag = TRUE;
return flag;

}
int is_included(Position positions[],Position position, int size)
{
int i, flag = FALSE;
for(i=0; i<size; i++){
if(positions[i].x==position.x && positions[i].y==position.y){
flag = TRUE;
break;
}
}
return flag;
}
int is_constructed(Field field, Position position)
{
return is_included(field.constructed,position,field.constructed_size);
}
void positions_to_array(Position positions[], Position indexes,
Position initial, int array[])
{
int i, j, size = indexes.x*indexes.y;
Position current_position;
for(i=0; i<indexes.x; i++){
for(j=0; j<indexes.y; j++){
set_position(&current_position,i+initial.x,j+initial.y);
if(is_included(positions,current_position,size))
array[j+(i*indexes.y)] = BLOCK;
else
array[j+(i*indexes.y)] = PATH;
}
}
}
void block_positions_to_array(Block block, Position indexes, int array[])
{
positions_to_array(block.body,indexes,get_block_position(block),array);
}
void array_to_positions(Position positions[], Position indexes,
Position initial, int array[])
{
int i, j, index = 0;
for(i=0; i<indexes.y; i++){
for(j=0; j<indexes.x; j++){
if(array[j+(i*indexes.x)] == BLOCK)
set_position(&positions[index++],i+initial.x,j+initial.y);
}
}
}
void array_to_block_positions(Block* block, Position indexes, int array[])
{
array_to_positions(block->body,indexes,get_block_position((*block)),array);
}
Position get_block_position(Block block)
{
int i, x[block.size], y[block.size];

for(i=0; i<block.size; i++){


x[i] = block.body[i].x;
y[i] = block.body[i].y;
}
int row
= get_min(x,block.size);
int column = get_min(y,block.size);
Position result = {.x = row, .y = column};
return result;
}
Position get_array_indexes(Position array[], int length)
{
int i, x[length], y[length];
for(i=0; i<length; i++){
x[i] = array[i].x;
y[i] = array[i].y;
}
int rows
= 1+(get_max(x,length)-get_min(x,length));
int columns = 1+(get_max(y,length)-get_min(y,length));
Position result = {.x = rows, .y = columns};
return result;
}
Position null_position()
{
Position null = {.x = -1, .y = -1};
return null;
}
//--------------------------------------------------------------------------------// Game behavior functions -------------------------------------------------------/*
Block get_random_block()
{
Block blocks[11];
int i, x = 1, y = 1;
for(i=0; i<11; i++){
if(i==0){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
blocks[i].size = 1;
}else if(i==1){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x,y+1);
blocks[i].size = 2;
}else if(i==2){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x,y+2);
blocks[i].size = 3;
}else if(i==3){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x,y+2);
set_position(&blocks[i].body[k++],x,y+3);

blocks[i].size = 4;
}else if(i==4){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+1,y+1);
blocks[i].size = 3;
}else if(i==5){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+1,y+1);
blocks[i].size = 4;
}else if(i==6){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y+1);
blocks[i].size = 4;
}else if(i==7){
int k = 0;
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y);
blocks[i].size = 4;
}else if(i==8){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+2,y);
set_position(&blocks[i].body[k++],x+2,y+1);
blocks[i].size = 4;
}else if(i==9){
int k = 0;
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y+1);
set_position(&blocks[i].body[k++],x+2,y);
blocks[i].size = 4;
}else if(i==10){
int k = 0;
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y+1);
set_position(&blocks[i].body[k++],x+1,y);
blocks[i].size = 4;
}
}
return blocks[rand()%11];
}
*/
Block get_random_block()
{
int nblocks = 7;
Block blocks[nblocks];
int i, x = 1, y = 1;
for(i=0; i<nblocks; i++){

if(i==0){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x,y+2);
set_position(&blocks[i].body[k++],x,y+3);
blocks[i].size = 4;
}else if(i==1){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+1,y+1);
blocks[i].size = 4;
}else if(i==2){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y+1);
blocks[i].size = 4;
}else if(i==3){
int k = 0;
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y);
blocks[i].size = 4;
}else if(i==4){
int k = 0;
set_position(&blocks[i].body[k++],x,y);
set_position(&blocks[i].body[k++],x+1,y);
set_position(&blocks[i].body[k++],x+2,y);
set_position(&blocks[i].body[k++],x+2,y+1);
blocks[i].size = 4;
}else if(i==5){
int k = 0;
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y+1);
set_position(&blocks[i].body[k++],x+2,y);
blocks[i].size = 4;
}else if(i==6){
int k = 0;
set_position(&blocks[i].body[k++],x,y+1);
set_position(&blocks[i].body[k++],x+1,y+1);
set_position(&blocks[i].body[k++],x+2,y+1);
set_position(&blocks[i].body[k++],x+1,y);
blocks[i].size = 4;
}
}
return blocks[rand()%nblocks];
}
void update_player_score(Match* match)
{
// TODO
}

void update_match_status(Match* match, int status)


{
match->status = status;
}
void update_current_block(Field* field, Block block)
{
copy_block(&field->current_block,block);
}
void update_block_positions(Block* block, int xfactor, int yfactor)
{
int i;
for(i=0; i<block->size; i++){
block->body[i].x += xfactor;
block->body[i].y += yfactor;
}
}
void remove_constructed_line(Field* field, int line)
{
int i, size = 0;
Position positions[field->constructed_size];
for(i=0; i<field->constructed_size; i++)
if(field->constructed[i].x != line)
positions[size++] = field->constructed[i];
for(i=0; i<field->constructed_size; i++){
if(i<size){
if(positions[i].x < line)
set_position(&field->constructed[i],positions[i].x+1,positions[i].y);
else
field->constructed[i] = positions[i];
}else{
field->constructed[i] = null_position();
}
}
field->constructed_size = size;
}
int rotate_block(Field* field, int direction)
{
if(direction != CLOCKWISE && direction != COUNTERCLOCKWISE) return FALSE;
int i, j;
Position blockpos = get_block_position(field->current_block);
Position indexes = get_array_indexes(field->current_block.body,field->current_
block.size);
int array[indexes.x*indexes.y];
block_positions_to_array(field->current_block,indexes,array);
int rotated_array[indexes.x*indexes.y];
for(i=0; i<indexes.x; i++){
for(j=0; j<indexes.y; j++){
if(direction == CLOCKWISE)
rotated_array[(indexes.x-1-i)+(j*indexes.x)] = array[j+(i*indexes.y)];
else
rotated_array[i+((indexes.y-1-j)*indexes.x)] = array[j+(i*indexes.y)];
}
}
Block temp_block;
Position current;
create_block(&temp_block);

temp_block.size = field->current_block.size;
array_to_positions(temp_block.body,indexes,blockpos,rotated_array);
for(i=0; i<indexes.y; i++)
for(j=0; j<indexes.x; j++)
if(temp_block.body[j+(i*indexes.x)].y > COLUMNS-2)
update_block_positions(&temp_block,0,-1);
for(i=0; i<temp_block.size; i++){
set_position(&current,temp_block.body[i].x,temp_block.body[i].y);
if(!valid_position((*field),current)) return FALSE;
}
copy_block(&field->current_block,temp_block);
return TRUE;
}
int move_block(Field* field, int direction, int axis)
{
if(axis != VERTICAL && axis != HORIZONTAL) return FALSE;
if(axis == VERTICAL) return move_block_vertically(field);
else return move_block_horizontally(field,direction);
}
int move_block_horizontally(Field* field, int direction)
{
int i;
Position new_positions[field->current_block.size];
for(i=0; i<field->current_block.size; i++){
Position current_pos = field->current_block.body[i];
Position new_pos = null_position();
if(direction == RIGHT)
set_position(&new_pos,current_pos.x,current_pos.y+1);
else if(direction == LEFT)
set_position(&new_pos,current_pos.x,current_pos.y-1);
else
return FALSE;
if(!valid_position((*field),new_pos)) return FALSE;
new_positions[i] = new_pos;
}
for(i=0; i<field->current_block.size; i++)
field->current_block.body[i] = new_positions[i];
return TRUE;
}
int move_block_vertically(Field* field)
{
int i;
Position new_positions[field->current_block.size];
for(i=0; i<field->current_block.size; i++){
Position current_pos = field->current_block.body[i];
Position new_pos = {.x = current_pos.x+1, .y = current_pos.y};
if(!valid_position((*field),new_pos)) return FALSE;
new_positions[i] = new_pos;
}
for(i=0; i<field->current_block.size; i++)
field->current_block.body[i] = new_positions[i];
return TRUE;
}
int valid_position(Field field, Position position)
{
if(is_out_of_bounds(position) || is_constructed(field,position)) return FALSE;

return TRUE;
}
int build(Field* field)
{
int i, x = 0, size = field->constructed_size;
Block block = field->current_block;
for(i=0; i<block.size; i++)
if(!valid_position((*field),block.body[i])) return FALSE;
for(i=size; i<size+block.size; i++)
field->constructed[i] = block.body[x++];
field->constructed_size += block.size;
return TRUE;
}
int explode(Field* field)
{
int i, j, line_size = COLUMNS-2;
int constr_lines_size = 0, removing_lines_size = 0;
int constr_lines[ROWS-2], removing_lines[ROWS-2];
for(i=0; i<field->constructed_size; i++)
if(!contains(constr_lines,constr_lines_size,field->constructed[i].x))
constr_lines[constr_lines_size++] = field->constructed[i].x;
for(i=0; i<constr_lines_size; i++){
int current_line = constr_lines[i], count = 0;
for(j=0; j<field->constructed_size; j++)
if(field->constructed[j].x == current_line) count++;
if(count == line_size) removing_lines[removing_lines_size++] = current_line;
}
for(i=removing_lines_size-1; i>=0; i--) remove_constructed_line(field,removing
_lines[i]);
return removing_lines_size;
}
//--------------------------------------------------------------------------------// Game control functions --------------------------------------------------------void play_match(Match* match)
{
int key, flag = TRUE;
render_confirmation((*match),START);
run_start_animation((*match));
init_running_match_threads(match);
while(flag){
if(is_paused((*match))){
run_pause_animation(match);
}else if(is_finished((*match))){
flag = FALSE;
}
usleep(ONE_SECOND/get_player_rate());
}
end_running_match_threads();
run_match_over_animation((*match));
render_confirmation((*match),QUIT);
}
void start_match(Match* match, char* player_name, int match_speed)
{
RunTime* run_time = malloc(sizeof(RunTime));

Block* block = malloc(sizeof(Block));


Field* field = malloc(sizeof(Field));
Player* player = malloc(sizeof(Player));
create_entire_match(match,player,field,block,run_time,player_name,match_speed)
;
update_current_block(&match->field,get_random_block());
play_match(match);
}
void start_game()
{
int key, *match_speed = malloc(sizeof(int));
char* player_name = malloc(sizeof(char*));
// For test ------------------------------player_name = "Rafael David Quirino 12345";
(*match_speed) = NORMAL;
//----------------------------------------render_set_up_match_screen(player_name,match_speed);
Match* current_match = malloc(sizeof(Match));
start_match(current_match,player_name,(*match_speed));
}
//--------------------------------------------------------------------------------// Threads functions -------------------------------------------------------------void *screen_thread(void *arg)
{
Match* match = (Match*)arg;
while(TRUE){
clear();
render_match_screen((*match),FALSE,OFF_PAUSE_STRING);
usleep(ONE_SECOND/FPS);
}
return NULL;
}
void *run_time_thread(void *arg)
{
Match* match = (Match*)arg;
while(TRUE){
tick_time(&match->run_time);
usleep(ONE_SECOND);
}
return NULL;
}
void *block_thread(void *arg)
{
Match* match = (Match*)arg;
int flag = TRUE, speed = match->speed;
int seconds = time_to_seconds(match->run_time);
while(flag){
if(move_block(&match->field,0,VERTICAL)){
usleep(ONE_SECOND/match->speed);
}else{
if(build(&match->field)){
explode(&match->field);
update_current_block(&match->field,get_random_block());
}else{

flag = FALSE;
update_match_status(match,FINISHED);
}
}
if(time_to_seconds(match->run_time)>seconds){
match->speed = speed;
seconds = time_to_seconds(match->run_time);
}
}
return NULL;
}
void *player_thread(void *arg)
{
Match* match = (Match*)arg;
int key;
int speed = match->speed, flag = TRUE;
int seconds = time_to_seconds(match->run_time);
cbreak();
// Avoid queueing pressed keys
//nodelay(stdscr, TRUE); // Avoid waiting for the hit (returns err if no key
was pressed)
while(TRUE){
key = getch();
if(key == KEY_UP){
rotate_block(&match->field,DEFAULT_DIRECTION);
}
else if(key == KEY_LEFT){
move_block(&match->field,LEFT,HORIZONTAL);
}
else if(key == KEY_RIGHT){
move_block(&match->field,RIGHT,HORIZONTAL);
}
else if(key == KEY_DOWN){
match->speed = FASTEST;
}
else if(key == DOWN_CASE_Q || key == UP_CASE_Q){
rotate_block(&match->field,COUNTERCLOCKWISE);
}
else if(key == DOWN_CASE_W || key == UP_CASE_W){
rotate_block(&match->field,CLOCKWISE);
}
else if(key == DOWN_CASE_P || key == UP_CASE_P){
update_match_status(match,PAUSED);
}
usleep(ONE_SECOND/get_player_rate());
}
}
void *pause_animation(void *arg)
{
Match* match = (Match*)arg;
int flag = TRUE, i = 0;
while(TRUE){
clear();
if(i%2==0) flag = TRUE;
else
flag = FALSE;
render_match_screen((*match),flag,ON_PAUSE_STRING);
usleep(ONE_SECOND/2);
i++;
}

return NULL;
}
//--------------------------------------------------------------------------------// Threads control functions -----------------------------------------------------void init_running_match_threads(Match *match)
{
pthread_create(&run_time_t, NULL, run_time_thread, match);
pthread_create(&screen_t, NULL, screen_thread, match);
pthread_create(&player_t, NULL, player_thread, match);
pthread_create(&block_t, NULL, block_thread, match);
}
void end_running_match_threads()
{
pthread_cancel(run_time_t);
pthread_detach(run_time_t);
pthread_cancel(player_t);
pthread_detach(player_t);
pthread_cancel(screen_t);
pthread_detach(screen_t);
pthread_cancel(block_t);
pthread_detach(block_t);
}
void init_pause_animation(Match* match)
{
pthread_create(&pause_t, NULL, pause_animation, match);
}
void end_pause_animation()
{
pthread_cancel(pause_t);
pthread_detach(pause_t);
}
//--------------------------------------------------------------------------------// Graphics functions -------------------------------------------------------------void run_start_animation(Match match)
{
int i, countdown = 3;
char* messages[4];
messages[0] = "=> !!! GO !!! <=";
messages[1] = "=> 1 <=";
messages[2] = "=> 2 <=";
messages[3] = "=> 3 <=";
for(i=countdown; i>=0; i--){
clear();
render_match_screen(match,FALSE,messages[i]);
usleep(ONE_SECOND);
}
}
void run_pause_animation(Match* match)
{
int key;

end_running_match_threads();
init_pause_animation(match);
do{
key = getch();
usleep(ONE_SECOND/get_player_rate());
}while(key != DOWN_CASE_P && key != UP_CASE_P);
end_pause_animation();
update_match_status(match,RUNNING);
init_running_match_threads(match);
}
void run_match_over_animation(Match match)
{
int flag = TRUE, i = 0;
while(i<=GAME_OVER_BLINKS*2){
clear();
if(i%2==0) flag = TRUE;
else
flag = FALSE;
render_match_screen(match,FALSE,GAME_OVER_STRING);
usleep(ONE_SECOND/4);
i++;
}
}
void render_pause()
{
int i, run_times = (get_width()/2)-(string_length(PAUSE_STRING)/4)-1;
print_repeteadly(get_screen_cell(PATH),run_times);
printw("%s\n",PAUSE_STRING);
}
void render_confirmation(Match match, int type)
{
int key;
char* message = get_confirmation_message(type);
clear();
render_match_screen(match,FALSE,message);
do{
key = getch();
usleep(ONE_SECOND/get_player_rate());
}while(key != ENTER);
}
void render_messages(char* message, int pause_flag)
{
int run_times = (get_width()/2)-(string_length(message)/4)-1;
if(pause_flag) render_pause();
else
printw("\n");
print_repeteadly(get_screen_cell(PATH),run_times);
printw("%s\n",message);
}
void render_match_board_player_name(int row, int column, char* player_name)
{
int a = get_inner_board_size();
int b = string_length(PLAYER_NAME_STRING);
int c = string_length(player_name)-2;
int times = a-b-c;
move(row,column);
printw("| %s %s",PLAYER_NAME_STRING,player_name);

print_repeteadly(" ",times-4);
printw("|");
}
void render_match_board_border(int row, int column)
{
move(row,column);
printw("+");
print_repeteadly("-",get_inner_board_size());
printw("+");
}
void render_match_board_empty_line(int row, int column)
{
move(row,column);
printw("|");
print_repeteadly(" ",get_inner_board_size());
printw("|");
}
void render_match_board_run_time(RunTime t, int row, int column)
{
char* hstr = "";
char* mstr = "";
char* sstr = "";
int h = t.hour, m = t.minute, s = t.second;
int times = get_inner_board_size()-string_length(TIME_STRING)-10;
if(how_many_digits(h)==1){hstr = "0";}
if(how_many_digits(m)==1){mstr = "0";}
if(how_many_digits(s)==1){sstr = "0";}
move(row,column);
printw("| %s %s%d:%s%d:%s%d",TIME_STRING,hstr,h,mstr,m,sstr,s);
print_repeteadly(" ",times);
printw("|");
}
void render_match_board_score(int row, int column, int score)
{
int a = get_inner_board_size();
int b = string_length(SCORE_STRING);
int c = how_many_digits(score)-2;
int times = a-b-c;
move(row,column);
printw("| %s %d",SCORE_STRING,score);
print_repeteadly(" ",times-4);
printw("|");
}
void render_match_board(Match match)
{
int i, row = 1, n = string_length(get_screen_cell(PATH));
int column = (COLUMNS*n)+2;
render_match_board_border(++row,column);
render_match_board_player_name(++row,column,match.player.name);
render_match_board_empty_line(++row,column);
render_match_board_run_time(match.run_time,++row,column);
render_match_board_empty_line(++row,column);
render_match_board_score(++row,column,match.player.score);
render_match_board_border(++row,column);
}

void render_match_screen(Match match, int pause_flag, char* message)


{
int i, j;
render_messages(message,pause_flag);
Block block = match.field.current_block;
for(i=0; i<ROWS; i++){
for(j=0; j<COLUMNS; j++){
char* current_cell = get_screen_cell(PATH);
Position current_position = {.x = i, .y = j};
if(is_wall(current_position)){
current_cell = get_screen_cell(WALL);
}else if(is_constructed(match.field,current_position)){
current_cell = get_screen_cell(BLOCK);
}else if(is_included(block.body,current_position,block.size)){
current_cell = get_screen_cell(BLOCK);
}else{
current_cell = get_screen_cell(PATH);
}
printw("%s",current_cell);
}
printw("\n");
}
render_match_board(match);
refresh();
}
void render_set_up_match_screen(char* player_name, int* match_speed)
{
// TODO
}
//--------------------------------------------------------------------------------//==============================================================================
====

You might also like