0% found this document useful (0 votes)
102 views

Tetris

This is a source code of a tetris game, writen in c programming language. Very useful for those willing to learn more about c and game programing.

Uploaded by

Rafael Quirino
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
102 views

Tetris

This is a source code of a tetris game, writen in c programming language. Very useful for those willing to learn more about c and game programing.

Uploaded by

Rafael Quirino
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 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